782422e800
涵盖架构/性能/代码质量/配置/测试/引擎一致性/UX 等 9 个方面、26 条具体建议,标注实施优先级和工作量。
304 lines
8.4 KiB
Markdown
304 lines
8.4 KiB
Markdown
# 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 步) 跳过校准
|
||
- 或只在校准目录为空时执行
|
||
|
||
```python
|
||
# 建议改动
|
||
_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+ 个模块级全局变量:
|
||
|
||
```python
|
||
box_a = None
|
||
alpha = None
|
||
ATOM_IDS = None
|
||
...
|
||
```
|
||
|
||
所有算法函数直接依赖这些全局变量,导致:
|
||
- 无法并发运行两个模拟
|
||
- 无法单元测试单个函数
|
||
- 函数签名无法自文档化
|
||
|
||
**建议**:将全局状态封装为 `SimulationState` 类:
|
||
|
||
```python
|
||
@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 个模块级变量:
|
||
|
||
```python
|
||
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`配置 | 旧注释格式 | 新注释格式 |
|
||
|
||
**建议**:
|
||
|
||
```yaml
|
||
# 统一模板
|
||
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 列表更自然:
|
||
|
||
```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 缺少类型标注(中优先级)
|
||
|
||
```python
|
||
# 现状
|
||
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`。需要:
|
||
|
||
1. 读取 `save_trajectory` 参数
|
||
2. 计算时按 NSTEP 采样
|
||
3. 写 display.txt 新格式
|
||
4. 按条件跳过 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(半小时内可完成)
|
||
|
||
1. ✅ 更新 Fortran 引擎(参考 C 的 `write_display_txt` 迁移)
|
||
2. ✅ 删除 `sample.py`(已废弃)
|
||
3. ✅ 统一 6 个案例的 `input.txt` 格式
|
||
4. ✅ 添加 `save_trajectory` 到 case01-05 的 default 配置
|
||
5. ✅ 统一 `ball_color_r/g/b` 为 `ball_color` 列表
|