e2m2e package

e2m2e - Earth to Moon, Moon to Earth Transfer Orbit Design Library

一个用于设计和分析地月空间转移轨道的Python库,专注于圆型限制性三体问题 (CR3BP)中的轨道动力学。五层架构(ADR 0011):data/(数据层)、crates/ (数值层)、algorithm/(算法层)、api/(接口层)、tools/(工具层)。

主要能力:任务轨道设计、轨道保持、转移轨道设计、轨道预报、时空坐标转换。

作者: 天疆说

Subpackages

Submodules

e2m2e.integrators module

Rust 积分器扩展的公共 Python 适配层。

e2m2e.integrators.augmented_eom_7d_py(forces_py, observer, et, state7, thrust_spec)

7D 受控动力学单点求值(配点法用)。

包装 augmented_eom_7d :给定状态 [r,v,m] 与控制参数 (t_max, isp, throttle, θ₁, θ₂) ,返回 7D 导数。方向由角度参数化还原。

# 参数 - forces_py: 非推力 force 元组列表(格式同 propagate_compiled ) - observer: 传播系 origin - et: 历元时刻(SPICE et 秒) - state7: 状态 [x,y,z,vx,vy,vz,m] - thrust_spec: (t_max, isp, throttle, θ₁, θ₂)

# 返回 7D 导数 [vx,vy,vz, ax,ay,az, ṁ]

e2m2e.integrators.batch_body_states_py(target, observer, ets)

批量天体状态查询:target 相对 observer 在 J2000 下的 6 维状态。

对齐 SPICEManager.get_body_state(target, et, "J2000", observer) 的 逐点循环(ELFO 月心根数提取等场景)。返回行优先 (n, 6) 展平。

e2m2e.integrators.batch_et_to_utc_py(et)

批量 ET → UTC 日历分量(年/月/日/时/分/秒)。

对齐 SPICEManager.et_to_utc``("ISOC" 格式、0 位小数秒)的逐点循环, 直接返回六分量数组,免去 Python ``datetime.fromisoformat 字符串解析。 秒为浮点(ISOC prec=0 下为整数秒)。

e2m2e.integrators.batch_j2000_to_synodic_py(states_j2000, t_syn, et0, mu, t_c)

批量 J2000(km, km/s)→ synodic(无量纲)状态转换。

语义对齐 SynodicJ2000System.j2000_to_synodic``(逐点): ``pos_syn = Rᵀ @ r_j2000 / l_c - [μ,0,0]vel_syn = (Rᵀ @ (v_j2000 - Rdot @ (Rᵀ @ r_j2000)))·t_c / l_c

e2m2e.integrators.batch_synodic_to_j2000_py(states_syn, t_syn, et0, mu, t_c)

批量 synodic(无量纲)→ J2000(km, km/s)状态转换。

语义对齐 SynodicJ2000System.synodic_to_j2000``(逐点): ``et = et0 + t_syn·t_cpos = R @ ((r_syn + [μ,0,0])·l_c)vel = R @ (v_syn·l_c/t_c) + Rdot @ ((r_syn + [μ,0,0])·l_c)

e2m2e.integrators.build_cr3bp_hamiltonian_py(mu, gamma, rho_e_ratio, max_degree)

CR3BP Hamiltonian 构造(Jorba-Masdemont c_n·ρⁿ·P_n(x/ρ) 形式)。

H = ½‖p‖² + y·p_x x·p_y Σ_{n≥2} c_n·ρⁿ·P_n(x/ρ) (地心会合系、 平动点偏移坐标),c_n = (-1)ⁿ/γ³·[μ + (1−μ)·rho_e_ratioⁿ⁺¹] (JM 1999 式 1)。Q_n = ρⁿ·P_n(x/ρ) 用递推 Q_n = ((2n−1)/n)·x·Q_{n−1} ((n−1)/n)·ρ²·Q_{n−2} 展开为 (x, y, z) 的多项式(纯数值,不依赖 sympy)。

参数

  • mu: 质量比 μ。

  • gamma: 共线平动点的 γ。

  • rho_e_ratio: γ/(1+γ) (L2 的 JM 展开比)。

  • max_degree: 截断阶数(≥2)。

返回

(pows, coefs)(K, 6) 幂次(后 3 位动量为 0)与 (K,) 系数。动能与科里奥利项(½‖p‖²y·p_x x·p_y )已包含。

e2m2e.integrators.center_manifold_reduce_py(tlist, lam, wp, wv, max_order, steps, higher_pows, higher_coefs)

中心流形化简完整 reduce。

参数

  • tlist: 等距时间采样。

  • lam, wp, wv: 双曲指数与平面/垂直中心频率(来自 QF 的 D)。

  • max_order: 截断阶。

  • steps: "invariant" / "center" 序列。

  • higher_pows: 高阶项幂次 (K, 6)

  • higher_coefs: 高阶项实系数时间序列 (K, N)(K, 1)

返回

(w_entries, h_pows, h_coefs, pre_coupling, steps_done): - w_entries: (step, order, pow[6], re[N], im[N]) 列表; - h_pows / h_coefs: 化简后实 Hamiltonian; - pre_coupling: 化简前双曲-中心耦合度量; - steps_done: 实际执行步骤。

e2m2e.integrators.check_collision_py(traj_states, mu, collision_earth_radius, collision_moon_radius)

转移搜索几何核:碰撞检测。

移植自 search_geometry.check_collision 。earth 中心 [-mu,0,0] 、moon 中心 [1-mu,0,0] ;earth 优先(首个命中即返回),无 earth 再扫 moon,比较为严格 < 。 返回 (collision, body|None, idx) ,body 为 "earth"/"moon"

e2m2e.integrators.cm_to_qf_py(x_cm, w_series, rtol=None, atol=None)

中心流形 → quasi-Floquet(高阶 Lie 级数反向)。

e2m2e.integrators.collinear_center_modes_py(mu, collinear_point)

返回共线点和线性中心模态参数 (x_l, omega_xy, omega_z, y_ratio)

class e2m2e.integrators.CowellResult

基类:object

单步 Cowell (Störmer-Cowell) 的结果。x_new 仅含位置; 历史缓冲混合位置与加速度采样(见 cowell_step )。

error
h_next
history
x_new
e2m2e.integrators.cowell_step(t, h, tol, accel, history)[源代码]

x'' = a(t, x) 执行单个 Cowell(Störmer-Cowell)8 阶步。

history = [x_{n-1}, x_n, a_{n-7}, ..., a_n] (10 个向量:2 个位置 样本与 8 个加速度样本,按从旧到新排列)。accel(t, x) 返回只依赖位置的 加速度(引力、J2)。输出仅含位置,步长固定。

返回的 CowellResult 包含 x_newerrorh_nexthistory

参数:
e2m2e.integrators.compute_distance_series_py(traj_states, orbit_states)

转移搜索几何核:轨迹每步到目标轨道采样点集合的最近距离与索引。

移植自 search_geometry.compute_distance_series (纯数学,非 SPICE 门控)。 traj_states/orbit_states 为 n×6 行优先展平,只用前 3 维位置;n_traj×n_orbit 超过 1e7 时内部分块(与 numpy 同阈值)。argmin 取首个(numpy 约定)。

# 返回 (d_per_step, orbit_idx_per_step) :两个长度 n_traj 的 list。

e2m2e.integrators.compute_min_distance_py(traj_states, orbit_states)

转移搜索几何核:全局最近点(min_dist, step_idx, orbit_idx)。

移植自 search_geometry.compute_min_distancestep_idx 为 d_per_step 的 首个最小值索引,orbit_idx = orbit_idx_per_step[step_idx]

e2m2e.integrators.differential_correction_cr3bp_py(*args, **kwargs)[源代码]

调用 Rust CR3BP 微分修正,并返回规范化字典。

参数:
返回类型:

dict[str, Any]

e2m2e.integrators.generate_cr3bp_family_py(family_type, mu, characteristic_length_km, secondary_radius_km, point, n_orbits, max_amplitude_km=None, min_amplitude_km=None, perilune_height_max_km=None, north_south=None, amplitude_in_km=None, amplitude_out_km=None, phase_in=None, phase_out=None, continuation_direction=None, match_tolerance_km=None, n_periods=3, rtol=1e-12, atol=1e-12, max_step=None)
e2m2e.integrators.generate_cr3bp_family_windows_py(family_type, mu, characteristic_length_km, secondary_radius_km, point, n_orbits, jacobi_windows, max_amplitude_km=None, min_amplitude_km=None, perilune_height_max_km=None, north_south=None, amplitude_in_km=None, amplitude_out_km=None, phase_in=None, phase_out=None, continuation_direction=None, match_tolerance_km=None, n_periods=3, rtol=1e-12, atol=1e-12, max_step=None)

按 Jacobi 能量窗口批量生成轨道族:同一组生成参数下延拓 trace 只走 一次,返回与 jacobi_windows 同序的结果列表(每窗口一条,成员 Jacobi 均落在窗口内,边界包含)。窗口成员超上限时按 trace 顺序取 前 n_orbits 条(与一维扫描的成员上限语义一致)。窗口零成员时 该窗口结果为零成员的结构化软失败;族生成参数与 generate_cr3bp_family_py 同集(走能量窗口时族延拓范围取各族 默认振幅/近月点上限,由调用方给定)。

e2m2e.integrators.detect_intersection_py(traj_states, orbit_states, threshold)

转移搜索几何核:相交检测。

移植自 search_geometry.detect_intersection 。全局最近点距离 < threshold 时返回该点完整 6 维状态。返回 (found, point|None, step_idx) ,比较为严格 <

e2m2e.integrators.detect_local_minimum_py(traj_states, orbit_states)

转移搜索几何核:局部极小检测。

移植自 search_geometry.detect_local_minimum 。在每步最近距离序列上找严格 局部极小(两侧严格大于),取所有极小中值最小者(首个并列)。返回 (found, dist, idx) ;无极小 (false, inf, -1)

e2m2e.integrators.disable_ephem_cache()

关闭 Rust 星历缓存(回到逐次 cspice 查询)。

e2m2e.integrators.enable_ephem_cache(targets, frame_pairs, et_start, et_end, dt=3600.0, *, sxform_pairs=None)

激活 Rust 星历预采样缓存。

在积分前把要用到的天体状态与帧旋转矩阵在均匀网格上预采样、建三次样条, 装入进程级缓存。此后 Rust 力模型(ThirdBody/IndirectTerm/GravityField/Relativistic) 每步查表,不再调 cspice FFI。需在 SPICE 内核已加载后调用。

参数

  • targets: 要缓存的天体对 [(target, observer), ...] ,如 [("MOON", "EARTH"), ("SUN", "EARTH"), ("EARTH", "SOLAR SYSTEM BARYCENTER")]

  • frame_pairs: 要缓存的帧旋转对 [(from, to), ...] ,如 [("ITRF93", "J2000"), ("MOON_PA", "J2000")]

  • sxform_pairs: 要缓存的 6×6 状态变换对 [(from, to), ...] ,如 [("ITRF93", "J2000")] (Lense-Thirring 用)。关键字参数,默认 None

  • et_start, et_end: 积分时间范围(SPICE et 秒)

  • dt: 网格步长(秒),默认 3600

e2m2e.integrators.ephem_ffi_call_count()

返回 cspice FFI 调用计数(验证"零 cspice"用)。

e2m2e.integrators.grid_search_rust(dep_states, dep_times, alpha_grid, arrival_states, *, mu, max_transfer_time, integration_dt, intersection_threshold, min_distance_threshold, collision_earth_radius, collision_moon_radius, rtol, atol, max_step, parallel=None, n_workers=None, progress_callback=None)[源代码]

转移网格搜索 Rust 后端(阶段 C,Rayon 并行 + GIL 释放)。

展平 POD 输入 → 调 transfer_grid_search_pypy.allow_threads 释放 GIL + Rayon par_iter 真并行)→ 转 list[dict]。返回字段与 顺序与 grid_search_rust_serial() 完全一致——并行与串行逐位相同 (par_iter``+``collect 保序、evaluate_point 纯函数)。 其余参数同 grid_search_rust_serial()

参数:
  • parallel (bool | None) -- None (默认)时由 E2M2E_SEARCH_PARALLEL 环境变量决定 ("0"``→串行,其余/未设→并行);显式 ``True/False 覆盖。 串/并一致性对照用 parallel=Falseparallel=True 各跑一遍。

  • n_workers (int | None) -- None (默认)时用 Rayon 全局线程池,线程数由 RAYON_NUM_THREADS 决定(未设则 cpu 核数);显式传入时 Rust 端 建一次性 ThreadPoolBuilder 限定 max(n_workers, 1) 个线程并 install 本次 compute,覆盖 RAYON_NUM_THREADS。串行模式 (parallel=False)下无线程池,此参数被忽略。

  • progress_callback (Callable[[int], Any] | None) -- cb(delta: int) -> None,每个 departure 完成 调一次(出发粒度);None 不回调。Rust 端走 channel + drainer 线程,释放 GIL 后实时回调。

  • dep_states (ArrayLike)

  • dep_times (ArrayLike)

  • alpha_grid (ArrayLike)

  • arrival_states (ArrayLike)

  • mu (float)

  • max_transfer_time (float)

  • integration_dt (float)

  • intersection_threshold (float)

  • min_distance_threshold (float)

  • collision_earth_radius (float)

  • collision_moon_radius (float)

  • rtol (float)

  • atol (float)

  • max_step (float)

返回:

list[dict],长度 n_dep * n_alpha,顺序为外层 departure、内层 alpha。

返回类型:

list[dict[str, Any]]

e2m2e.integrators.grid_search_rust_serial(dep_states, dep_times, alpha_grid, arrival_states, *, mu, max_transfer_time, integration_dt, intersection_threshold, min_distance_threshold, collision_earth_radius, collision_moon_radius, rtol, atol, max_step, progress_callback=None)[源代码]

转移网格搜索 Rust 串行后端(阶段 B)。

展平 POD 输入 → 调 transfer_grid_search_serial_py → 转 list[dict]。 返回字段对齐 search_parallel.grid_search_sequential,便于逐候选等价 对照(整数索引精确相等、浮点 allclose)。

本 wrapper 只做数组→dict 转换,不依赖 transfer 算法层(分层:算法层调 数值层合法,数值层不反向依赖)。出发轨道采样(sample_departure_points) 与 Orbit 展平由调用方完成;阶段 D 的 grid_search_rust 编排器会在此之上 接入 TransferSearch

参数:
  • dep_states (ArrayLike) -- (n_dep, 6) 或展平 n_dep*6 出发状态。

  • dep_times (ArrayLike) -- (n_dep,) 出发时刻。

  • alpha_grid (ArrayLike) -- (n_alpha,) 切向速度比 α 网格。

  • arrival_states (ArrayLike) -- (n_arrival, 6) 或展平目标轨道状态。

  • / (mu / max_transfer_time / integration_dt / intersection_threshold) -- min_distance_threshold / collision_earth_radius / collision_moon_radius: CR3BP 与搜索标量配置。

  • max_step (float) -- 积分器容差与最大步长。

  • progress_callback (Callable[[int], Any] | None) -- cb(delta: int) -> None,每个 departure 完成 调一次(出发粒度);None 不回调。Rust 端走 channel + drainer 线程,释放 GIL 后实时回调。

  • mu (float)

  • max_transfer_time (float)

  • integration_dt (float)

  • intersection_threshold (float)

  • min_distance_threshold (float)

  • collision_earth_radius (float)

  • collision_moon_radius (float)

  • rtol (float)

  • atol (float)

  • max_step

返回:

list[dict],长度 n_dep * n_alpha,顺序为外层 departure、 内层 alpha(与 grid_search_sequential 一致)。

返回类型:

list[dict[str, Any]]

e2m2e.integrators.hello_integrators()

占位函数,用于验证 FFI 路径端到端通畅。

e2m2e.integrators.indirect_term_acceleration(et, target, observer, mu)

第三体间接项加速度:a = -μ · r_ob / |r_ob|³

移植自 Python IndirectTerm.compute_acceleration

e2m2e.integrators.initialize_abm_history(t0, y0, h, f, n_stages=3, tol=1e-12)[源代码]

n_stages 个 RK89 步启动 ABM history。

ABM 方法使用 4 个导数样本;默认 n_stages=3 时返回 (t0 + 3h, y(3h), [f_0, f_1, f_2, f_3]),其中 history 可直接传给 multistep_step()

参数:
返回类型:

tuple[float, ndarray, list[list[float]]]

e2m2e.integrators.initialize_cowell_history(t0, x0, v0, h, accel, n_startup=7, tol=1e-12)[源代码]

n_startup 个 RK89 步启动 8 阶 Cowell history。

返回 (t, x, v, history),其中 history = [x_{n-1}, x_n, a_{n-7}, ..., a_n] (2 个位置与 8 个加速度, 可直接传给 cowell_step())。n_startup 须不小于 7,以获得最近的 8 个加速度样本;默认 n_startup=7 时状态推进至 t0 + 7h

参数:
返回类型:

tuple[float, ndarray, ndarray, list[list[float]]]

e2m2e.integrators.keys_by_order_py(pows)

按总阶数分组返回幂次键(每组内排序)。

e2m2e.integrators.lambert_batch_py(geometries, tofs, mu, long_way, revs)

N×M 网格批量 Lambert 求解(porkchop 用)的 Python 接口。

# 参数 - geometries :几何列表,每项 [r0x, r0y, r0z, rfx, rfy, rfz] (km) - tofs :飞行时间列表(s),对每个几何都求解一遍 - mu/long_way/revs :同 lambert_izzo_py

# 返回 长度 len(geometries) * len(tofs) 的 list(几何在外,tof 在内), 每项为 dict 或 None(该组合无解)。

e2m2e.integrators.lambert_izzo_py(r0, rf, tof, mu, long_way, revs)

二体 Lambert 求解(Izzo 算法)的 Python 接口。

# 参数 - r0/rf :出发/到达位置 [x, y, z](km) - tof :飞行时间(s) - mu :中心天体 GM(km³/s²) - long_way :True 取长程解(转移角 > π) - revs :完整圈数(≥ 1 时返回右分支低能解)

# 返回 Python dict:{"v0": [3], "vf": [3], "n_iter": int} ;无解/不收敛抛 ValueError。

e2m2e.integrators.low_energy_patch_rust(states_a, states_b, weights, *, parallel=None, n_workers=None, progress_callback=None)[源代码]

低能转移流形截面态配对的 Rust 后端。

输入为两组 (n, 6) 截面态,Rust 完成全部配对、位置/速度范数、 加权代价和稳定排序。parallel=None 时由 E2M2E_LOW_ENERGY_PARALLEL 决定是否使用 Rayon;显式 n_workers 为本次调用建立一次性线程池。

参数:
返回类型:

list[dict[str, Any]]

e2m2e.integrators.lowthrust_collocation_defects_py(states, controls, t0, tf, observer, forces_py, t_max, isp)

Hermite-Simpson 配点缺陷的批量求值。

e2m2e.integrators.lowthrust_shooting_evaluate_py(controls, t0, tf, initial_state, observer, forces_py, t_max, isp, with_jacobian)

多段低推力打靶评估:接龙传播,并按需组装末端控制灵敏度。

e2m2e.integrators.lissajous_bounded_trajectory_py(mu, collinear_point, char_length_km, amplitude_in_km, amplitude_out_km, phase_in, phase_out, n_periods=3, points_per_period=60)

Rust Lissajous 线性中心流多点轨迹。

面内与面外中心模态分别按独立频率解析推进;不把状态重新送入含双曲方向的 完整 CR3BP,因此轨迹按构造保持有界。该结果是参数采样轨迹,不宣称周期闭合。

e2m2e.integrators.manifold_propagate_py(mu, seeds, kind, t_span, sample_dt, rtol, atol, max_step=None, *, n_workers=None, parallel=None)

Python 接口:不变流形批量弧传播。

输入展平种子 n*6kind 决定积分方向;单弧失败跳过。n_workers>1 或环境变量 E2M2E_MANIFOLD_PARALLEL!=0 时走 Rayon。

e2m2e.integrators.manifold_seeds_py(mu, initial_state, period, kind, branch_sign, epsilon, n_points, rtol, atol, max_step=None)

Python 接口:不变流形种子生成。

相位扫掠(STM)、单值矩阵双曲实特征选取、转运归一化与 ±ε 扰动均在 Rust 完成;全程 py.allow_threads ,无 Python 数值回退。

class e2m2e.integrators.MultistepMethod

基类:object

显式多步方法。与 RkMethod 分开,因为多步方法携带历史缓冲, 不能共享无状态的单步入口。启用 pyo3 feature 时暴露给 Python。

ABM = MultistepMethod.ABM
class e2m2e.integrators.MultistepResult

基类:object

单步多步的结果。携带滚动后的历史缓冲,供 Python 传播循环传入下一步调用。

error
h_next
history
y_new
e2m2e.integrators.multistep_step(method, t, y, h, tol, f, history)[源代码]

执行单个多步预测-校正步。

history 须按从旧到新的顺序保存 method.steps() 个导数样本,每个样本 与 y 等长,间隔均为 h。回调 f 的签名与 rk_step() 相同。 返回 MultistepResult,其 history 是供下一步使用的滚动缓冲区。

假定步长固定;改变 h 后须重新初始化 history(见 initialize_abm_history())。

参数:
e2m2e.integrators.multiple_shooting_correct_py(*args, **kwargs)[源代码]

调用 Rust 多重打靶,并立即校验最终状态三元组。

参数:
返回类型:

_ShootingResult

e2m2e.integrators.nsga2_environmental_selection_py(rank, crowd, n_keep)

(rank, -crowding) 进行环境选择。

e2m2e.integrators.nsga2_sort_py(fit, viol)

Deb 可行支配规则的非支配排序与拥挤度距离。

e2m2e.integrators.nsga2_tournament_selection_py(rank, crowd, draws)

使用 Python 已按原顺序产生的随机索引执行二元锦标赛。

e2m2e.integrators.nsga2_variation_py(parents, lo, hi, crossover_prob, eta_c, mutation_prob, eta_m, crossover_draws, gene_draws, beta_draws, swap_draws, mutation_draws, mutation_value_draws)

执行 SBX 交叉与多项式变异。

随机抽样由 Python 按既有条件分支顺序准备;未使用的位置允许为 NaN。

e2m2e.integrators.orbit_family_metric_py(mu, metric, point, initial_state, period, rtol=1e-12, atol=1e-12, max_step=None, sample_count=1000)

传播周期轨道并在 Rust 内测量族几何量。

metric 可取 moon-distance、l45-distance 或 z-amplitude;返回对应 绝对距离或振幅的 (minimum, maximum)(无量纲)。

e2m2e.integrators.pal_f_df_tangent_py(mu, x, sv0, rtol, atol, max_step)

PAL 延拓:XZ 平面对称约束的 F/dF/切向量单次计算(#443)。

对应 Python continuation.compute_F_and_dF_symmetric_xz_plane + compute_tangent_vector (纯数值,非 SPICE 门控)。供延拓收敛轨道后的 切向量刷新;初始切向量两后端统一走 Python 参照计算(零空间符号约定 在 SVD 与广义叉积间无保证,首步方向由 Python 侧锁定)。

# 返回 Python dict:{"f": [3], "df": [[4], [4], [4]], "tangent": [4], "final_state": [6]}

e2m2e.integrators.pal_newton_step_py(mu, x_start, x_ref, sv0, tangent_ref, ds, tol, iter_max, rtol, atol, max_step)

PAL 延拓:单步牛顿迭代(#443)。

对应 Python pseudo_arclength_continuation 的内层牛顿循环:从预测点 x_start 出发解 G = [F; (Xnew - x_ref)·tangent_ref - ds] = 0 ,先判 收敛再更新,牛顿步按 [0.04, 0.12, 0.12, 0.08] 分量裁剪。无论收敛与否 都返回当前 x_new (对应 Python 循环 break/耗尽后继续用最后值)。

# 返回 Python dict:{"x_new": [4], "tangent": [4], "iterations": int, "residual": float, "converged": bool, "singular": bool}

e2m2e.integrators.planar_full_period_pal_py(*args, **kwargs)[源代码]

调用 Rust 平面全周期 PAL,并立即校验最终状态三元组。

参数:
返回类型:

_ShootingResult

e2m2e.integrators.pole_tide(et, xp, yp)

极潮(固体极潮 + 海洋极潮,IERS TN32)。返回长度 50 的 Vec<f64> (C25 + S25)。

e2m2e.integrators.poly_poisson_py(pows1, coefs1_flat, pows2, coefs2_flat, series_len)

6-DOF 辛 Poisson 括号 {poly1, poly2} (标量或时间序列、实/复)。

系数编码:coefs_flatn * series_len * 2 的交错 (re, im)series_len=1 表示标量。

e2m2e.integrators.poly_simplify_py(pows, coefs_flat, series_len, eps)

标量系数 simplify:合并同幂次,剔除模长 ≤ eps 的项(|coef| eps)。

与 Python poly_simplify 数值路径一致;series_len 通常为 1, 但接口允许序列(按任一分量模阈值,同 _is_zero )。

e2m2e.integrators.polylist_simplify_py(pows, coefs_flat, series_len, eps)

时间序列 simplify:合并同幂次,剔除 mean(|coef|) eps 的项。

与 Python polylist_simplify 一致。

e2m2e.integrators.porkchop_grid_py(t_dep, tof, dep_kind, dep_state, dep_t0, dep_period, arr_kind, arr_state, arr_t0, arr_period, mu_cr3bp, rtol, atol, max_step, mu_central, long_way, revs, *, parallel=None)

porkchop 网格扫描 Rust 后端(规格路径,#446):终端传播 + Lambert + ΔV 组装。

照搬 transfer_grid_search_pypy.allow_threads + Rayon + 环境变量 开关范式(对称 E2M2E_SEARCH_PARALLEL ):默认并行,parallel=FalseE2M2E_PORKCHOP_PARALLEL=0 强制串行,两者逐位一致。

参数

  • t_dep / tof :出发时刻与飞行时间网格。

  • dep_kind / arr_kind"orbit" (周期轨道终端:*_state 为首点 状态、*_t0 时间原点、*_period 周期)或 "state" (固定状态终端, 仅 *_state 有意义)。

  • mu_cr3bp / rtol / atol / max_step :CR3BP 质量参数与终端 传播积分器配置;两端均为 "state" 时均传 None (无需传播)。

  • mu_central / long_way / revs :Lambert 求解配置。

返回

(dv1, dv2) 展平列表,长度 len(t_dep) * len(tof) ,行优先(t_dep 主序); 无解组合为 NaN。

e2m2e.integrators.porkchop_grid_states_py(dep_states, arr_states, tof, mu_central, long_way, revs, *, parallel=None)

porkchop 网格扫描 Rust 后端(状态网格路径,#446):终端状态已由 Python 按 get_arrival_state 协议预提取,本入口只做 Lambert + ΔV 组装。

参数

  • dep_states :展平 n*6dep_states[i*6..]t_dep[i] 时刻出发状态。

  • arr_states :展平 n*m*6 ,行优先(t_dep 主序),arr_states[(i*m+j)*6..]t_dep[i] + tof[j] 时刻到达状态。

  • tof / mu_central / long_way / revs / parallel :同 porkchop_grid_py

返回porkchop_grid_py

e2m2e.integrators.project_hamiltonian_qf_py(pows, coefs, b_seq)

H→QF 投影:X = B·Y 单项式替换展开(对应 qiao Code09 )。

参数:
  • pows -- (N_in, 6) 输入单项式的幂次(平动点偏移坐标)。

  • coefs -- (N_in,) 输入单项式的标量系数(CR3BP 自治,常数)。

  • b_seq -- (M, 36) 每个采样时刻的 6×6 变换矩阵 B(t) 展平。

返回:

(out_pows, out_coefs)out_pows(K, 6) 展开后幂次 并集(排序),out_coefs(M, K) 逐时刻系数矩阵。

e2m2e.integrators.qf_to_cm_py(x_qf, w_series, rtol=None, atol=None)

quasi-Floquet → 中心流形(高阶 Lie 级数,12 实维 DOP853)。

参数:
  • x_qf -- 长度 6 的实 QF 状态

  • w_series -- [(order, exps, coefs_re, coefs_im), ...]

  • atol (rtol /) -- ODE 容差(默认与 Python 一致 1e-11 / 1e-13)

e2m2e.integrators.qlaw_propagate_py(t0, tf, y0, target_oe, mu, t_max, isp, h_init, tol, max_steps)

Q-law 低推力反馈积分(完整热路径在 Rust,#442)。

e2m2e.integrators.qlaw_segment_direction_py(state7, target_oe, mu, t_max)

Q-law 段中点评估:Q 值、开普勒根数和惯性系推力方向。

e2m2e.integrators.trim_degree_py(pows, coefs_flat, series_len, max_degree)

截断总阶数大于 max_degree 的项;空结果退回零多项式。

e2m2e.integrators.propagate_compiled(method, t0, y0, h_init, tol, t_eval, observer, forces_py, max_steps)

全 Rust 力模型传播器(消除 Python↔Rust 跨界)。

Python 侧把所有 force 序列化为元组列表,Rust 在内部循环里直接调 compute_total_acceleration ,每个 RK 子阶段不再跨界回 Python。

# 参数 - method: RkMethod - t0/y0: 初始时刻与状态 - h_init: 初始步长 - tol: 容差 - t_eval: 评估时刻数组 - observer: 传播系 origin(如 "EARTH") - forces_py: force 元组列表 - max_steps: 最大步数

# 返回 Python dict:{"time": [...], "states": [[...]], "n_steps": int, "n_rejected": int}

e2m2e.integrators.propagate_compiled_lowthrust(method, t0, y0, h_init, tol, t_eval, observer, forces_py, thrust_spec, max_steps)

7D 可变质量低推力传播:状态 [x, y, z, vx, vy, vz, m]

受控动力学复用 e2m2e-forcesaugmented_eom_7d :重力走 compute_total_acceleration ,推力与质量流走 ThrustParams 。控制律为 常量 throttle 与常量方向(与 ThrustParams 的常量语义对齐);时变控制 留待求解器期次。

# 参数 - method: RK 方法 - t0: 起始时刻(SPICE et 秒) - y0: 初始状态,长度 7 - h_init: 初始步长 - tol: 步长误差容差 - t_eval: 评估时刻数组 - observer: 传播系 origin(如 "EARTH") - forces_py: 非推力 force 元组列表(格式同 propagate_compiled ) - thrust_spec: (t_max, isp, throttle, dir_x, dir_y, dir_z) - max_steps: 最大步数

# 返回 Python dict:{"time": [...], "states": [[7], ...], "n_steps": int, "n_rejected": int}

e2m2e.integrators.propagate_compiled_lowthrust_sensitivity(method, t0, y0, h_init, tol, t_eval, observer, forces_py, thrust_spec, max_steps)

7D 可变质量低推力 + 灵敏度传播(64D 增广状态)。

propagate_compiled_lowthrust (7D 受控)基础上,同时积分: - Φ(6×6 状态对初值 STM,链式接龙用) - S(7×3 状态对控制参数 (throttle, θ₁, θ₂) 的灵敏度)

一次传播同时产出末端状态、STM、灵敏度,供低推力求解器组装解析雅可比 (替代 SLSQP 数值差分)。详见 docs/plans/lowthrust-analytic-jacobian-prd.md

参数

  • method: RK 方法

  • t0: 起始时刻(SPICE et 秒)

  • y0: 初始状态,长度 7

  • h_init, tol: 步长控制

  • t_eval: 评估时刻数组(取首末两点即可)

  • observer: 传播系 origin

  • forces_py: 非推力 force 元组列表

  • thrust_spec: (t_max, isp, throttle, θ₁, θ₂)

  • max_steps: 最大步数

返回

Python dict:{"time": [...], "states": [[7]], "stm": [[36]], "sensitivity": [[21]], "n_steps": int, "n_rejected": int} (均为末端时刻的值序列)

e2m2e.integrators.propagate_compiled_stm_py(observer, forces_py, t_span, t_eval, initial_state, rtol, atol, max_step=None, max_steps=None, method=Ellipsis)

编译型力模型 + STM 的 PD45 传播(消除 cspice 隔离)。

propagate_with_stm_py (纯 NBody)不同,本函数支持所有编译型力模型: PointMass、GravityField、ThirdBody、IndirectTerm、SRP、Relativistic。 使用 integrators crate 的 cspice 实例,避免跨 .so 内核池隔离问题。

参数

  • observer: 传播系 origin 天体名(如 "EARTH")

  • forces_py: force 元组列表(格式同 propagate_compiled

  • t_span: (t_start, t_end) 积分区间(SPICE et 秒)

  • t_eval: 输出时间点数组

  • initial_state: 初始状态 [x, y, z, vx, vy, vz] (km, km/s)

  • rtol, atol: 积分容差

  • max_step: 最大步长(秒),None 则不限制

  • max_steps: 最大步数,None 则用默认上限

返回

Python dict:{"states": [[6], ...], "stm": [[36], ...], "time": [...], "n_steps": int, "n_rejected": int}

e2m2e.integrators.propagate_bcr4bp_py(mu, mu_sun, sun_distance, sun_angular_rate, sun_phase0, t_span, t_eval, initial_state, rtol, atol, max_step=None, max_steps=None)

Python 接口:BCR4BP 6 维纯状态传播(PD78)。

纯数学(无量纲),不依赖 SPICE。在 CR3BP 之上叠加太阳质点摄动,太阳 位置由解析公式 r_s(t) = a_s·(cos θ, sin θ, 0)θ = θ0 + ω_s·t 给出。 循环结构与 propagate_cr3bp_py 一致;RK callback 把当前步时间传入 EOM (BCR4BP 显式含时)。供 BCR4BP_Dynamics 透明走 Rust。

# 参数 - mu: 地月质量参数 μ = m₂/(m₁+m₂) - mu_sun: 太阳无量纲质量 m_s = GM_sun / GM_EMB - sun_distance: 太阳圆周轨道半径 a_s(无量纲) - sun_angular_rate: 太阳会合系角速度 ω_s(无量纲,负值表示逆行) - sun_phase0: t = 0 时刻的太阳相位角 θ0(弧度) - t_span: (t_start, t_end) 积分区间(无量纲时间) - t_eval: 输出时间点数组 - initial_state: 初始状态 [x, y, z, vx, vy, vz] - rtol, atol: 积分容差 - max_step: 最大步长,None 则不限制 - max_steps: 最大步数,None 则用默认上限

# 返回 Python dict:{"time": [...], "states": [[6], ...], "n_steps": int, "n_rejected": int}

e2m2e.integrators.propagate_bcr4bp_stm_py(mu, mu_sun, sun_distance, sun_angular_rate, sun_phase0, t_span, t_eval, initial_state, rtol, atol, max_step=None, max_steps=None)

Python 接口:BCR4BP 42 维增广状态传播(状态 + STM,PD78)。

纯数学(无量纲),不依赖 SPICE。初始 STM 设为单位矩阵;步长误差控制只 统计前 6 维,避免 STM 分量主导步长。参数同 propagate_bcr4bp_py

# 返回 Python dict:{"states": [[6], ...], "stm": [[36], ...], "time": [...], "n_steps": int, "n_rejected": int}stm[k][i*6+j] = ∂state(t_k)[i]/∂state(t0)[j]

e2m2e.integrators.propagate_cr3bp_py(mu, t_span, t_eval, initial_state, rtol, atol, max_step=None, max_steps=None)

Python 接口:CR3BP 6 维纯状态传播(PD78)。

纯数学(无量纲),不依赖 SPICE。供 CR3BP_Dynamics 透明走 Rust。 循环结构与 propagate_compiled_stm 一致,保证与带 STM 路径的 states 逐位相同。

# 参数 - mu: 质量参数 μ = m₂/(m₁+m₂) - t_span: (t_start, t_end) 积分区间(无量纲时间) - t_eval: 输出时间点数组 - initial_state: 初始状态 [x, y, z, vx, vy, vz] - rtol, atol: 积分容差 - max_step: 最大步长,None 则不限制 - max_steps: 最大步数,None 则用默认上限

# 返回 Python dict:{"time": [...], "states": [[6], ...], "n_steps": int, "n_rejected": int}

e2m2e.integrators.propagate_cr3bp_stm_py(mu, t_span, t_eval, initial_state, rtol, atol, max_step=None, max_steps=None)

Python 接口:CR3BP 42 维增广状态传播(状态 + STM,PD78)。

纯数学(无量纲),不依赖 SPICE。初始 STM 设为单位矩阵;步长误差控制只 统计前 6 维,避免 STM 分量主导步长。

# 参数 同 propagate_cr3bp_py

# 返回 Python dict:{"states": [[6], ...], "stm": [[36], ...], "time": [...], "n_steps": int, "n_rejected": int}stm[k][i*6+j] = ∂state(t_k)[i]/∂state(t0)[j]

e2m2e.integrators.propagate_segments_py(observer, forces, seg_t0, seg_t1, seg_states, t_eval_list, rtol, max_steps=500000, method=Ellipsis)

多段并发积分(segmented 逐段积分填 et_grid 用,issue #400 性能下沉)。

每段从 seg_states[i] 积分到 seg_t1[i] ,输出 t_eval_list[i] 逐点对应的状态序列(不追加段终点,语义同 propagate_compiled_core )。 段间独立(只依赖本段输入),rayon 并发;并行前提与多重打靶段积分相同 (strict + 预采样星历缓存,零 cspice FFI)。rayon 保序 collect + 各段 积分确定 → 并行与串行位级一致(E2M2E_MS_PARALLEL=0 强制串行)。

初值步长上限复刻 Python ForceModel._estimate_initial_step (2πr/v/100), 与 fm.propagate 路径的步长控制语义一致。

e2m2e.integrators.propagate_with_state_py(bodies, origin, gm_values, t_span, t_eval, initial_state, rtol, atol, max_step=None, max_steps=None)

Python 接口:6 维纯状态传播(不含 STM)。

纯 N 体模型,与 propagate_with_stm_py 同用 solve_ivp_capped ,保证 两条路径的 states 前 6 维逐位相等(parity)。供 EphemerisDynamics 的纯状态路径(with_stm=False )透明走 Rust,省去 42 维 STM 的开销。

# 参数 同 propagate_with_stm_py ,但不返回 STM。

# 返回 Python dict:{"states": [[6], ...], "time": [...]}

e2m2e.integrators.propagate_with_stm_py(bodies, origin, gm_values, t_span, t_eval, initial_state, rtol, atol, max_step=None, max_steps=None)

Python 接口:42 维增广状态传播(状态 + STM)。

纯 N 体模型(EARTH/MOON/SUN 等),用于星历修正的逐段积分。 调用 e2m2e-forcespropagate_with_stm (DOP853 + STM 变分方程)。

参数

  • bodies: 天体名称列表(如 ["EARTH", "MOON", "SUN"]

  • origin: 原点天体名称(如 "EARTH"

  • gm_values: 各天体的 GM(km³/s²),与 bodies 一一对应

  • t_span: (t_start, t_end) 积分区间(SPICE et 秒)

  • t_eval: 输出时间点数组

  • initial_state: 初始状态 [x, y, z, vx, vy, vz] (km, km/s)

  • rtol, atol: 积分容差

  • max_step: 最大步长(秒),None 则不限制

  • max_steps: 最大步数,None 则用默认上限

返回

Python dict:{"states": [[6], ...], "stm": [[36], ...], "time": [...]}

e2m2e.integrators.reset_ephem_ffi_call_count()

清零 cspice FFI 调用计数。

e2m2e.integrators.rk_step(method, t, y, h, tol, f, state_error_dim=None)[源代码]

使用 Rust 积分器内核执行单个 Runge-Kutta 步。

回调 f 接收 NumPy ndarray,并须返回同长度数组。返回的 StepResult 包含 y_newerrorh_next

state_error_dim:步长误差控制只统计前 N 维(None 时统计全部)。 STM 增广传播时传 6,让状态转移矩阵的 36 个分量不主导步长控制。

参数:
class e2m2e.integrators.RkMethod

基类:object

单步 Runge-Kutta 方法枚举。启用 pyo3 feature 时暴露给 Python。

每种方法对应一张 Butcher 表(见 [crate::butcher::ButcherTable])。

PD45 = RkMethod.PD45
PD78 = RkMethod.PD78
RK89 = RkMethod.RK89
e2m2e.integrators.require_rust_extension(*required_symbols)[源代码]

确保 Rust 扩展可用且指定的模块级符号存在;否则抛 RustExtensionUnavailableError

在使用 Rust 扩展符号的每个入口调用。扩展未构建、构建不含 spice feature、或符号缺失时,抛带 make dev 指引的 RustExtensionUnavailableError——不允许静默回退到 Python/scipy (issue #378)。required_symbolse2m2e.integrators 模块级 符号名;扩展缺失时符号为 None

示例

>>> require_rust_extension("propagate_compiled", "spice_furnsh")
参数:

required_symbols (str)

返回类型:

None

e2m2e.integrators.segmented_shooting_correct_py(*args, **kwargs)[源代码]

调用 Rust 分段打靶,并立即校验最终状态三元组。

参数:
返回类型:

_ShootingResult

e2m2e.integrators.solid_tide_step1(perturbers_flat, k_love_flat, k_plus_flat, mu_central, r_central)

固体潮 Step 1(频率无关,天体无关)。

Python 侧 earth_tide.solid_tide_step1 的 Rust 加速版。输入扰动体位置由 Python 完成坐标变换后传入(本函数不查 SPICE)。

参数

  • perturbers_flat :扁平化扰动体列表,每 4 个一组 [px, py, pz, gm] (位置 km、 gm km³/s²)。长度必须是 4 的倍数。

  • k_love_flat :Love 数表 5×5 行优先扁平化,长度 25。

  • k_plus_flat :弹性 Love 数 5 元素,或 None (无贡献)。

  • mu_centralr_central :中心天体 GM 与参考半径。

返回

长度 50 的 Vec<f64>C(25) ++ S(25) ,各为 5×5 行优先扁平化。

e2m2e.integrators.solid_tide_step2(et)

固体潮 Step 2(频率相关,地球专用)。返回长度 50 的 Vec<f64> (C25 + S25)。

e2m2e.integrators.solve_ivp_events(t_span, y0, t_eval, rtol, atol, f, events, method=None, max_step=None, max_steps=None, state_error_dim=None)[源代码]

带事件检测的 Rust solve_ivp 封装(scipy 事件语义)。

事件检测在 Rust 积分内循环完成:每个接受步的端点评估事件函数, 符号变化(经 direction 过滤)时在步内对线性插值态二分求精(无稠密输出)。

参数:
  • t_span (tuple[float, float]) -- 积分区间 (t0, tf)

  • y0 (ArrayLike) -- 初始状态向量。

  • t_eval (ArrayLike) -- 输出时间点数组。

  • rtol (float) -- 相对容差。

  • atol (float) -- 绝对容差。

  • f (Callable[[float, ndarray[tuple[Any, ...], dtype[floating]]], ndarray[tuple[Any, ...], dtype[floating]]]) -- ODE 右端函数 f(t, y) -> dy/dt

  • events (list[tuple[Callable[[float, ndarray[tuple[Any, ...], dtype[floating]]], float], bool, float]]) -- [(g, terminal, direction), ...]g(t, y) -> float, 零点即事件面;terminal=True 触发即停;direction > 0 只记 上行穿越(g 由负到正)、< 0 只记下行、0 双向。

  • method (RkMethod | None) -- RK 方法,默认 PD78(DOP853)。

  • max_step (float | None) -- 最大步长。求精精度受步内线性插值误差(~h²/8·|ÿ|)限制, 需要更紧的事件时刻时请设小 max_step。

  • max_steps (int | None) -- 最大积分步数。

  • state_error_dim (int | None) -- 步长误差控制只统计前 N 维(用于 STM 增广传播)。

返回:

dict:states/time (t_eval 前缀,terminal 截断时末点为求精后的 事件点)、t_events/y_events (逐事件的触发时刻与状态列表)、 terminal_event (触发终止的事件索引或 None)、n_steps

返回类型:

dict[str, Any]

e2m2e.integrators.solve_ivp_events_py(t_span, y0, t_eval, rtol, atol, f, events, method=None, max_step=None, max_steps=None, state_error_dim=None)

Python 接口:带事件检测的自适应步长 ODE 积分器。

事件检测在 Rust 积分内循环完成:每个接受步的端点评估事件函数, 符号变化(经 direction 过滤)时在步内对线性插值态二分求精(无稠密输出)。

参数

  • events: [(callable, terminal, direction), ...] ,callable 为 g(t, y) -> floatterminal=True 触发即停;direction > 0 只记 上行穿越、< 0 只记下行、0 双向(scipy solve_ivp 语义)

  • method: RK 方法(默认 Pd78 ,即 DOP853)

  • 其余参数同 solve_ivp_py

返回

Python dict:{"states", "time", "n_steps", "t_events", "y_events", "terminal_event"} ; terminal 截断时 time/states 末点为求精后的事件点, terminal_event 为触发终止的事件索引(未终止为 None)。

e2m2e.integrators.solve_hjb_py(terminal, minimum, maximum, shape, t0, tf, dynamics, params, cfl, max_step)

通用 HJB 求解入口。

dynamics 为动力学标识,当前支持:

  • "planar_double_integrator":平面双积分器,参数 drift_x、drift_y、 max_accel、fuel_weight;

  • "cr3bp_synodic":地月会合系无量纲平面 CR3BP,参数 mu、 max_accel、fuel_weight;

  • "ephemeris_planar"``(需 spice):平面全星历脉动会合系(#498, ADR 0034),参数 mu_earth、mu_moon、mu_sun(km³/s²)、et0(求解器 t=0 对应的 SPICE et)、thrust(N)、isp(s)、g0(m/s²)、fuel_weight、 mass_mode(0 = 4 维固定质量,需 fixed_mass;1 = 5 维含质量轴, 单位 kg)。求解器 t 单位为秒;调用前须 ``enable_ephem_cache 覆盖 [et0+t0, et0+tf],求解阶段零 cspice。

terminal 为终端代价 ψ 的扁平数组(C 序,长度等于网格节点数)。 返回字典:times 升序时刻、values 逐快照拼接的值函数 (C 序,形状 (len(times), ×shape))、axes 各维节点坐标、 steps 实际积分步数。快照按时间近似等距抽样,数量有上界, 高维网格不会返回完整时间序列。

值函数产物落盘时,调用方须按 ADR 0033 决策 3 补足元数据:动力学 标识与参数表、状态维顺序、无量纲化口径、times 语义 (ephemeris_planar 为求解器秒,ET = et0 + times)、历元映射参数。

e2m2e.integrators.solve_planar_lowthrust_hjb_py(terminal, minimum, maximum, shape, t0, tf, drift_accel, max_accel, fuel_weight, cfl, max_step)

geo-nrho 既有调用签名的兼容包装:平面双积分器低推力 HJB。

参数顺序与 geo-nrho algorithm/dp.pysolve_low_dim_hjb 调用一致, 语义等同 solve_hjb_py(dynamics="planar_double_integrator", ...)

e2m2e.integrators.spice_furnsh(path)

在 Rust cspice 内核池加载一个内核文件。

Rust cspice 与 Python spiceypy 是**独立的 CSPICE 实例** (静态链接,全局状态 不共享)。Python 侧 furnsh 的内核,Rust 看不见;反之亦然。要让 Rust 查询 可用,必须用本函数在 Rust 侧再 furnsh 一次(同一份文件,两边独立加载)。

同时在首次加载时把行星名注册到质心/本体 ID(register_bodies ),使本 实例对 "MARS"/"JUPITER" 等的解析与 Python spiceypy 实例(那边在 manager.load_kernel 里 boddef)以及 DFH 一致——否则 CSPICE 默认表会把 "MARS" 解析成不存在的本体 499。

e2m2e.integrators.spice_pxform()

诊断用:在 Rust CSPICE 实例上查 pxform(与 spiceypy.pxform 同名函数对齐)。

用于对比 Python(spiceypy)与 Rust(cspice-sys)两个独立 CSPICE 实例的 帧旋转查询,排查内核加载同步问题。常规查询仍走 SPICEManager / spiceypy。返回 3×3 行优先矩阵。

e2m2e.integrators.spice_spkezr(target, et, frame, abcorr, observer)

诊断用:在 Rust CSPICE 实例上查 spkezr(与 spiceypy.spkezr 同名函数对齐)。

用于对比 Python(spiceypy)与 Rust(cspice-sys)两个独立 CSPICE 实例的 查询结果,排查内核加载 / boddef 同步问题。常规查询仍走 SPICEManager / spiceypy。返回 (state[6], lt)

e2m2e.integrators.spice_unload(path)

从 Rust cspice 内核池卸载一个内核文件(与 [spice_furnsh] 对称)。

Rust cspice 与 Python spiceypy 独立(见 [spice_furnsh] 文档)。 SPICEManager.load_kernel 双 furnsh,卸载必须对称:否则 Rust 内核池残留 已卸载文件,测试结果依赖同进程执行顺序(issue #387)。只卸载清单中 确已加载的文件,其余静默跳过(保持幂等语义)。

e2m2e.integrators.spherical_harmonic_accel(r, c_flat, s_flat, mu, radius, degree, order)

球谐引力加速度(body-fixed 系)。

Python 侧 GravityField._compute_acceleration_in_input_frame 的 Rust 加速版。 输入位置 r 与输出加速度均在 body-fixed 系(坐标变换仍由 Python 完成)。 c_flat/s_flat 是 C/S 系数矩阵的行优先扁平化(shape=(degree+1)**2)。

e2m2e.integrators.srp_acceleration(et, sc_pos, area, mass, cr, shadow_bodies, observer)

SRP 加速度(含阴影)。

移植自 Python SolarRadiationPressure.compute_acceleration

# 参数 - et :SPICE et 秒 - sc_pos :航天器位置 [x, y, z] km(observer 系下) - area/mass/cr :SRP cannonball 参数(area m²、mass kg、cr 无量纲) - shadow_bodies :遮挡体名称列表(如 ["EARTH", "MOON"]),空 = 无阴影 - observer :观察者天体(通常 "EARTH")

e2m2e.integrators.third_body_acceleration(et, target, observer, sc_pos, mu)

第三体摄动加速度(含直接项 + 间接项)。

移植自 Python ThirdBodyGravity.compute_acceleration 。一次调用完成 "cspice 查扰动体位置 + 加速度公式",消除 Python↔cspice 跨界 + numpy 数组分配开销。

# 参数 - et :SPICE et 秒(past J2000 TDB) - target :摄动天体名("MOON"/"SUN"/"5"=JUPITER 等) - observer :原点天体名(通常 "EARTH") - sc_pos :航天器位置 [x, y, z] km(相对 observer),长度 3 - mu :摄动天体 GM(km³/s²)

# 返回 长度 3 的加速度 Vec<f64> ,单位 km/s²。

e2m2e.integrators.wsb_search_rust(departure_state, target_state, *, mu, mu_sun, sun_distance, sun_angular_rate, sun_phase_range, n_sun_phase, departure_phase_range, n_departure_phase, tof_range_sec, n_tof, perilune_alt_range_km, max_total_dv, h2_energy_threshold, tli_speed_factor, n_propagation_samples, rtol, atol, max_step, max_steps, secondary_radius_km, characteristic_length_km, characteristic_time_sec, parallel=None, n_workers=None, progress_callback=None)[源代码]

WSB 三维网格搜索的 Rust 后端。

参数全部是已无量纲化的 POD 数值;BCR4BP 传播、截面求精和候选筛选均在 Rust 内完成。parallel=None 时由 E2M2E_WSB_PARALLEL 控制 Rayon。

参数:
返回类型:

tuple[list[dict[str, Any]], int, int]

class e2m2e.integrators.LowEnergyPatchCandidate

基类:object

低能转移流形截面态配对结果(PyO3 绑定)。

cost
delta_r
delta_v
i_a
i_b
state_a
state_b
class e2m2e.integrators.TransferPointResult

基类:object

单候选点评估结果(PyO3 绑定)。

字段对齐 Python search_single_departure 组装的候选解 dict (search_parallel.py:189-215 成功 + :135-150 失败分支)。get_all 让所有字段在 Python 侧只读可访问;wrapper grid_search_rust_serial 转为 list[dict] 返回,保持与 Python sequential 后端返回类型一致。

pyclass 在本 crate(e2m2e-forces 无 pyo3 依赖,纯数学结果由 [TransferPointResult::from] 转换)。

alpha
cause
collision_body
collision_found
collision_idx
departure_state
departure_time
dv_departure
dv_insertion
first_intersection_idx
first_intersection_time
first_min_distance_idx
first_min_distance_time
intersection_found
intersection_idx
intersection_point
local_minimum_distance
local_minimum_found
local_minimum_idx
message
min_distance
min_distance_idx
min_distance_orbit_idx
status
transfer_time
transfer_times
transfer_trajectory
e2m2e.integrators.transfer_grid_search_py(dep_states, dep_times, alpha_grid, arrival_states, mu, max_transfer_time, integration_dt, intersection_threshold, min_distance_threshold, collision_earth_radius, collision_moon_radius, rtol, atol, max_step, *, parallel=None, n_workers=None, progress_callback=None)

Python 接口:转移网格搜索(阶段 C,Rayon 并行 + GIL 释放)。

照搬 multiple_shooting_correct_pypy.allow_threads + 环境变量开关范式(multiple_shooting.rs:660-676 )。 默认走并行 transfer_grid_search_parallelparallel=FalseE2M2E_SEARCH_PARALLEL=0 回退串行 transfer_grid_search_serial—— 供并行/串行位级一致性对照(两者结果逐位相同:par_iter``+``collect 保序、 evaluate_point 纯函数)。

参数

transfer_grid_search_serial_py ,新增关键字参数:

  • parallel: None (默认)时由 E2M2E_SEARCH_PARALLEL 决定("0" → 串行, 其余/未设→并行);显式 True/False 覆盖环境变量。

  • n_workers: None (默认)时用 Rayon 全局线程池(线程数由 RAYON_NUM_THREADS 决定,未设则 cpu 核数);显式 Some(n) 时建一次性 ThreadPoolBuilder 限定 n.max(1) 个线程并 install 本次 compute—— 覆盖 RAYON_NUM_THREADS 。串行模式忽略此参数(无线程池)。

  • progress_callback: 同 transfer_grid_search_serial_py

GIL 与并行

py.allow_threads 释放 GIL 是 Rayon 真并行 + drainer 实时回调的前提—— 不释放则 GIL 序列化所有 Rayon worker、drainer 拿不到 GIL。channel 创建 + ThreadPoolBuilder + compute + drainer join 全在闭包内,tx 在闭包内 drop, drainer 干净退出。内部直接调纯 Rust transfer_grid_search 核心,不绕道持 GIL 的 propagate_cr3bp_py (这是最易踩的坑,见 transfer-grid-search-rust.md:109)。

e2m2e.integrators.transfer_grid_search_serial_py(dep_states, dep_times, alpha_grid, arrival_states, mu, max_transfer_time, integration_dt, intersection_threshold, min_distance_threshold, collision_earth_radius, collision_moon_radius, rtol, atol, max_step, *, progress_callback=None)

Python 接口:转移网格搜索(串行版,阶段 B)。

展平 POD 输入,调纯 Rust transfer_grid_search_serial , 返回 Vec<TransferPointResult> (保序:外层 departure、内层 alpha)。 串行不用 Rayon,但传入 progress_callback 时仍走 py.allow_threads 释放 GIL——否则 drainer 线程拿不到 GIL,回调退化为 compute 结束后批量触发。

参数

  • dep_states: n_dep*6 展平(行优先)

  • dep_times: n_dep

  • alpha_grid: n_alpha

  • arrival_states: n_arrival*6 展平(行优先)

  • 标量包:mu / max_transfer_time / integration_dt / intersection_threshold / min_distance_threshold / collision_earth_radius / collision_moon_radius / rtol / atol / max_step

  • progress_callback (关键字):cb(delta: int) -> None ,每个 departure 完成 调一次(出发粒度);None 不回调。

返回

list[TransferPointResult] ,长度 n_dep * n_alpha 。Python 侧 grid_search_rust_seriallist[dict]

e2m2e.exceptions module

e2m2e 统一异常层次。

所有 e2m2e 抛出的异常都以 E2M2EError 为共同基类, 便于调用方用 except E2M2EError 统一捕获库内部错误。

异常不属于任何一层,放顶层供 data/algorithm/api/tools 共享(ADR 0011 五层 结构)。

exception e2m2e.exceptions.E2M2EError[源代码]

基类:Exception

所有 e2m2e 异常的共同基类。

exception e2m2e.exceptions.RustExtensionUnavailableError[源代码]

基类:E2M2EError, RuntimeError

需要使用 Rust 扩展但扩展不可用/缺少所需符号时抛出。

spice 是默认且唯一支持的 feature(ADR 0009):核心计算路径必须由 Rust 扩展承载,不允许静默回退到 Python/scipy(issue #378)。扩展 未构建、构建不含 spice feature、或符号缺失时在使用处抛本异常, 错误信息含 make dev 修复指引。

同时继承 E2M2EError (库内统一捕获)与 RuntimeError (兼容既有裸 RuntimeError 捕获点)。

exception e2m2e.exceptions.PropagationFailure[源代码]

基类:E2M2EError

传播失败(ADR 0020 决策 2,取代字符串前缀匹配契约)。

步长塌缩到机器精度地板等确定性传播失败,在 Rust→Python FFI 边界 翻译成本异常,供下游 except PropagationFailure 精确捕获;此前依赖 "step size collapsed" 错误消息前缀匹配(issue #317 第 3.1 项), 现已废弃。改写 Rust 侧错误消息措辞不再影响捕获。

继承 E2M2EError (统一捕获契约),但不继承 RuntimeError (与通用运行时错误区分;既有裸 except RuntimeError 不再兜住它)。

e2m2e.tools.logging module

结构化日志:配置工厂。

标准 logging + 关键事件键值对、零新依赖(ADR 0011):算法层保持 logger.info,打靶/延拓迭代等关键数值事件用键值对 (logger.info("correction_iter", iter=3, error=1e-8));本模块提供 配置工厂(Formatter 把键值对转 key=val)。 应用入口(examples/ 等,包外)调用 configure_logging 控制级别和 handler——库本身不配置日志(ADR 0012:api/ 不依赖 tools/)。

e2m2e.tools.logging.configure_logging(level='WARNING', *, handler=None, formatter=None)[源代码]

配置根 logger(级别 + 键值对 Formatter)。

参数:
  • level (str) -- 日志级别(DEBUG/INFO/WARNING/ERROR)。

  • handler (Handler | None) -- 输出 handler(缺省 StreamHandler)。

  • formatter (Formatter | None) -- 自定义 Formatter(缺省 KeyValueFormatter)。

返回类型:

None