# 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` 列表
