first
pc-1
This commit is contained in:
16
three_body_problem/examples/__init__.py
Normal file
16
three_body_problem/examples/__init__.py
Normal file
@@ -0,0 +1,16 @@
|
||||
"""
|
||||
三体问题示例模块
|
||||
"""
|
||||
|
||||
from .figure8 import run_figure8_example, analyze_figure8_stability
|
||||
from .lagrange import run_lagrange_example, compare_lagrange_points
|
||||
from .random import run_random_example, run_multiple_random_simulations
|
||||
|
||||
__all__ = [
|
||||
"run_figure8_example",
|
||||
"analyze_figure8_stability",
|
||||
"run_lagrange_example",
|
||||
"compare_lagrange_points",
|
||||
"run_random_example",
|
||||
"run_multiple_random_simulations"
|
||||
]
|
||||
203
three_body_problem/examples/figure8.py
Normal file
203
three_body_problem/examples/figure8.py
Normal file
@@ -0,0 +1,203 @@
|
||||
"""
|
||||
8字形轨道示例 - 著名的稳定三体轨道
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import sys
|
||||
import os
|
||||
|
||||
# 添加父目录到路径
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from three_body_problem import ThreeBodySolver, ThreeBodyConfig, ThreeBodyVisualizer
|
||||
|
||||
|
||||
def run_figure8_example():
|
||||
"""运行8字形轨道示例"""
|
||||
print("=" * 60)
|
||||
print("8字形轨道示例")
|
||||
print("=" * 60)
|
||||
|
||||
# 创建8字形轨道配置
|
||||
particles = ThreeBodyConfig.create_figure8_config()
|
||||
|
||||
# 打印配置摘要
|
||||
ThreeBodyConfig.print_config_summary(particles)
|
||||
|
||||
# 创建求解器
|
||||
dt = 0.001 # 时间步长(年)
|
||||
solver = ThreeBodySolver(particles, dt=dt)
|
||||
|
||||
# 模拟10年
|
||||
total_time = 10.0
|
||||
print(f"\n开始模拟,总时间: {total_time}年,时间步长: {dt}年")
|
||||
|
||||
solver.simulate(total_time=total_time, progress_interval=2000)
|
||||
|
||||
# 计算守恒误差
|
||||
momentum_error, angular_momentum_error, energy_error = solver.get_conservation_errors()
|
||||
print(f"\n守恒定律误差:")
|
||||
print(f" 动量误差: {momentum_error:.6e}")
|
||||
print(f" 角动量误差: {angular_momentum_error:.6e}")
|
||||
print(f" 能量相对误差: {energy_error:.6e}")
|
||||
|
||||
# 可视化
|
||||
print("\n生成可视化图形...")
|
||||
visualizer = ThreeBodyVisualizer(figsize=(14, 10))
|
||||
|
||||
# 创建3D轨迹图
|
||||
plt.figure(figsize=(14, 10))
|
||||
|
||||
# 3D轨迹
|
||||
ax1 = plt.subplot(2, 2, 1, projection='3d')
|
||||
trajectories = solver.get_trajectories()
|
||||
colors = ['red', 'green', 'blue']
|
||||
|
||||
for i, (traj, particle) in enumerate(zip(trajectories, solver.particles)):
|
||||
color = particle.color if particle.color else colors[i % len(colors)]
|
||||
label = particle.name if particle.name else f"质点 {i+1}"
|
||||
ax1.plot(traj[:, 0], traj[:, 1], traj[:, 2],
|
||||
color=color, alpha=0.7, linewidth=1.5, label=label)
|
||||
ax1.scatter(traj[-1, 0], traj[-1, 1], traj[-1, 2],
|
||||
color=color, s=100, edgecolors='black', linewidth=1.5)
|
||||
|
||||
# 绘制质心
|
||||
com = solver.get_center_of_mass()
|
||||
ax1.scatter(com[0], com[1], com[2],
|
||||
color='black', marker='x', s=200, label='质心', linewidth=2)
|
||||
|
||||
ax1.set_xlabel('X (AU)')
|
||||
ax1.set_ylabel('Y (AU)')
|
||||
ax1.set_zlabel('Z (AU)')
|
||||
ax1.set_title('8字形轨道 - 3D视图')
|
||||
ax1.legend()
|
||||
ax1.grid(True, alpha=0.3)
|
||||
|
||||
# XY平面投影
|
||||
ax2 = plt.subplot(2, 2, 2)
|
||||
for i, (traj, particle) in enumerate(zip(trajectories, solver.particles)):
|
||||
color = particle.color if particle.color else colors[i % len(colors)]
|
||||
label = particle.name if particle.name else f"质点 {i+1}"
|
||||
ax2.plot(traj[:, 0], traj[:, 1], color=color, alpha=0.7, linewidth=1.5, label=label)
|
||||
ax2.scatter(traj[-1, 0], traj[-1, 1], color=color, s=100, edgecolors='black', linewidth=1.5)
|
||||
|
||||
ax2.scatter(com[0], com[1], color='black', marker='x', s=200, label='质心', linewidth=2)
|
||||
ax2.set_xlabel('X (AU)')
|
||||
ax2.set_ylabel('Y (AU)')
|
||||
ax2.set_title('XY平面投影')
|
||||
ax2.legend()
|
||||
ax2.grid(True, alpha=0.3)
|
||||
ax2.set_aspect('equal', adjustable='box')
|
||||
|
||||
# XZ平面投影
|
||||
ax3 = plt.subplot(2, 2, 3)
|
||||
for i, (traj, particle) in enumerate(zip(trajectories, solver.particles)):
|
||||
color = particle.color if particle.color else colors[i % len(colors)]
|
||||
label = particle.name if particle.name else f"质点 {i+1}"
|
||||
ax3.plot(traj[:, 0], traj[:, 2], color=color, alpha=0.7, linewidth=1.5, label=label)
|
||||
ax3.scatter(traj[-1, 0], traj[-1, 2], color=color, s=100, edgecolors='black', linewidth=1.5)
|
||||
|
||||
ax3.scatter(com[0], com[2], color='black', marker='x', s=200, label='质心', linewidth=2)
|
||||
ax3.set_xlabel('X (AU)')
|
||||
ax3.set_ylabel('Z (AU)')
|
||||
ax3.set_title('XZ平面投影')
|
||||
ax3.legend()
|
||||
ax3.grid(True, alpha=0.3)
|
||||
ax3.set_aspect('equal', adjustable='box')
|
||||
|
||||
# YZ平面投影
|
||||
ax4 = plt.subplot(2, 2, 4)
|
||||
for i, (traj, particle) in enumerate(zip(trajectories, solver.particles)):
|
||||
color = particle.color if particle.color else colors[i % len(colors)]
|
||||
label = particle.name if particle.name else f"质点 {i+1}"
|
||||
ax4.plot(traj[:, 1], traj[:, 2], color=color, alpha=0.7, linewidth=1.5, label=label)
|
||||
ax4.scatter(traj[-1, 1], traj[-1, 2], color=color, s=100, edgecolors='black', linewidth=1.5)
|
||||
|
||||
ax4.scatter(com[1], com[2], color='black', marker='x', s=200, label='质心', linewidth=2)
|
||||
ax4.set_xlabel('Y (AU)')
|
||||
ax4.set_ylabel('Z (AU)')
|
||||
ax4.set_title('YZ平面投影')
|
||||
ax4.legend()
|
||||
ax4.grid(True, alpha=0.3)
|
||||
ax4.set_aspect('equal', adjustable='box')
|
||||
|
||||
plt.suptitle('8字形三体轨道', fontsize=16, fontweight='bold')
|
||||
plt.tight_layout()
|
||||
|
||||
# 保存图形
|
||||
output_file = "figure8_orbit.png"
|
||||
plt.savefig(output_file, dpi=300, bbox_inches='tight')
|
||||
print(f"\n图形已保存到: {output_file}")
|
||||
|
||||
# 显示图形
|
||||
plt.show()
|
||||
|
||||
return solver
|
||||
|
||||
|
||||
def analyze_figure8_stability():
|
||||
"""分析8字形轨道的稳定性"""
|
||||
print("\n" + "=" * 60)
|
||||
print("8字形轨道稳定性分析")
|
||||
print("=" * 60)
|
||||
|
||||
# 创建8字形轨道配置
|
||||
particles = ThreeBodyConfig.create_figure8_config()
|
||||
|
||||
# 测试不同时间步长
|
||||
time_steps = [0.01, 0.005, 0.001, 0.0005]
|
||||
total_time = 5.0
|
||||
|
||||
results = []
|
||||
|
||||
for dt in time_steps:
|
||||
print(f"\n测试时间步长: {dt}")
|
||||
|
||||
solver = ThreeBodySolver([p.copy() for p in particles], dt=dt)
|
||||
solver.simulate(total_time=total_time, progress_interval=10000)
|
||||
|
||||
# 计算守恒误差
|
||||
momentum_error, angular_momentum_error, energy_error = solver.get_conservation_errors()
|
||||
|
||||
results.append({
|
||||
'dt': dt,
|
||||
'momentum_error': momentum_error,
|
||||
'angular_momentum_error': angular_momentum_error,
|
||||
'energy_error': energy_error
|
||||
})
|
||||
|
||||
print(f" 能量相对误差: {energy_error:.6e}")
|
||||
|
||||
# 绘制误差随步长变化
|
||||
plt.figure(figsize=(10, 6))
|
||||
|
||||
dts = [r['dt'] for r in results]
|
||||
energy_errors = [r['energy_error'] for r in results]
|
||||
|
||||
plt.loglog(dts, energy_errors, 'o-', linewidth=2, markersize=8)
|
||||
plt.xlabel('时间步长 (年)', fontsize=12)
|
||||
plt.ylabel('能量相对误差', fontsize=12)
|
||||
plt.title('8字形轨道数值误差分析', fontsize=14, fontweight='bold')
|
||||
plt.grid(True, alpha=0.3, which='both')
|
||||
|
||||
# 添加参考线(四阶精度)
|
||||
ref_dt = np.array(dts)
|
||||
ref_error = 1e-4 * (ref_dt / 0.001)**4
|
||||
plt.loglog(ref_dt, ref_error, 'r--', alpha=0.7, label='四阶精度参考线')
|
||||
|
||||
plt.legend()
|
||||
plt.tight_layout()
|
||||
|
||||
output_file = "figure8_stability_analysis.png"
|
||||
plt.savefig(output_file, dpi=300, bbox_inches='tight')
|
||||
print(f"\n稳定性分析图形已保存到: {output_file}")
|
||||
plt.show()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 运行主示例
|
||||
solver = run_figure8_example()
|
||||
|
||||
# 运行稳定性分析(可选)
|
||||
# analyze_figure8_stability()
|
||||
343
three_body_problem/examples/lagrange.py
Normal file
343
three_body_problem/examples/lagrange.py
Normal file
@@ -0,0 +1,343 @@
|
||||
"""
|
||||
拉格朗日点示例 - 三体问题的稳定点
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import sys
|
||||
import os
|
||||
|
||||
# 添加父目录到路径
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from three_body_problem import ThreeBodySolver, ThreeBodyConfig, ThreeBodyVisualizer
|
||||
|
||||
|
||||
def run_lagrange_example(lagrange_point: int = 4, total_time: float = 100.0):
|
||||
"""
|
||||
运行拉格朗日点示例
|
||||
|
||||
参数:
|
||||
lagrange_point: 拉格朗日点编号 (4=L4, 5=L5)
|
||||
total_time: 总模拟时间(年)
|
||||
"""
|
||||
point_name = "L4" if lagrange_point == 4 else "L5"
|
||||
print("=" * 60)
|
||||
print(f"拉格朗日点 {point_name} 示例")
|
||||
print("=" * 60)
|
||||
|
||||
# 创建拉格朗日点配置
|
||||
particles = ThreeBodyConfig.create_lagrange_point_config(lagrange_point=lagrange_point)
|
||||
|
||||
# 打印配置摘要
|
||||
ThreeBodyConfig.print_config_summary(particles)
|
||||
|
||||
# 创建求解器
|
||||
dt = 0.001 # 时间步长(年)
|
||||
solver = ThreeBodySolver(particles, dt=dt)
|
||||
|
||||
print(f"\n开始模拟,总时间: {total_time}年,时间步长: {dt}年")
|
||||
print(f"模拟拉格朗日点 {point_name} 的稳定性")
|
||||
|
||||
solver.simulate(total_time=total_time, progress_interval=20000)
|
||||
|
||||
# 计算守恒误差
|
||||
momentum_error, angular_momentum_error, energy_error = solver.get_conservation_errors()
|
||||
print(f"\n守恒定律误差:")
|
||||
print(f" 动量误差: {momentum_error:.6e}")
|
||||
print(f" 角动量误差: {angular_momentum_error:.6e}")
|
||||
print(f" 能量相对误差: {energy_error:.6e}")
|
||||
|
||||
# 分析测试质点的轨道稳定性
|
||||
test_particle = solver.particles[2] # 测试质点是第三个
|
||||
trajectory = test_particle.get_trajectory()
|
||||
|
||||
# 计算与L4/L5点的距离变化
|
||||
if lagrange_point == 4:
|
||||
lagrange_position = np.array([0.5, np.sqrt(3)/2, 0.0])
|
||||
else: # L5
|
||||
lagrange_position = np.array([0.5, -np.sqrt(3)/2, 0.0])
|
||||
|
||||
distances = np.linalg.norm(trajectory - lagrange_position, axis=1)
|
||||
time_points = np.arange(len(distances)) * dt
|
||||
|
||||
print(f"\n测试质点稳定性分析:")
|
||||
print(f" 初始距离L{lagrange_point}点: {distances[0]:.6e} AU")
|
||||
print(f" 最终距离L{lagrange_point}点: {distances[-1]:.6e} AU")
|
||||
print(f" 最大距离偏差: {np.max(distances):.6e} AU")
|
||||
print(f" 平均距离偏差: {np.mean(distances):.6e} AU")
|
||||
|
||||
# 可视化
|
||||
print("\n生成可视化图形...")
|
||||
|
||||
# 创建图形
|
||||
fig = plt.figure(figsize=(16, 10))
|
||||
|
||||
# 1. XY平面轨迹
|
||||
ax1 = plt.subplot(2, 3, 1)
|
||||
|
||||
# 绘制所有质点的轨迹
|
||||
trajectories = solver.get_trajectories()
|
||||
colors = ['gold', 'blue', 'gray']
|
||||
|
||||
for i, (traj, particle) in enumerate(zip(trajectories, solver.particles)):
|
||||
color = particle.color if particle.color else colors[i % len(colors)]
|
||||
label = particle.name if particle.name else f"质点 {i+1}"
|
||||
|
||||
# 只绘制最后一部分轨迹(更清晰)
|
||||
if len(traj) > 1000:
|
||||
traj_to_plot = traj[-1000:]
|
||||
else:
|
||||
traj_to_plot = traj
|
||||
|
||||
ax1.plot(traj_to_plot[:, 0], traj_to_plot[:, 1],
|
||||
color=color, alpha=0.7, linewidth=1.5, label=label)
|
||||
|
||||
# 绘制最终位置
|
||||
ax1.scatter(traj[-1, 0], traj[-1, 1],
|
||||
color=color, s=100, edgecolors='black', linewidth=1.5, zorder=5)
|
||||
|
||||
# 绘制拉格朗日点位置
|
||||
ax1.scatter(lagrange_position[0], lagrange_position[1],
|
||||
color='red', marker='*', s=300, label=f'L{lagrange_point}点', zorder=10)
|
||||
|
||||
# 绘制等边三角形
|
||||
triangle_points = [
|
||||
[0, 0], # 太阳
|
||||
[1, 0], # 地球
|
||||
lagrange_position[:2] # L4或L5点
|
||||
]
|
||||
triangle_points.append(triangle_points[0]) # 闭合三角形
|
||||
triangle_points = np.array(triangle_points)
|
||||
ax1.plot(triangle_points[:, 0], triangle_points[:, 1],
|
||||
'k--', alpha=0.5, linewidth=1, label='等边三角形')
|
||||
|
||||
ax1.set_xlabel('X (AU)', fontsize=12)
|
||||
ax1.set_ylabel('Y (AU)', fontsize=12)
|
||||
ax1.set_title(f'拉格朗日点 {point_name} - XY平面', fontsize=14, fontweight='bold')
|
||||
ax1.legend(fontsize=10)
|
||||
ax1.grid(True, alpha=0.3)
|
||||
ax1.set_aspect('equal', adjustable='box')
|
||||
|
||||
# 2. 距离随时间变化
|
||||
ax2 = plt.subplot(2, 3, 2)
|
||||
ax2.plot(time_points, distances, 'b-', linewidth=2, alpha=0.8)
|
||||
ax2.set_xlabel('时间 (年)', fontsize=12)
|
||||
ax2.set_ylabel(f'距离L{lagrange_point}点 (AU)', fontsize=12)
|
||||
ax2.set_title('测试质点轨道稳定性', fontsize=14, fontweight='bold')
|
||||
ax2.grid(True, alpha=0.3)
|
||||
|
||||
# 添加平均距离线
|
||||
mean_distance = np.mean(distances)
|
||||
ax2.axhline(y=mean_distance, color='r', linestyle='--', alpha=0.7,
|
||||
label=f'平均距离: {mean_distance:.3e}')
|
||||
ax2.legend(fontsize=10)
|
||||
|
||||
# 3. 相空间图 (x vs vx)
|
||||
ax3 = plt.subplot(2, 3, 3)
|
||||
|
||||
# 计算速度(使用位置差分)
|
||||
if len(trajectory) > 1:
|
||||
dt = solver.dt
|
||||
velocities = np.gradient(trajectory, dt, axis=0)
|
||||
x_positions = trajectory[:, 0]
|
||||
x_velocities = velocities[:, 0]
|
||||
|
||||
# 使用颜色表示时间
|
||||
scatter = ax3.scatter(x_positions, x_velocities, c=time_points,
|
||||
cmap='viridis', alpha=0.7, s=20)
|
||||
plt.colorbar(scatter, ax=ax3, label='时间 (年)')
|
||||
|
||||
ax3.set_xlabel('X 位置 (AU)', fontsize=12)
|
||||
ax3.set_ylabel('X 速度 (AU/年)', fontsize=12)
|
||||
ax3.set_title('测试质点相空间 (X维度)', fontsize=14, fontweight='bold')
|
||||
ax3.grid(True, alpha=0.3)
|
||||
|
||||
# 4. 相对位置图(以地球为参考系)
|
||||
ax4 = plt.subplot(2, 3, 4)
|
||||
|
||||
# 计算相对于地球的位置
|
||||
earth_trajectory = trajectories[1] # 地球是第二个质点
|
||||
sun_trajectory = trajectories[0] # 太阳是第一个质点
|
||||
test_trajectory = trajectories[2] # 测试质点是第三个
|
||||
|
||||
# 转换为以地球为中心的坐标系
|
||||
earth_centered_sun = sun_trajectory - earth_trajectory
|
||||
earth_centered_test = test_trajectory - earth_trajectory
|
||||
|
||||
# 只绘制最后一部分
|
||||
if len(earth_centered_test) > 1000:
|
||||
earth_centered_test = earth_centered_test[-1000:]
|
||||
|
||||
ax4.plot(earth_centered_test[:, 0], earth_centered_test[:, 1],
|
||||
'gray', alpha=0.7, linewidth=1.5, label='测试质点')
|
||||
ax4.scatter(0, 0, color='blue', s=200, label='地球', edgecolors='black', linewidth=1.5)
|
||||
ax4.scatter(earth_centered_sun[-1, 0], earth_centered_sun[-1, 1],
|
||||
color='gold', s=200, label='太阳', edgecolors='black', linewidth=1.5)
|
||||
|
||||
# 绘制理论L4/L5点位置
|
||||
if lagrange_point == 4:
|
||||
l_point_relative = np.array([-0.5, np.sqrt(3)/2])
|
||||
else: # L5
|
||||
l_point_relative = np.array([-0.5, -np.sqrt(3)/2])
|
||||
|
||||
ax4.scatter(l_point_relative[0], l_point_relative[1],
|
||||
color='red', marker='*', s=300, label=f'L{lagrange_point}点', zorder=10)
|
||||
|
||||
ax4.set_xlabel('相对X位置 (AU)', fontsize=12)
|
||||
ax4.set_ylabel('相对Y位置 (AU)', fontsize=12)
|
||||
ax4.set_title('以地球为参考系', fontsize=14, fontweight='bold')
|
||||
ax4.legend(fontsize=10)
|
||||
ax4.grid(True, alpha=0.3)
|
||||
ax4.set_aspect('equal', adjustable='box')
|
||||
|
||||
# 5. 能量随时间变化(简化)
|
||||
ax5 = plt.subplot(2, 3, 5)
|
||||
|
||||
# 计算相对能量变化(简化)
|
||||
# 在实际实现中,需要记录能量历史
|
||||
time_array = np.linspace(0, total_time, len(distances))
|
||||
# 使用距离变化作为能量变化的代理
|
||||
energy_proxy = distances / distances[0]
|
||||
|
||||
ax5.plot(time_array, energy_proxy, 'g-', linewidth=2, alpha=0.8)
|
||||
ax5.set_xlabel('时间 (年)', fontsize=12)
|
||||
ax5.set_ylabel('相对能量变化', fontsize=12)
|
||||
ax5.set_title('轨道能量变化', fontsize=14, fontweight='bold')
|
||||
ax5.grid(True, alpha=0.3)
|
||||
ax5.axhline(y=1.0, color='r', linestyle='--', alpha=0.5, label='初始能量')
|
||||
ax5.legend(fontsize=10)
|
||||
|
||||
# 6. 3D视图
|
||||
ax6 = plt.subplot(2, 3, 6, projection='3d')
|
||||
|
||||
for i, (traj, particle) in enumerate(zip(trajectories, solver.particles)):
|
||||
color = particle.color if particle.color else colors[i % len(colors)]
|
||||
label = particle.name if particle.name else f"质点 {i+1}"
|
||||
|
||||
# 只绘制最后一部分轨迹
|
||||
if len(traj) > 1000:
|
||||
traj_to_plot = traj[-1000:]
|
||||
else:
|
||||
traj_to_plot = traj
|
||||
|
||||
ax6.plot(traj_to_plot[:, 0], traj_to_plot[:, 1], traj_to_plot[:, 2],
|
||||
color=color, alpha=0.7, linewidth=1.5, label=label)
|
||||
|
||||
# 绘制最终位置
|
||||
ax6.scatter(traj[-1, 0], traj[-1, 1], traj[-1, 2],
|
||||
color=color, s=100, edgecolors='black', linewidth=1.5, zorder=5)
|
||||
|
||||
ax6.scatter(lagrange_position[0], lagrange_position[1], lagrange_position[2],
|
||||
color='red', marker='*', s=300, label=f'L{lagrange_point}点', zorder=10)
|
||||
|
||||
ax6.set_xlabel('X (AU)', fontsize=10)
|
||||
ax6.set_ylabel('Y (AU)', fontsize=10)
|
||||
ax6.set_zlabel('Z (AU)', fontsize=10)
|
||||
ax6.set_title('3D视图', fontsize=14, fontweight='bold')
|
||||
ax6.legend(fontsize=9, loc='upper left')
|
||||
ax6.grid(True, alpha=0.3)
|
||||
|
||||
plt.suptitle(f'拉格朗日点 {point_name} 稳定性分析', fontsize=16, fontweight='bold')
|
||||
plt.tight_layout()
|
||||
|
||||
# 保存图形
|
||||
output_file = f"lagrange_point_{point_name}.png"
|
||||
plt.savefig(output_file, dpi=300, bbox_inches='tight')
|
||||
print(f"\n图形已保存到: {output_file}")
|
||||
|
||||
# 显示图形
|
||||
plt.show()
|
||||
|
||||
return solver
|
||||
|
||||
|
||||
def compare_lagrange_points():
|
||||
"""比较L4和L5点的稳定性"""
|
||||
print("\n" + "=" * 60)
|
||||
print("拉格朗日点L4和L5稳定性比较")
|
||||
print("=" * 60)
|
||||
|
||||
total_time = 50.0
|
||||
dt = 0.001
|
||||
|
||||
results = []
|
||||
|
||||
for lagrange_point in [4, 5]:
|
||||
point_name = f"L{lagrange_point}"
|
||||
print(f"\n模拟 {point_name} 点...")
|
||||
|
||||
particles = ThreeBodyConfig.create_lagrange_point_config(lagrange_point=lagrange_point)
|
||||
solver = ThreeBodySolver([p.copy() for p in particles], dt=dt)
|
||||
solver.simulate(total_time=total_time, progress_interval=25000)
|
||||
|
||||
# 分析测试质点的轨道稳定性
|
||||
test_particle = solver.particles[2]
|
||||
trajectory = test_particle.get_trajectory()
|
||||
|
||||
if lagrange_point == 4:
|
||||
lagrange_position = np.array([0.5, np.sqrt(3)/2, 0.0])
|
||||
else: # L5
|
||||
lagrange_position = np.array([0.5, -np.sqrt(3)/2, 0.0])
|
||||
|
||||
distances = np.linalg.norm(trajectory - lagrange_position, axis=1)
|
||||
|
||||
results.append({
|
||||
'point': point_name,
|
||||
'max_distance': np.max(distances),
|
||||
'mean_distance': np.mean(distances),
|
||||
'std_distance': np.std(distances),
|
||||
'final_distance': distances[-1]
|
||||
})
|
||||
|
||||
print(f" {point_name} 最大距离偏差: {np.max(distances):.6e} AU")
|
||||
print(f" {point_name} 平均距离偏差: {np.mean(distances):.6e} AU")
|
||||
|
||||
# 绘制比较图
|
||||
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
|
||||
|
||||
points = [r['point'] for r in results]
|
||||
max_distances = [r['max_distance'] for r in results]
|
||||
mean_distances = [r['mean_distance'] for r in results]
|
||||
|
||||
x = np.arange(len(points))
|
||||
width = 0.35
|
||||
|
||||
axes[0].bar(x - width/2, max_distances, width, label='最大偏差', color='lightcoral')
|
||||
axes[0].bar(x + width/2, mean_distances, width, label='平均偏差', color='lightblue')
|
||||
axes[0].set_xlabel('拉格朗日点', fontsize=12)
|
||||
axes[0].set_ylabel('距离偏差 (AU)', fontsize=12)
|
||||
axes[0].set_title('L4和L5点稳定性比较', fontsize=14, fontweight='bold')
|
||||
axes[0].set_xticks(x)
|
||||
axes[0].set_xticklabels(points)
|
||||
axes[0].legend()
|
||||
axes[0].grid(True, alpha=0.3, axis='y')
|
||||
|
||||
# 最终位置偏差
|
||||
final_distances = [r['final_distance'] for r in results]
|
||||
axes[1].bar(points, final_distances, color=['lightgreen', 'lightblue'])
|
||||
axes[1].set_xlabel('拉格朗日点', fontsize=12)
|
||||
axes[1].set_ylabel('最终距离偏差 (AU)', fontsize=12)
|
||||
axes[1].set_title('最终位置稳定性', fontsize=14, fontweight='bold')
|
||||
axes[1].grid(True, alpha=0.3, axis='y')
|
||||
|
||||
plt.tight_layout()
|
||||
|
||||
output_file = "lagrange_points_comparison.png"
|
||||
plt.savefig(output_file, dpi=300, bbox_inches='tight')
|
||||
print(f"\n比较图形已保存到: {output_file}")
|
||||
plt.show()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 运行L4点示例
|
||||
print("运行拉格朗日点L4示例...")
|
||||
solver_l4 = run_lagrange_example(lagrange_point=4, total_time=50.0)
|
||||
|
||||
# 运行L5点示例
|
||||
print("\n" + "="*60)
|
||||
print("运行拉格朗日点L5示例...")
|
||||
solver_l5 = run_lagrange_example(lagrange_point=5, total_time=50.0)
|
||||
|
||||
# 比较L4和L5
|
||||
compare_lagrange_points()
|
||||
426
three_body_problem/examples/random.py
Normal file
426
three_body_problem/examples/random.py
Normal file
@@ -0,0 +1,426 @@
|
||||
"""
|
||||
随机初始条件示例 - 探索不同的三体系统
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import sys
|
||||
import os
|
||||
|
||||
# 添加父目录到路径
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from three_body_problem import ThreeBodySolver, ThreeBodyConfig, ThreeBodyVisualizer
|
||||
|
||||
|
||||
def run_random_example(seed: int = 42, total_time: float = 20.0):
|
||||
"""
|
||||
运行随机初始条件示例
|
||||
|
||||
参数:
|
||||
seed: 随机种子
|
||||
total_time: 总模拟时间(年)
|
||||
"""
|
||||
np.random.seed(seed)
|
||||
|
||||
print("=" * 60)
|
||||
print(f"随机初始条件示例 (种子: {seed})")
|
||||
print("=" * 60)
|
||||
|
||||
# 创建随机配置
|
||||
particles = ThreeBodyConfig.create_random_config(
|
||||
masses=None, # 使用随机质量
|
||||
position_range=2.0, # 位置范围 ±2 AU
|
||||
velocity_scale=3.0 # 速度缩放因子
|
||||
)
|
||||
|
||||
# 打印配置摘要
|
||||
ThreeBodyConfig.print_config_summary(particles)
|
||||
|
||||
# 创建求解器
|
||||
dt = 0.001 # 时间步长(年)
|
||||
solver = ThreeBodySolver(particles, dt=dt)
|
||||
|
||||
print(f"\n开始模拟,总时间: {total_time}年,时间步长: {dt}年")
|
||||
|
||||
solver.simulate(total_time=total_time, progress_interval=2000)
|
||||
|
||||
# 计算守恒误差
|
||||
momentum_error, angular_momentum_error, energy_error = solver.get_conservation_errors()
|
||||
print(f"\n守恒定律误差:")
|
||||
print(f" 动量误差: {momentum_error:.6e}")
|
||||
print(f" 角动量误差: {angular_momentum_error:.6e}")
|
||||
print(f" 能量相对误差: {energy_error:.6e}")
|
||||
|
||||
# 分析系统行为
|
||||
analyze_system_behavior(solver)
|
||||
|
||||
# 可视化
|
||||
print("\n生成可视化图形...")
|
||||
visualize_random_system(solver, seed)
|
||||
|
||||
return solver
|
||||
|
||||
|
||||
def analyze_system_behavior(solver: ThreeBodySolver):
|
||||
"""分析三体系统的行为"""
|
||||
print("\n" + "-" * 40)
|
||||
print("系统行为分析")
|
||||
print("-" * 40)
|
||||
|
||||
trajectories = solver.get_trajectories()
|
||||
|
||||
# 计算每个质点的运动范围
|
||||
for i, (traj, particle) in enumerate(zip(trajectories, solver.particles)):
|
||||
pos_range = np.ptp(traj, axis=0) # 位置范围 (max - min)
|
||||
avg_speed = np.mean(np.linalg.norm(np.gradient(traj, solver.dt, axis=0), axis=1))
|
||||
|
||||
print(f"\n质点 {i+1} ({particle.name}):")
|
||||
print(f" 质量: {particle.mass:.4f} M_sun")
|
||||
print(f" 位置范围: X={pos_range[0]:.3f}, Y={pos_range[1]:.3f}, Z={pos_range[2]:.3f} AU")
|
||||
print(f" 平均速度: {avg_speed:.3f} AU/年")
|
||||
|
||||
# 计算质点之间的最小距离
|
||||
min_distances = []
|
||||
for i in range(3):
|
||||
for j in range(i+1, 3):
|
||||
traj_i = trajectories[i]
|
||||
traj_j = trajectories[j]
|
||||
distances = np.linalg.norm(traj_i - traj_j, axis=1)
|
||||
min_dist = np.min(distances)
|
||||
min_distances.append((i, j, min_dist))
|
||||
|
||||
print(f"\n质点间最小距离:")
|
||||
for i, j, min_dist in min_distances:
|
||||
print(f" 质点{i+1}-质点{j+1}: {min_dist:.4f} AU")
|
||||
|
||||
# 检查是否有碰撞或近距离接近
|
||||
collision_threshold = 0.1 # AU
|
||||
close_encounters = [(i, j, d) for i, j, d in min_distances if d < collision_threshold]
|
||||
|
||||
if close_encounters:
|
||||
print(f"\n警告: 检测到近距离接近!")
|
||||
for i, j, d in close_encounters:
|
||||
print(f" 质点{i+1}和质点{j+1}的最小距离: {d:.4f} AU < {collision_threshold} AU")
|
||||
else:
|
||||
print(f"\n系统稳定: 所有质点间距离都大于 {collision_threshold} AU")
|
||||
|
||||
# 计算系统质心运动
|
||||
com_trajectory = []
|
||||
for t in range(len(trajectories[0])):
|
||||
com = np.zeros(3)
|
||||
total_mass = 0.0
|
||||
for i, traj in enumerate(trajectories):
|
||||
com += solver.particles[i].mass * traj[t]
|
||||
total_mass += solver.particles[i].mass
|
||||
com_trajectory.append(com / total_mass)
|
||||
|
||||
com_trajectory = np.array(com_trajectory)
|
||||
com_range = np.ptp(com_trajectory, axis=0)
|
||||
print(f"\n系统质心运动范围: X={com_range[0]:.4f}, Y={com_range[1]:.4f}, Z={com_range[2]:.4f} AU")
|
||||
|
||||
|
||||
def visualize_random_system(solver: ThreeBodySolver, seed: int):
|
||||
"""可视化随机三体系统"""
|
||||
trajectories = solver.get_trajectories()
|
||||
|
||||
# 创建图形
|
||||
fig = plt.figure(figsize=(16, 12))
|
||||
|
||||
# 1. 3D轨迹图
|
||||
ax1 = plt.subplot(2, 3, 1, projection='3d')
|
||||
|
||||
colors = ['red', 'green', 'blue']
|
||||
for i, (traj, particle) in enumerate(zip(trajectories, solver.particles)):
|
||||
color = particle.color if particle.color else colors[i % len(colors)]
|
||||
label = particle.name if particle.name else f"质点 {i+1}"
|
||||
|
||||
ax1.plot(traj[:, 0], traj[:, 1], traj[:, 2],
|
||||
color=color, alpha=0.7, linewidth=1.5, label=label)
|
||||
ax1.scatter(traj[-1, 0], traj[-1, 1], traj[-1, 2],
|
||||
color=color, s=100, edgecolors='black', linewidth=1.5)
|
||||
|
||||
# 绘制质心轨迹
|
||||
com_trajectory = []
|
||||
for t in range(len(trajectories[0])):
|
||||
com = np.zeros(3)
|
||||
total_mass = 0.0
|
||||
for i, traj in enumerate(trajectories):
|
||||
com += solver.particles[i].mass * traj[t]
|
||||
total_mass += solver.particles[i].mass
|
||||
com_trajectory.append(com / total_mass)
|
||||
|
||||
com_trajectory = np.array(com_trajectory)
|
||||
ax1.plot(com_trajectory[:, 0], com_trajectory[:, 1], com_trajectory[:, 2],
|
||||
'k--', alpha=0.5, linewidth=1, label='质心轨迹')
|
||||
ax1.scatter(com_trajectory[-1, 0], com_trajectory[-1, 1], com_trajectory[-1, 2],
|
||||
color='black', marker='x', s=200, label='质心', linewidth=2)
|
||||
|
||||
ax1.set_xlabel('X (AU)', fontsize=12)
|
||||
ax1.set_ylabel('Y (AU)', fontsize=12)
|
||||
ax1.set_zlabel('Z (AU)', fontsize=12)
|
||||
ax1.set_title('3D轨迹图', fontsize=14, fontweight='bold')
|
||||
ax1.legend(fontsize=10)
|
||||
ax1.grid(True, alpha=0.3)
|
||||
|
||||
# 2. XY平面投影
|
||||
ax2 = plt.subplot(2, 3, 2)
|
||||
for i, (traj, particle) in enumerate(zip(trajectories, solver.particles)):
|
||||
color = particle.color if particle.color else colors[i % len(colors)]
|
||||
label = particle.name if particle.name else f"质点 {i+1}"
|
||||
ax2.plot(traj[:, 0], traj[:, 1], color=color, alpha=0.7, linewidth=1.5, label=label)
|
||||
ax2.scatter(traj[-1, 0], traj[-1, 1], color=color, s=100, edgecolors='black', linewidth=1.5)
|
||||
|
||||
ax2.plot(com_trajectory[:, 0], com_trajectory[:, 1], 'k--', alpha=0.5, linewidth=1)
|
||||
ax2.scatter(com_trajectory[-1, 0], com_trajectory[-1, 1],
|
||||
color='black', marker='x', s=200, linewidth=2)
|
||||
|
||||
ax2.set_xlabel('X (AU)', fontsize=12)
|
||||
ax2.set_ylabel('Y (AU)', fontsize=12)
|
||||
ax2.set_title('XY平面投影', fontsize=14, fontweight='bold')
|
||||
ax2.legend(fontsize=10)
|
||||
ax2.grid(True, alpha=0.3)
|
||||
ax2.set_aspect('equal', adjustable='box')
|
||||
|
||||
# 3. 距离随时间变化
|
||||
ax3 = plt.subplot(2, 3, 3)
|
||||
|
||||
time_points = np.arange(len(trajectories[0])) * solver.dt
|
||||
|
||||
# 计算所有质点对之间的距离
|
||||
distances = []
|
||||
labels = []
|
||||
for i in range(3):
|
||||
for j in range(i+1, 3):
|
||||
dist = np.linalg.norm(trajectories[i] - trajectories[j], axis=1)
|
||||
distances.append(dist)
|
||||
labels.append(f"质点{i+1}-质点{j+1}")
|
||||
|
||||
for dist, label in zip(distances, labels):
|
||||
ax3.plot(time_points, dist, linewidth=1.5, alpha=0.8, label=label)
|
||||
|
||||
ax3.set_xlabel('时间 (年)', fontsize=12)
|
||||
ax3.set_ylabel('距离 (AU)', fontsize=12)
|
||||
ax3.set_title('质点间距离变化', fontsize=14, fontweight='bold')
|
||||
ax3.legend(fontsize=10)
|
||||
ax3.grid(True, alpha=0.3)
|
||||
|
||||
# 4. 速度大小随时间变化
|
||||
ax4 = plt.subplot(2, 3, 4)
|
||||
|
||||
for i, (traj, particle) in enumerate(zip(trajectories, solver.particles)):
|
||||
color = particle.color if particle.color else colors[i % len(colors)]
|
||||
label = particle.name if particle.name else f"质点 {i+1}"
|
||||
|
||||
# 计算速度大小(使用位置差分)
|
||||
if len(traj) > 1:
|
||||
velocities = np.gradient(traj, solver.dt, axis=0)
|
||||
speed = np.linalg.norm(velocities, axis=1)
|
||||
ax4.plot(time_points, speed, color=color, linewidth=1.5, alpha=0.8, label=label)
|
||||
|
||||
ax4.set_xlabel('时间 (年)', fontsize=12)
|
||||
ax4.set_ylabel('速度大小 (AU/年)', fontsize=12)
|
||||
ax4.set_title('质点速度变化', fontsize=14, fontweight='bold')
|
||||
ax4.legend(fontsize=10)
|
||||
ax4.grid(True, alpha=0.3)
|
||||
|
||||
# 5. 能量分布饼图
|
||||
ax5 = plt.subplot(2, 3, 5)
|
||||
|
||||
# 计算每个质点的动能和势能
|
||||
kinetic_energies = []
|
||||
potential_energies = []
|
||||
|
||||
for i, particle in enumerate(solver.particles):
|
||||
# 动能
|
||||
v_squared = np.sum(particle.velocity**2)
|
||||
kinetic_energy = 0.5 * particle.mass * v_squared
|
||||
kinetic_energies.append(kinetic_energy)
|
||||
|
||||
# 势能(与其他质点的相互作用)
|
||||
potential_energy = 0.0
|
||||
for j, other in enumerate(solver.particles):
|
||||
if i != j:
|
||||
r_vec = other.position - particle.position
|
||||
r = np.linalg.norm(r_vec)
|
||||
if r > 1e-10:
|
||||
potential_energy -= ThreeBodySolver.G * particle.mass * other.mass / r
|
||||
potential_energies.append(potential_energy)
|
||||
|
||||
# 只考虑势能的一半(每对质点计算了两次)
|
||||
potential_energies = [pe/2 for pe in potential_energies]
|
||||
|
||||
labels = [f"质点{i+1}" for i in range(3)]
|
||||
colors_pie = ['lightcoral', 'lightgreen', 'lightblue']
|
||||
|
||||
ax5.pie(kinetic_energies, labels=labels, autopct='%1.1f%%',
|
||||
colors=colors_pie, startangle=90)
|
||||
ax5.set_title('动能分布', fontsize=14, fontweight='bold')
|
||||
|
||||
# 6. 相空间图(所有质点)
|
||||
ax6 = plt.subplot(2, 3, 6)
|
||||
|
||||
for i, (traj, particle) in enumerate(zip(trajectories, solver.particles)):
|
||||
color = particle.color if particle.color else colors[i % len(colors)]
|
||||
label = particle.name if particle.name else f"质点 {i+1}"
|
||||
|
||||
if len(traj) > 1:
|
||||
velocities = np.gradient(traj, solver.dt, axis=0)
|
||||
x_positions = traj[:, 0]
|
||||
x_velocities = velocities[:, 0]
|
||||
|
||||
# 使用颜色表示时间
|
||||
scatter = ax6.scatter(x_positions, x_velocities, c=time_points,
|
||||
cmap='viridis', alpha=0.6, s=10, label=label)
|
||||
|
||||
plt.colorbar(scatter, ax=ax6, label='时间 (年)')
|
||||
ax6.set_xlabel('X 位置 (AU)', fontsize=12)
|
||||
ax6.set_ylabel('X 速度 (AU/年)', fontsize=12)
|
||||
ax6.set_title('相空间图 (X维度)', fontsize=14, fontweight='bold')
|
||||
ax6.legend(fontsize=10)
|
||||
ax6.grid(True, alpha=0.3)
|
||||
|
||||
plt.suptitle(f'随机三体系统 (种子: {seed})', fontsize=16, fontweight='bold')
|
||||
plt.tight_layout()
|
||||
|
||||
# 保存图形
|
||||
output_file = f"random_system_seed_{seed}.png"
|
||||
plt.savefig(output_file, dpi=300, bbox_inches='tight')
|
||||
print(f"\n图形已保存到: {output_file}")
|
||||
|
||||
# 显示图形
|
||||
plt.show()
|
||||
|
||||
|
||||
def run_multiple_random_simulations(n_simulations: int = 5, total_time: float = 10.0):
|
||||
"""运行多个随机模拟并比较结果"""
|
||||
print("=" * 60)
|
||||
print(f"运行 {n_simulations} 个随机三体系统模拟")
|
||||
print("=" * 60)
|
||||
|
||||
results = []
|
||||
|
||||
for sim_idx in range(n_simulations):
|
||||
seed = 100 + sim_idx # 不同的随机种子
|
||||
np.random.seed(seed)
|
||||
|
||||
print(f"\n模拟 {sim_idx+1}/{n_simulations} (种子: {seed})")
|
||||
|
||||
# 创建随机配置
|
||||
particles = ThreeBodyConfig.create_random_config(
|
||||
masses=None,
|
||||
position_range=2.0,
|
||||
velocity_scale=2.0 + np.random.random() * 2.0 # 随机速度缩放
|
||||
)
|
||||
|
||||
# 创建求解器
|
||||
solver = ThreeBodySolver(particles, dt=0.001)
|
||||
solver.simulate(total_time=total_time, progress_interval=5000)
|
||||
|
||||
# 分析结果
|
||||
trajectories = solver.get_trajectories()
|
||||
|
||||
# 计算系统特性
|
||||
final_distances = []
|
||||
for i in range(3):
|
||||
for j in range(i+1, 3):
|
||||
final_dist = np.linalg.norm(trajectories[i][-1] - trajectories[j][-1])
|
||||
final_distances.append(final_dist)
|
||||
|
||||
avg_final_distance = np.mean(final_distances)
|
||||
std_final_distance = np.std(final_distances)
|
||||
|
||||
# 计算质心移动距离
|
||||
initial_com = solver.get_center_of_mass()
|
||||
# 需要重新计算初始质心
|
||||
total_mass = sum(p.mass for p in particles)
|
||||
initial_com = np.zeros(3)
|
||||
for p in particles:
|
||||
initial_com += p.mass * p.position
|
||||
initial_com /= total_mass
|
||||
|
||||
final_com = solver.get_center_of_mass()
|
||||
com_movement = np.linalg.norm(final_com - initial_com)
|
||||
|
||||
results.append({
|
||||
'seed': seed,
|
||||
'avg_final_distance': avg_final_distance,
|
||||
'std_final_distance': std_final_distance,
|
||||
'com_movement': com_movement,
|
||||
'energy_error': solver.get_conservation_errors()[2]
|
||||
})
|
||||
|
||||
print(f" 平均最终距离: {avg_final_distance:.3f} AU")
|
||||
print(f" 质心移动: {com_movement:.3f} AU")
|
||||
print(f" 能量相对误差: {solver.get_conservation_errors()[2]:.6e}")
|
||||
|
||||
# 绘制比较图
|
||||
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
|
||||
|
||||
seeds = [r['seed'] for r in results]
|
||||
avg_distances = [r['avg_final_distance'] for r in results]
|
||||
com_movements = [r['com_movement'] for r in results]
|
||||
energy_errors = [r['energy_error'] for r in results]
|
||||
|
||||
# 平均最终距离
|
||||
axes[0, 0].bar(range(n_simulations), avg_distances, color='skyblue', edgecolor='black')
|
||||
axes[0, 0].set_xlabel('模拟编号', fontsize=12)
|
||||
axes[0, 0].set_ylabel('平均最终距离 (AU)', fontsize=12)
|
||||
axes[0, 0].set_title('质点间平均距离', fontsize=14, fontweight='bold')
|
||||
axes[0, 0].set_xticks(range(n_simulations))
|
||||
axes[0, 0].set_xticklabels([f"#{i+1}" for i in range(n_simulations)])
|
||||
axes[0, 0].grid(True, alpha=0.3, axis='y')
|
||||
|
||||
# 质心移动
|
||||
axes[0, 1].bar(range(n_simulations), com_movements, color='lightgreen', edgecolor='black')
|
||||
axes[0, 1].set_xlabel('模拟编号', fontsize=12)
|
||||
axes[0, 1].set_ylabel('质心移动距离 (AU)', fontsize=12)
|
||||
axes[0, 1].set_title('系统质心移动', fontsize=14, fontweight='bold')
|
||||
axes[0, 1].set_xticks(range(n_simulations))
|
||||
axes[0, 1].set_xticklabels([f"#{i+1}" for i in range(n_simulations)])
|
||||
axes[0, 1].grid(True, alpha=0.3, axis='y')
|
||||
|
||||
# 能量误差
|
||||
axes[1, 0].bar(range(n_simulations), energy_errors, color='lightcoral', edgecolor='black')
|
||||
axes[1, 0].set_xlabel('模拟编号', fontsize=12)
|
||||
axes[1, 0].set_ylabel('能量相对误差', fontsize=12)
|
||||
axes[1, 0].set_title('数值积分误差', fontsize=14, fontweight='bold')
|
||||
axes[1, 0].set_xticks(range(n_simulations))
|
||||
axes[1, 0].set_xticklabels([f"#{i+1}" for i in range(n_simulations)])
|
||||
axes[1, 0].set_yscale('log')
|
||||
axes[1, 0].grid(True, alpha=0.3, axis='y')
|
||||
|
||||
# 散点图:质心移动 vs 平均距离
|
||||
axes[1, 1].scatter(avg_distances, com_movements, s=100, c=range(n_simulations),
|
||||
cmap='viridis', edgecolors='black', alpha=0.8)
|
||||
axes[1, 1].set_xlabel('平均最终距离 (AU)', fontsize=12)
|
||||
axes[1, 1].set_ylabel('质心移动距离 (AU)', fontsize=12)
|
||||
axes[1, 1].set_title('系统稳定性关系', fontsize=14, fontweight='bold')
|
||||
|
||||
# 添加标签
|
||||
for i, (x, y) in enumerate(zip(avg_distances, com_movements)):
|
||||
axes[1, 1].annotate(f"#{i+1}", (x, y), textcoords="offset points",
|
||||
xytext=(0, 10), ha='center', fontsize=9)
|
||||
|
||||
axes[1, 1].grid(True, alpha=0.3)
|
||||
|
||||
plt.suptitle(f'{n_simulations}个随机三体系统模拟比较', fontsize=16, fontweight='bold')
|
||||
plt.tight_layout()
|
||||
|
||||
output_file = "multiple_random_simulations.png"
|
||||
plt.savefig(output_file, dpi=300, bbox_inches='tight')
|
||||
print(f"\n比较图形已保存到: {output_file}")
|
||||
plt.show()
|
||||
|
||||
return results
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 运行单个随机示例
|
||||
print("运行单个随机三体系统示例...")
|
||||
solver = run_random_example(seed=42, total_time=15.0)
|
||||
|
||||
# 运行多个随机模拟(可选)
|
||||
# print("\n" + "="*60)
|
||||
# print("运行多个随机模拟比较...")
|
||||
# results = run_multiple_random_simulations(n_simulations=5, total_time=5.0)
|
||||
Reference in New Issue
Block a user