numpy Python nan出现在分子气体模拟中

ig9co6j1  于 2024-01-08  发布在  Python
关注(0)|答案(1)|浏览(242)

我正在写一个脚本,它应该是模拟气体分子的相互作用,使用伦纳-琼斯势。我面临着两个问题。
1.当我用np.sqrt()来计算分子之间的距离时,我只得到了由nan值组成的列表.这不是很有帮助。
1.我把()**0.5替换成np.sqrt()后就解决了这个问题。但我仍然得到错误的结果。
这里讨论的行是下面的一个dist12 = (r12[0]**2 + r12[1]**2)**0.5然而,摆脱nan警告并没有完全解决我的问题,因为稍后我会检查if dist12 == 0: return 0, 0,这导致位置列表组成-除了前四个粒子的列表之外-大部分包含零的列表。
所以代码流可能有问题。但是我无法找到问题所在。所以让我首先简短地描述预期的代码流。
1.粒子初始化,从class Czastka中初始化16个粒子,并给出相应的初始条件。

  1. simulate()函数在粒子列表中迭代num_step = 1000,并计算每个粒子与其他粒子相互作用的力的总和。为此,使用lennard_jones_forces(x1, y1, x2, y2)函数。应用条件是,如果粒子之间的距离超过2.5*sigma,则它们不会感受到任何吸引力。
    1.使用函数leapforg_single_step(particle, force_x_comp, force_y_comp):计算新的位置和速度。
    1.然后使用p1.update_position(p1_x_next, p1_y_next, box_size)将其附加到粒子位置列表中。**这里还检查了周期性边界条件。**它们背后的想法是,如果粒子将离开模拟/包含气体的框架/盒子。它将从另一侧出现,这是使用模块划分self.x = new_x % box_size实现的。
    正如我说的,我不明白是什么原因导致的nan错误,也不明白为什么我最终在我的位置列表中得到的大多是零?这是我的完整代码:
  1. import numpy as np
  2. #Inicjalizacja paramatrów
  3. particle_num, box_size, eps, sigma = 16, 8.0, 1.0, 1.0
  4. dt, temp, k_B, m, M = 0.0001, 2.5, 1, 1, 1
  5. radius = sigma/2
  6. class Czastka:
  7. #Inicjalizacja danych cząstki
  8. def __init__(self, radius, x_pos, y_pos, x_vel, y_vel):
  9. #Składowe wartości wektorowych
  10. self.x, self.y = x_pos, y_pos
  11. self.vx, self.vy = x_vel, y_vel
  12. """
  13. NOTE: The goal of the simulation in the end is to get only these 4 lists
  14. """
  15. #Positions lists
  16. self.x_positions_lst = []
  17. self.y_positions_lst = []
  18. #Velocity lists
  19. self.x_velocity_lst = []
  20. self.y_velocity_lst = []
  21. def append_postions(self, x_pos, y_pos):
  22. self.x_positions_lst.append(x_pos)
  23. self.y_positions_lst.append(y_pos)
  24. def update_velocities(self, x_vel, y_vel):
  25. self.x_velocity_lst.append(x_vel)
  26. self.y_velocity_lst.append(y_vel)
  27. # Stosujemy periodyczne warunki brzegowe poprzez liczenie modułowe
  28. def update_position(self, new_x, new_y, box_size):
  29. self.x = new_x % box_size
  30. self.y = new_y % box_size
  31. self.append_postions(self.x, self.y)
  32. # Inicjalizacja cząstek
  33. initial_x, initial_y = [1, 3, 5, 7], [1, 3, 5, 7]
  34. initial_vx, initial_vy = [1, 1, 2, 0.5], [1, 0.5, 0.25, 4]
  35. particle_lst = []
  36. for i in range(0, 4):
  37. for j in range(0, 4):
  38. particle_lst.append(Czastka(radius, initial_x[j], initial_y[j], initial_vx[j], initial_vy[j]))
  39. #print(len(particle_lst))
  40. #Siła jaka działa na skutek odziaływań w potencjale Lennard-Jonesa
  41. def lennard_jones_forces(x1, y1, x2, y2):
  42. global sigma, eps
  43. #Obliczenia pomocnicze
  44. r12 = [x2-x1, y2-y1]
  45. dist12 = (r12[0]**2 + r12[1]**2)**0.5
  46. print(r12[0], ' ', r12[1])
  47. if dist12 == 0:
  48. return 0, 0
  49. # Calculate Lennard-Jones force
  50. sigma_over_dist12 = sigma / dist12
  51. sigma_over_dist12_14 = sigma_over_dist12 ** 14
  52. sigma_over_dist12_8 = sigma_over_dist12 ** 8
  53. Force21 = -(48 * eps / (sigma ** 2)) * (sigma_over_dist12_14 - 0.5 * sigma_over_dist12_8)
  54. Force21_x = Force21 * r12[0]
  55. Force21_y = Force21 * r12[1]
  56. #W tym momecie nasza funkcja jest gotowa ALE musimy sprawdzić czy zachodzi warunek odcięcia
  57. #Żeby zwiększyć wydajnośc obliczniową powinno się dokonać tego sprwdzenia, przed obliczniem sił
  58. if np.isnan(Force21_x) or np.isnan(Force21_y):
  59. print(Force21_x, ' ', Force21_y)
  60. print("Nan detected in force calculation")
  61. if dist12 > (2.5*sigma):
  62. #print('Cut off')
  63. Force21_x, Force21_y = 0, 0
  64. return Force21_x, Force21_y
  65. else:
  66. #print('Normal operation')
  67. return Force21_x, Force21_y
  68. # Obliczanie poprzez wykorzystanie algorytmu żabki nowych współrzędnych
  69. def leapforg_single_step(particle, force_x_comp, force_y_comp):
  70. global dt, m
  71. #Obliczanie pół-krokowych prędkości
  72. vx_half = particle.vx + 0.5 * (force_x_comp / m) * dt
  73. vy_half = particle.vy + 0.5 * (force_y_comp / m) * dt
  74. #Obliczanie pół-krokowych położeń
  75. x_next = particle.x + vx_half * dt
  76. y_next = particle.y + vy_half * dt
  77. #Obliczanie nowych prędkości
  78. vx_next = vx_half + 0.5 * (force_x_comp / m) * dt
  79. vy_next = vy_half + 0.5 * (force_y_comp / m) * dt
  80. return x_next, y_next, vx_next, vy_next
  81. def simulate():
  82. global box_size
  83. num_steps = 1000
  84. #Cała symulacja składa się z num_steps kroków
  85. for step in range(num_steps):
  86. #Obliczmy sumę sił działającą na każdą cząstkę
  87. for i, p1 in enumerate(particle_lst):
  88. force_x, force_y = 0, 0
  89. for j, p2 in enumerate(particle_lst):
  90. if i != j:
  91. # Obliczam sume sił działająca na cząsteki p1 (bez interakcji z samym sobą)
  92. f_x, f_y = lennard_jones_forces(p1.x, p1.y, p2.x, p2.y)
  93. force_x += f_x
  94. force_y += f_y
  95. p1_x_next, p1_y_next, p1_vx_next, p1_vy_next = leapforg_single_step(p1, force_x, force_y)
  96. p1.update_position(p1_x_next, p1_y_next, box_size)
  97. p1.update_velocities(p1_vx_next, p1_vy_next)
  98. simulate()
  99. def simulation_results():
  100. for i, particle in enumerate(particle_lst):
  101. print('Particle number: {}. List lenght: {} and x-positions list: {}'.format(i, len(particle.x_positions_lst), particle.x_positions_lst))
  102. simulation_results()
  103. def animation():
  104. pass

字符串
任何帮助将不胜感激!干杯!

gpfsuwkq

gpfsuwkq1#

零距离是非物理的。你有一个可能不正确的初始迭代,从4个初始位置值产生16个粒子。当我修复这个问题时,即使我通过引发异常来检测相同的噪声,也没有NaN。这里还有其他需要改进的地方(你根本没有正确使用Numpy)。

  1. import numpy as np
  2. # Inicjalizacja paramatrów
  3. particle_num, box_size, eps, sigma = 16, 8.0, 1.0, 1.0
  4. dt, temp, k_B, m, M = 0.0001, 2.5, 1, 1, 1
  5. radius = sigma/2
  6. class Particle:
  7. # Inicjalizacja danych cząstki
  8. def __init__(self, radius: float, x_pos: float, y_pos: float, x_vel: float, y_vel: float) -> None:
  9. # Składowe wartości wektorowych
  10. self.x, self.y = x_pos, y_pos
  11. self.vx, self.vy = x_vel, y_vel
  12. """
  13. NOTE: The goal of the simulation in the end is to get only these 4 lists
  14. """
  15. # Positions lists
  16. self.x_positions_lst: list[float] = []
  17. self.y_positions_lst: list[float] = []
  18. # Velocity lists
  19. self.x_velocity_lst: list[float] = []
  20. self.y_velocity_lst: list[float] = []
  21. def append_postions(self, x_pos: float, y_pos: float) -> None:
  22. self.x_positions_lst.append(x_pos)
  23. self.y_positions_lst.append(y_pos)
  24. def update_velocities(self, x_vel: float, y_vel: float) -> None:
  25. self.x_velocity_lst.append(x_vel)
  26. self.y_velocity_lst.append(y_vel)
  27. # Stosujemy periodyczne warunki brzegowe poprzez liczenie modułowe
  28. def update_position(self, new_x: float, new_y: float, box_size: float) -> None:
  29. self.x = new_x % box_size
  30. self.y = new_y % box_size
  31. self.append_postions(self.x, self.y)
  32. # Obliczanie poprzez wykorzystanie algorytmu żabki nowych współrzędnych
  33. def leapfrog_single_step(self, force_x_comp: float, force_y_comp: float) -> tuple[
  34. float, # x next
  35. float, # y next
  36. float, # vx next
  37. float, # vy next
  38. ]:
  39. # Obliczanie pół-krokowych prędkości
  40. vx_half = self.vx + 0.5 * (force_x_comp / m) * dt
  41. vy_half = self.vy + 0.5 * (force_y_comp / m) * dt
  42. # Obliczanie pół-krokowych położeń
  43. x_next = self.x + vx_half * dt
  44. y_next = self.y + vy_half * dt
  45. # Obliczanie nowych prędkości
  46. vx_next = vx_half + 0.5 * (force_x_comp / m) * dt
  47. vy_next = vy_half + 0.5 * (force_y_comp / m) * dt
  48. return x_next, y_next, vx_next, vy_next
  49. # Siła jaka działa na skutek odziaływań w potencjale Lennard-Jonesa
  50. def lennard_jones_forces(
  51. x1: float, y1: float, x2: float, y2: float,
  52. ) -> tuple[float, float]:
  53. # Obliczenia pomocnicze
  54. r12 = [x2-x1, y2-y1]
  55. dist12 = (r12[0]**2 + r12[1]**2)**0.5
  56. # print(r12[0], ' ', r12[1])
  57. if dist12 == 0:
  58. raise ValueError('A zero distance is non-physical')
  59. # Calculate Lennard-Jones force
  60. sigma_over_dist12 = sigma / dist12
  61. sigma_over_dist12_14 = sigma_over_dist12 ** 14
  62. sigma_over_dist12_8 = sigma_over_dist12 ** 8
  63. Force21 = -(48 * eps / (sigma ** 2)) * (sigma_over_dist12_14 - 0.5 * sigma_over_dist12_8)
  64. Force21_x = Force21 * r12[0]
  65. Force21_y = Force21 * r12[1]
  66. # W tym momecie nasza funkcja jest gotowa ALE musimy sprawdzić czy zachodzi warunek odcięcia
  67. # Żeby zwiększyć wydajnośc obliczniową powinno się dokonać tego sprwdzenia, przed obliczniem sił
  68. if np.isnan(Force21_x) or np.isnan(Force21_y):
  69. raise ValueError(f"Nan detected in force calculation: {Force21_x} {Force21_y}")
  70. if dist12 > (2.5*sigma):
  71. # print('Cut off')
  72. Force21_x, Force21_y = 0, 0
  73. return Force21_x, Force21_y
  74. else:
  75. # print('Normal operation')
  76. return Force21_x, Force21_y
  77. def simulate(particle_lst: list[Particle]) -> None:
  78. num_steps = 1000
  79. # Cała symulacja składa się z num_steps kroków
  80. for step in range(num_steps):
  81. # Obliczmy sumę sił działającą na każdą cząstkę
  82. for i, p1 in enumerate(particle_lst):
  83. force_x, force_y = 0, 0
  84. for j, p2 in enumerate(particle_lst):
  85. if i != j:
  86. # Obliczam sume sił działająca na cząsteki p1 (bez interakcji z samym sobą)
  87. f_x, f_y = lennard_jones_forces(p1.x, p1.y, p2.x, p2.y)
  88. force_x += f_x
  89. force_y += f_y
  90. p1_x_next, p1_y_next, p1_vx_next, p1_vy_next = p1.leapfrog_single_step(force_x, force_y)
  91. p1.update_position(p1_x_next, p1_y_next, box_size)
  92. p1.update_velocities(p1_vx_next, p1_vy_next)
  93. def simulation_results(particle_lst: list[Particle]) -> None:
  94. for i, particle in enumerate(particle_lst):
  95. print(
  96. f'Particle number: {i}. '
  97. f'List length: {len(particle.x_positions_lst)} and '
  98. f'x-positions list: {particle.x_positions_lst}'
  99. )
  100. def main() -> None:
  101. # Inicjalizacja cząstek
  102. initial_x, initial_y = [1, 3, 5, 7], [1, 3, 5, 7]
  103. initial_vx, initial_vy = [1, 1, 2, 0.5], [1, 0.5, 0.25, 4]
  104. particle_lst = []
  105. for x, y, vx, vy in zip(initial_x, initial_y, initial_vx, initial_vy):
  106. particle_lst.append(Particle(radius, x, y, vx, vy))
  107. # print(len(particle_lst))
  108. simulate(particle_lst)
  109. simulation_results(particle_lst)
  110. if __name__ == '__main__':
  111. main()

字符串

展开查看全部

相关问题