Files
three-body-problem/three_body_problem/config.py
dison0331-ThinkPad 8c8ad9fe07 first
pc-1
2026-03-11 21:32:58 +08:00

280 lines
9.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
三体问题配置管理模块
"""
import numpy as np
from typing import List, Dict, Any, Optional
from .particle import Particle
class ThreeBodyConfig:
"""三体问题配置类"""
@staticmethod
def create_figure8_config() -> List[Particle]:
"""
创建8字形轨道配置著名的稳定三体轨道
返回:
三个质点的列表
"""
# 8字形轨道的初始条件等质量
m = 1.0 # 质量
# 位置 (Chenciner & Montgomery, 2000)
r1 = np.array([0.97000436, -0.24308753, 0.0])
r2 = np.array([-0.97000436, 0.24308753, 0.0])
r3 = np.array([0.0, 0.0, 0.0])
# 速度
v1 = np.array([0.466203685, 0.43236573, 0.0])
v2 = np.array([0.466203685, 0.43236573, 0.0])
v3 = np.array([-0.93240737, -0.86473146, 0.0])
particles = [
Particle(mass=m, position=r1, velocity=v1, name="Star A", color="red"),
Particle(mass=m, position=r2, velocity=v2, name="Star B", color="green"),
Particle(mass=m, position=r3, velocity=v3, name="Star C", color="blue")
]
return particles
@staticmethod
def create_lagrange_point_config(lagrange_point: int = 4) -> List[Particle]:
"""
创建拉格朗日点配置
参数:
lagrange_point: 拉格朗日点编号 (4=L4, 5=L5)
返回:
三个质点的列表
"""
if lagrange_point not in [4, 5]:
raise ValueError("lagrange_point 必须是 4 (L4) 或 5 (L5)")
# 大质量天体(类似太阳)
m_sun = 1.0
# 小质量天体(类似地球)
m_earth = 3e-6 # 地球质量/太阳质量
# 测试质点(类似小行星)
m_test = 1e-8
# 大质量天体在原点
r_sun = np.array([0.0, 0.0, 0.0])
v_sun = np.array([0.0, 0.0, 0.0])
# 小质量天体在圆形轨道上1 AU距离
r_earth = np.array([1.0, 0.0, 0.0])
# 圆形轨道速度v = sqrt(G*M/r)
v_earth = np.array([0.0, 2*np.pi, 0.0]) # 2π AU/年
# 拉格朗日点位置(等边三角形)
if lagrange_point == 4: # L4
r_test = np.array([0.5, np.sqrt(3)/2, 0.0])
else: # L5
r_test = np.array([0.5, -np.sqrt(3)/2, 0.0])
# 测试质点的速度(与地球相同角速度)
v_test = np.array([-np.sqrt(3)/2 * 2*np.pi, 0.5 * 2*np.pi, 0.0])
particles = [
Particle(mass=m_sun, position=r_sun, velocity=v_sun, name="Sun", color="yellow"),
Particle(mass=m_earth, position=r_earth, velocity=v_earth, name="Earth", color="blue"),
Particle(mass=m_test, position=r_test, velocity=v_test, name="Test", color="gray")
]
return particles
@staticmethod
def create_random_config(masses: Optional[List[float]] = None,
position_range: float = 2.0,
velocity_scale: float = 1.0) -> List[Particle]:
"""
创建随机初始条件配置
参数:
masses: 质量列表如果为None则使用随机质量
position_range: 位置范围±position_range
velocity_scale: 速度缩放因子
返回:
三个质点的列表
"""
if masses is None:
# 随机质量在0.5到2.0之间)
masses = np.random.uniform(0.5, 2.0, 3)
if len(masses) != 3:
raise ValueError("需要恰好3个质量值")
particles = []
colors = ['red', 'green', 'blue']
names = ['Star A', 'Star B', 'Star C']
for i in range(3):
# 随机位置
position = np.random.uniform(-position_range, position_range, 3)
# 随机速度(确保系统总动量接近零)
velocity = np.random.uniform(-velocity_scale, velocity_scale, 3)
particles.append(
Particle(mass=masses[i], position=position, velocity=velocity,
name=names[i], color=colors[i])
)
# 调整速度使系统总动量接近零
total_momentum = sum(p.mass * p.velocity for p in particles)
total_mass = sum(p.mass for p in particles)
for p in particles:
p.velocity -= total_momentum / total_mass
return particles
@staticmethod
def create_binary_star_config() -> List[Particle]:
"""
创建双星系统+测试质点配置
返回:
三个质点的列表
"""
# 双星质量
m1 = 1.0
m2 = 0.8
# 双星位置(在椭圆轨道上)
# 半长轴
a = 1.0
# 偏心率
e = 0.3
# 质心在原点
r1 = np.array([-m2/(m1+m2) * a * (1+e), 0.0, 0.0])
r2 = np.array([m1/(m1+m2) * a * (1+e), 0.0, 0.0])
# 计算轨道速度(简化圆形轨道近似)
# 对于椭圆轨道,速度更复杂,这里使用简化
orbital_speed = np.sqrt(4*np.pi**2 * (m1+m2) / (2*a))
v1 = np.array([0.0, orbital_speed * m2/(m1+m2), 0.0])
v2 = np.array([0.0, -orbital_speed * m1/(m1+m2), 0.0])
# 测试质点(小质量)
m_test = 0.01
r_test = np.array([0.0, 2.0, 0.0])
v_test = np.array([0.5, 0.0, 0.0])
particles = [
Particle(mass=m1, position=r1, velocity=v1, name="Primary", color="red"),
Particle(mass=m2, position=r2, velocity=v2, name="Secondary", color="green"),
Particle(mass=m_test, position=r_test, velocity=v_test, name="Test", color="blue")
]
return particles
@staticmethod
def create_custom_config(config_dict: Dict[str, Any]) -> List[Particle]:
"""
从字典创建自定义配置
参数:
config_dict: 包含配置信息的字典
返回:
三个质点的列表
"""
particles = []
for i in range(3):
key = f"particle_{i+1}"
if key not in config_dict:
raise ValueError(f"配置中缺少 {key}")
p_config = config_dict[key]
particle = Particle(
mass=p_config.get('mass', 1.0),
position=np.array(p_config.get('position', [0.0, 0.0, 0.0])),
velocity=np.array(p_config.get('velocity', [0.0, 0.0, 0.0])),
name=p_config.get('name', f"Particle {i+1}"),
color=p_config.get('color', None)
)
particles.append(particle)
return particles
@staticmethod
def save_config(particles: List[Particle], filename: str):
"""
保存配置到文件
参数:
particles: 质点列表
filename: 文件名
"""
config_dict = {}
for i, p in enumerate(particles):
config_dict[f"particle_{i+1}"] = {
'mass': float(p.mass),
'position': p.position.tolist(),
'velocity': p.velocity.tolist(),
'name': p.name,
'color': p.color
}
import json
with open(filename, 'w') as f:
json.dump(config_dict, f, indent=2)
print(f"配置已保存到: {filename}")
@staticmethod
def load_config(filename: str) -> List[Particle]:
"""
从文件加载配置
参数:
filename: 文件名
返回:
三个质点的列表
"""
import json
with open(filename, 'r') as f:
config_dict = json.load(f)
return ThreeBodyConfig.create_custom_config(config_dict)
@staticmethod
def print_config_summary(particles: List[Particle]):
"""打印配置摘要"""
print("=" * 60)
print("三体问题配置摘要")
print("=" * 60)
total_mass = 0.0
total_momentum = np.zeros(3)
total_angular_momentum = np.zeros(3)
for i, p in enumerate(particles):
print(f"\n质点 {i+1} ({p.name}):")
print(f" 质量: {p.mass:.6f} M_sun")
print(f" 位置: [{p.position[0]:.6f}, {p.position[1]:.6f}, {p.position[2]:.6f}] AU")
print(f" 速度: [{p.velocity[0]:.6f}, {p.velocity[1]:.6f}, {p.velocity[2]:.6f}] AU/yr")
total_mass += p.mass
total_momentum += p.mass * p.velocity
angular_momentum = np.cross(p.position, p.mass * p.velocity)
total_angular_momentum += angular_momentum
print("\n" + "=" * 60)
print("系统总质量: {:.6f} M_sun".format(total_mass))
print("系统总动量: [{:.6e}, {:.6e}, {:.6e}]".format(
total_momentum[0], total_momentum[1], total_momentum[2]))
print("系统总角动量: [{:.6e}, {:.6e}, {:.6e}]".format(
total_angular_momentum[0], total_angular_momentum[1], total_angular_momentum[2]))
print("=" * 60)