涵盖架构/性能/代码质量/配置/测试/引擎一致性/UX 等 9 个方面、26 条具体建议,标注实施优先级和工作量。
8.4 KiB
Dynamics 项目优化建议
分析日期:2026-06-12 版本:main (43 commits)
1. 架构优化
1.1 compute.py 拆分(高优先级)
现状:compute.py 1618 行,混合了以下职责:
- 物理引擎(数值积分方法 ~10 个函数)
- 文件 I/O(JSON/text 读写)
- 外部引擎管理(subprocess 调用)
- 参数加载与解析
- 主入口 main()
建议:按职责拆分为独立模块
compute/
├── __init__.py # 导出公共 API
├── core.py # 物理引擎: 数值积分方法, 力的计算 (~200 行)
├── io.py # 文件 I/O: save/load display/trajectory (~300 行)
├── params.py # 参数加载: load_coord_file, load_bond 等 (~150 行)
├── runner.py # 运行管理: run_simulation, run_engine, run_from_config (~200 行)
├── engine_helper.py # 外部引擎: 校准, subprocess, 进度监控 (~150 行)
└── main.py # 主入口: main(), if __name__ == "__main__" (~30 行)
收益:可单独测试物理算法、文件读写、引擎调用
1.2 外部引擎代码重构(中优先级)
现状:C/C++/Fortran 引擎各自实现了一套:
- JSON 读取/写入(3 套独立实现)
- 物理算法(复制粘贴)
- display.txt / trajectory.txt 输出
建议:
- C 和 C++ 引擎共用头文件/函数库
- 物理算法提取为公共库(
engines/common/) - Fortran 更新支持
save_trajectory兼容
2. 性能优化
2.1 外部引擎校准耗时(高)
现状:run_engine() 每次执行前先跑 1000 步校准测速(_calib_nt = min(1000, max(100, total_steps // 10))),对短时运行(~1000 步)校准占比高达 50%。
建议:
- 缓存校准结果:按
(engine, NT, DT, NSTEP, n_atoms)哈希缓存 - 或对短运行 (<5000 步) 跳过校准
- 或只在校准目录为空时执行
# 建议改动
_calib_cache = os.path.join(script_dir, "engines", engine, "_calib_cache.json")
if os.path.exists(_calib_cache):
with open(_calib_cache) as f:
_calib_data = json.load(f)
if _calib_data.get("key") == _calib_key:
_step_time = _calib_data["step_time"]
_overhead = _calib_data["overhead"]
skip_calibration()
2.2 display.txt 读取加速(已完成)
现状:已从逐行 split()+float() 改为 np.genfromtxt() 批量解析,200帧×120原子 加载仅 0.087s(测试已通过)。
2.3 Python 引擎性能(低)
现状:Python 引擎比 C 引擎慢约 6-8 倍(43s vs 7s for 10 万步)。对 50 万步以上的长时间模拟不适用。
建议:
- 使用 Numba JIT 加速力的计算
- 或使用
numpy.vectorize替代 Python 循环(力的计算中已部分使用 numpy 数组操作) - 文档中注明 Python 引擎仅适用于小规模测试
2.4 校准数据的进度条(已修复)
校准后进度条使用实时帧号更新,不再使用时间估算,避免了 0% → 100% 跳变。但注意校准本身不显示进度。
3. 代码质量
3.1 消除全局变量(高优先级)
现状:compute.py 定义了 40+ 个模块级全局变量:
box_a = None
alpha = None
ATOM_IDS = None
...
所有算法函数直接依赖这些全局变量,导致:
- 无法并发运行两个模拟
- 无法单元测试单个函数
- 函数签名无法自文档化
建议:将全局状态封装为 SimulationState 类:
@dataclass
class SimulationState:
box_a: float = 10.0
atom_ids: np.ndarray = None
atom_masses: np.ndarray = None
...
def leapfrog(state: SimulationState, ...):
...
3.2 draw.py 全局变量(中优先级)
现状:类似的问题,draw.py 用了 ~30 个模块级变量:
DISPLAY_X = ...
DISP_ALL_X = ...
N_FRAMES = ...
frame_idx = 0
建议:封装为 AnimationData 和 CameraState 类
3.3 废弃文件清理(低优先级)
以下文件可能已废弃或重复:
| 文件 | 行数 | 判断 |
|---|---|---|
sample.py |
184 | 已不再被调用(抽帧已移至引擎内部) |
build_release_zip.py |
- | 打包脚本,非核心功能 |
export_web_data.py |
- | 导出脚本,非核心功能 |
migrate_npz_outputs.py |
- | 迁移脚本,一次性使用 |
tools/NumericalMethods.py |
- | 可能已过时 |
build/ (CMake 相关) |
- | 与独立引擎编译无关 |
4. 配置管理
4.1 input.txt 格式统一(高优先级)
现状:6 个案例的 input.txt 格式不统一:
| 字段 | case01 | case06 |
|---|---|---|
save_trajectory |
❌ 缺失 | ✅ 有 |
camera_distance/elevation/azimuth |
❌ 缺失 | ✅ 有 |
move_camera |
❌ 缺失 | ✅ 有 |
step_sample |
仍然写 1 | 已改为 0 |
step_plot配置 |
旧注释格式 | 新注释格式 |
建议:
# 统一模板
flow:
step_simulate: 1
step_sample: 0 # 引擎已内置抽帧
step_animation: 1
save_trajectory: 0 # 默认不保留
physics:
box_a: 10.0
G: [0, 0, -9.8]
method: leapfrog
T_total: 10.0
NSTEP: 100
DT: 0.001
render:
use_marker: 0
alpha: [0.0]*6
ball_color: [0.9, 0.2, 0.2]
box_color: [0.8, 0.8, 0.85]
camera:
distance: 40.0
elevation: 0
azimuth: 0
move: false
4.2 YAML 结构优化(中优先级)
现状:ball_color_r/g/b 三个独立的键,YAML 列表更自然:
# 当前
ball_color_r: 0.90
ball_color_g: 0.20
ball_color_b: 0.20
# 建议
ball_color: [0.90, 0.20, 0.20]
5. 测试与质量
5.1 缺少测试(高优先级)
现状:无单元测试、无集成测试。每次修改只能手动跑案例。
建议:
- 为
compute.py的物理算法(Leapfrog、Euler 等)添加 pytest 测试 - 为文件 I/O(
save_display_txt/load_display_txt读写一致性)添加测试 - 添加一个
examples/case00最小验证案例(2 个原子,10 步) - CI:
pytest+ 简单的集成测试脚本
5.2 缺少类型标注(中优先级)
# 现状
def leapfrog(x, y, z, vx, vy, vz, dt, m, g, b):
# 建议
def leapfrog(
x: np.ndarray, y: np.ndarray, z: np.ndarray,
vx: np.ndarray, vy: np.ndarray, vz: np.ndarray,
dt: float, m: np.ndarray, g: np.ndarray, b: np.ndarray
) -> tuple[np.ndarray, np.ndarray, np.ndarray,
np.ndarray, np.ndarray, np.ndarray]:
6. 引擎一致性
6.1 Fortran 引擎更新(高)
现状:Fortran 引擎不支持 save_trajectory=0 模式,总是写 JSON 格式的 trajectory.txt。需要:
- 读取
save_trajectory参数 - 计算时按 NSTEP 采样
- 写 display.txt 新格式
- 按条件跳过 trajectory.txt 输出
参考 C 引擎的 write_display_txt 实现(约 40 行代码)。
6.2 参数默认值一致性(中)
各引擎的 SimParams 默认值不一致:
| 参数 | C | C++ | Fortran |
|---|---|---|---|
box_a |
无默认 | 10.0 | 10.0 (代码中) |
method |
leapfrog | leapfrog | leapfrog |
save_trajectory |
0 | 1 | 不支持 |
7. 用户体验
7.1 进度条改进(低)
- 外部引擎校准阶段不显示进度(建议加 "校准中…" 文本)
- Fortran 引擎支持时,增加进度消息
7.2 缓存一致性(已修复)
已修复:display.txt 在 save_trajectory=0 时不再保留 trajectory.txt,外部引擎路径总是从 trajectory.txt 重新抽帧。
7.3 move_camera.txt 实时生效(已修复)
draw.py 直接读取 move_camera.txt,修改后重启动画即可生效,无需重新跑模拟。
8. 实施优先级
| 优先级 | 内容 | 预估工作量 |
|---|---|---|
| P0 | Fortran 引擎支持 save_trajectory=0 | 2-3h |
| P0 | 全局变量封装为 SimulationState | 3-4h |
| P1 | compute.py 模块拆分 | 4-6h |
| P1 | 添加单元测试 (pytest) | 3-5h |
| P1 | input.txt 格式统一 (6个案例) | 1-2h |
| P2 | 校准缓存加速 | 1-2h |
| P2 | 废弃文件清理 | 0.5h |
| P3 | draw.py 封装 AnimationData | 2-3h |
| P3 | 类型标注 | 2-3h |
9. 快速 wins(半小时内可完成)
- ✅ 更新 Fortran 引擎(参考 C 的
write_display_txt迁移) - ✅ 删除
sample.py(已废弃) - ✅ 统一 6 个案例的
input.txt格式 - ✅ 添加
save_trajectory到 case01-05 的 default 配置 - ✅ 统一
ball_color_r/g/b为ball_color列表