""" 三体问题配置管理模块 """ 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)