Files
dynamics/optimization/claude_v1.md
T
admin e1ade53fff docs: 综合三工具六版本分析,输出 workbuddy_v2.md
基于 workbuddy.md / claude.md / codex.md 三份原始分析
及 claude_v1.md / codex_v1.md / workbuddy_v1.md 三份综合
版本,输出最终优化方案。

核心改进:
- 三工具角色定位框架(QA/Perf/Architect)
- Bug 三级分类(真 Bug / 已修复 / 疑似误报)
- 三阶段方案(修正确性→做性能→做治理)
- 自我评价与修正(v1→v2 改进表)
- 10 场景工具选择速查表
2026-06-12 15:45:47 +08:00

460 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Dynamics 项目优化方案综合报告
> 整合日期:2026-06-12
> 来源文档:[`claude.md`](claude.md)Claude Sonnet 4.6 分析)、[`workbuddy.md`](workbuddy.md)WorkBuddy 分析)
> 项目路径:`D:\Share\Data\aliyun-gitea\dynamics`
---
## 第一部分:两份分析报告的评价与对比
### 1.1 WorkBuddy 分析报告评价(`workbuddy.md`
#### 优势
**① 架构视野宏观、分层清晰**
WorkBuddy 从整体软件工程角度出发,明确指出 `compute.py` 的职责混乱问题(1618 行同时承担物理引擎、文件 I/O、参数加载、外部引擎管理五种职责),并给出了完整的模块拆分方案:
```
compute/
├── core.py # 物理引擎
├── io.py # 文件 I/O
├── params.py # 参数加载
├── runner.py # 运行管理
├── engine_helper.py # 外部引擎
└── main.py # 主入口
```
这是一个系统性重构方向,有助于长期维护。
**② 关注工程规范与测试**
WorkBuddy 专门开辟了"测试与质量"一节,强调了缺少单元测试的风险,并给出了类型标注的示例代码——这两点是 claude.md 未涉及的。对于一个教学/研究用项目,有测试才能安全重构。
**③ 配置管理建议具体**
提出了将 `ball_color_r/g/b` 三个键合并为 `ball_color: [r,g,b]` 数组的配置统一方案,以及6个案例 `input.txt` 格式不统一的问题(如 `save_trajectory``camera_*` 字段缺失),并给出了统一模板,实操性强。
**④ 引擎一致性梳理全面**
清晰列出了 C/C++/Fortran 三引擎在 `save_trajectory``box_a` 默认值等参数上的差异表格,对用户切换引擎有直接指导价值。
**⑤ 区分"已完成"与"待做"**
文档中标注了"✅ 已修复"、"✅ 已完成"条目,帮助读者快速定位当前状态,避免重复分析。
#### 劣势
**① 缺少具体 Bug 定位**
WorkBuddy 的分析主要停留在架构和规范层面,对于已经导致运行崩溃的 Bug(如 `plot_wave.py` 格式不匹配、`run_simulation``config` 未定义)没有识别和标注。用户按此文档操作时,可能先花时间做重构,但基础功能仍然崩溃。
**② 性能优化建议较抽象**
对 Python 引擎性能仅建议"使用 Numba JIT"或"numpy.vectorize",缺少具体的向量化代码示例。文档注明"Python vs C 慢约 6-8 倍",但未分析哪个函数是瓶颈(实际上是弹簧力的 Python for 循环)。
**③ 部分建议颗粒度不足**
"消除全局变量"建议封装为 `SimulationState` 数据类,但未说明:封装后接口如何调整、外部引擎的 `param.json` 协议是否需要同步更新、draw.py 的全局变量是否属于同一重构范围。
**④ 优先级排列有待商榷**
将"全局变量封装"列为 P0(与 Fortran 引擎修复同级),但封装全局变量是一项重构工作(3-4h),而 Fortran 引擎崩溃是已存在的功能阻断性问题,两者紧迫性不同。
---
### 1.2 Claude 分析报告评价(`claude.md`
#### 优势
**① Bug 定位精准,附有复现条件**
每个 Bug 都说明了触发条件("只要使用 `engine: python`"、"`step_plot_wave: 1` 时"),以及为什么当前没有爆发("当前所有案例恰好设置 `step_plot: 0`")。这对于开发者复现和验证问题极有价值。
**② 代码级修复方案完整**
每个 Bug 都给出了完整可运行的修复代码,包括需要修改的行号、修改前后的对比。特别是 B3(`plot_wave.py` 格式不匹配)不仅指出问题,还解释了为何修复较复杂(`atom_masses` 等物理量在新格式中缺失,需要同步扩展 header 字段),给出了分层的修复路径(快速修复 vs 彻底修复)。
**③ 弹簧力向量化方案具体可行**
给出了完整的 NumPy 向量化代码,包括处理重复索引的 `np.add.at` 用法,以及链状体系可进一步优化为直接索引的提示。预期加速 5-15 倍的估算也有根据(119 键 × 100,000 步的量级分析)。
**④ 引擎差异的量化说明**
指出了 `engines/cpp/param.json``save_trajectory` 默认值为 1(与 C 引擎的 0 不一致),并说明了实际影响(切换引擎时可能意外生成大文件)。
#### 劣势
**① 覆盖面刻意与 workbuddy.md 错开,造成视野盲区**
claude.md 开篇声明"不与 workbuddy.md 重复",因此主动跳过了架构、测试、配置管理等方向。但这导致文档读者如果只看 claude.md,会误以为架构是没问题的。两份文档需要结合阅读,割裂感较强。
**② 部分建议依赖全局变量方案**
claude.md 提出的 Bug B1 修复方案(将 `camera_distance` 等加入全局变量)是在全局变量模式下的补丁式修复,与 workbuddy.md 建议的"封装全局变量为类"方向相反。若未来执行 workbuddy.md 的重构,B1 的修复需要再次调整。
**③ 某些结论尚未验证**
文档末尾注明"基于代码静态分析,未实际运行测试验证"。例如 B3(`plot_wave.py` 格式不匹配)的结论基于函数调用链分析,如果 `load_text_data` 内部有容错逻辑,实际情况可能不同。
**④ 缺乏对 draw.py 的深入分析**
draw.py 是用户交互最频繁的模块(3D 动画播放),但 claude.md 仅指出了一处裸 `except`(B5),未分析动画帧率优化、大原子数渲染性能等用户体验层面的问题。
---
### 1.3 两份报告对比总结
| 维度 | WorkBuddy | Claude |
|------|-----------|--------|
| **Bug 识别** | ❌ 未发现运行时 Bug | ✅ 识别 5 个确认 Bug,附触发条件 |
| **性能优化** | 🟡 方向正确但缺代码 | ✅ 完整向量化代码示例 |
| **架构设计** | ✅ 完整模块拆分方案 | ❌ 刻意回避,未覆盖 |
| **测试建议** | ✅ pytest 方案具体 | ❌ 未涉及 |
| **配置管理** | ✅ 6 案例统一模板 | ❌ 未涉及 |
| **引擎一致性** | ✅ 参数差异表格 | ✅ 补充了势能归属约定 |
| **修复代码** | 🟡 仅有架构示意 | ✅ 逐条给出可运行代码 |
| **优先级合理性** | 🟡 P0 安排有误 | ✅ 按紧迫性分层清晰 |
| **可独立阅读** | ✅ 自成体系 | ❌ 依赖读者已读 workbuddy.md |
| **当前状态标注** | ✅ 已完成项有标注 | ❌ 未区分 |
**结论**:WorkBuddy 擅长系统性架构分析和工程规范,Claude 擅长 Bug 精确定位和具体修复代码。两份报告互补,单独使用任何一份都存在明显盲区。
---
## 第二部分:综合优化方案
### 原则
基于以上分析,综合方案遵循以下原则:
1. **先止血再手术**:运行时 Bug 优先于架构重构,不能让教学演示功能处于崩溃状态
2. **快速收益优先**:同等重要性时,工作量小的先做
3. **向量化先于重构**:Python 引擎提速不依赖架构改动,可独立进行
4. **渐进式重构**:全局变量封装等重构分阶段进行,避免一次性大改引入新 Bug
---
### 阶段一:紧急修复(总工作量约 4 小时)
> 目标:恢复所有已有功能到正常可用状态
#### 1. 修复 `plot_wave.py` 格式不匹配(B3)— 1.5h
**根本原因**`display.txt` 格式从 JSON 迁移到新文本格式时,`plot_wave.py` 未同步更新。
**修复步骤**
① 修改加载函数(`plot_wave.py:22-27`):
```python
def load_disp_data(output_dir):
disp_path = os.path.join(output_dir, "display.txt")
if not os.path.exists(disp_path):
raise FileNotFoundError(f"找不到 {disp_path}")
return compute.load_display_txt(disp_path) # 改为新格式加载
```
② 在 `save_display_txt``compute.py:217`)的 header 中补充 `atom_masses` 字段:
```python
# 在 header_fields 中添加
"atom_masses": ",".join(str(m) for m in ATOM_MASSES),
```
③ 修改 `plot_wave.py` 中的字段访问:
```python
# 旧 → 新
data["n_frames"] disp_data["frames_x"].shape[0]
data["disp_all_x"] disp_data["frames_x"]
data["atom_masses"] np.array([float(x) for x in h.get("atom_masses","").split(",") if x])
data["atom_ids"] disp_data["atom_ids"]
data["bond_pairs"] [] # display.txt 不含成键信息,能量计算中弹性势能项跳过
```
**验证**:运行 case05`step_plot_wave: 1`),确认生成 `wave_animation.gif`
---
#### 2. 修复 `run_simulation()` 中的 `config` 未定义(B1)— 15min
`compute.py` 模块顶部(约第 68 行,紧随 `camera_keyframes_raw`)添加全局变量:
```python
camera_keyframes_raw = ""
camera_distance = 40.0 # 新增
camera_elevation = 0 # 新增
camera_azimuth = 0 # 新增
```
`run_from_config`(约第 756 行,`use_marker` 赋值附近)添加:
```python
use_marker = int(config.get("use_marker", 0))
camera_distance = float(config.get("camera_distance", 40.0)) # 新增
camera_elevation = float(config.get("camera_elevation", 0)) # 新增
camera_azimuth = float(config.get("camera_azimuth", 0)) # 新增
```
`run_from_config``global` 声明行追加这三个变量:
```python
global use_marker, camera_keyframes_raw, camera_distance, camera_elevation, camera_azimuth
```
`run_simulation`(第 1548-1550 行)改为读全局变量:
```python
"camera_distance": str(camera_distance),
"camera_elevation": str(camera_elevation),
"camera_azimuth": str(camera_azimuth),
```
**验证**:用 `engine: python` 运行 case01,确认生成正确的 `display.txt`
---
#### 3. 修复 `dynamics.py` 绘图块死代码(B2)— 30min
`step_plot` 功能依赖完整轨迹数据,但当前架构中 `run_from_config` 不再在主流程中保留这些数据。
快速修复:添加 "功能暂不可用" 保护,避免用户误开后崩溃:
```python
# dynamics.py 约 322 行
if not no_plot and config.get("step_plot", 1):
print("[run] 注意:step_plot 绘图功能需要 save_trajectory=1 时的完整轨迹,")
print("[run] 当前版本暂未支持,已跳过。如需绘图请联系开发者。")
```
**长期修复**(阶段三再做):从 `display.txt` 读取抽帧数据重建绘图逻辑。
---
#### 4. 修复 Fortran 引擎输出格式(E3)— 2h
Fortran 引擎总是输出 JSON 格式 `trajectory.txt`,与 Python 侧期待的 `display.txt` 不兼容,
使用 `engine: fortran` 时必然崩溃。
参照 C 引擎的 `write_display_txt` 函数(`engines/c/main.c`)在 Fortran 中实现:
1. 读取 `param.json` 中的 `save_trajectory` 参数
2. 新增 `write_display_txt_f90` 子程序,按 NSTEP 抽帧写文本格式
3. 根据 `save_trajectory` 决定是否额外写 `trajectory.txt`
**同时**:将 `engines/cpp/param.json` 中的 `"save_trajectory": 1` 改为 `0`,与 C 保持一致。
---
#### 5. 其他 1-5 分钟的小修复
```python
# B4: examples/case06/run_dynamics.py:34
description="运行 Dynamics 示例案例 case06" # 改 case01 → case06
# B5: draw.py:97
except (ValueError, AttributeError): # 改裸 except
# Q1: dynamics.py 顶部
from compute import _load_camera_motion as _load_camera_kf # 删除重复实现
# E2: engines/cpp/param.json
"save_trajectory": 0 # 统一默认值
```
---
### 阶段二:性能优化(总工作量约 3 小时)
> 目标:Python 引擎提速 5-10 倍,外部引擎减少启动开销
#### 6. 弹簧力向量化(P1)— 1h
`compute.py:1253-1277` 的 Python for 循环替换为 NumPy 向量化版本(见 claude.md §P1 完整代码)。
**链状体系(case01-06)的进一步优化**
由于链状体系每根键的两端没有重复(原子 i 和 j 各只出现一次),可以用更快的直接索引替代 `np.add.at`
```python
# 比 np.add.at 快约 3 倍(无冲突索引时)
fx[i_arr] += fx_bond
fx[j_arr] -= fx_bond
fy[i_arr] += fy_bond
fy[j_arr] -= fy_bond
fz[i_arr] += fz_bond
fz[j_arr] -= fz_bond
```
对于有分叉键的复杂体系仍需用 `np.add.at`,可根据 `BOND_PAIRS` 检测是否有重复端点自动选择路径。
---
#### 7. `apply_fixed_constraints` 预计算掩码(P2)— 30min
`compute.py:1408-1418``column_stack` 方案替换为预计算 bool 掩码,见 claude.md §P2 完整代码。
对 case06(120 原子,x/y 全固定)每步节省 2 次 `(120, 3)` 数组分配。
---
#### 8. 外部引擎校准缓存(E4)— 1h
`compute.py:924` 校准逻辑前添加缓存命中检查:
```python
import hashlib, json as _json
def _calib_cache_key(engine, n_atoms, method, dt):
s = f"{engine}:{n_atoms}:{method}:{dt}"
return hashlib.md5(s.encode()).hexdigest()[:8]
_calib_cache_path = os.path.join(script_dir, "engines", engine, "_calib_cache.json")
_calib_key = _calib_cache_key(engine, len(ATOM_IDS), config.get("method","leapfrog"), float(config["DT"]))
_cached = {}
if os.path.exists(_calib_cache_path):
with open(_calib_cache_path) as _cf:
_cached = _json.load(_cf)
if _cached.get("key") == _calib_key and time.time() - _cached.get("ts", 0) < 86400:
# 缓存命中(1天内有效),跳过校准
_step_time = _cached["step_time"]
_overhead = _cached["overhead"]
else:
# 执行校准(现有逻辑)...
# 校准完成后写缓存
with open(_calib_cache_path, "w") as _cf:
_json.dump({"key": _calib_key, "ts": time.time(),
"step_time": _step_time, "overhead": _overhead}, _cf)
```
**预期收益**:case06 第二次运行节省约 10 秒(校准 10,000 步)。
---
#### 9. 其他微优化(P3/P4)— 30min
```python
# P3: run_simulation 中删除 frame_indices 列表
# 删除: frame_indices = [] 和 frame_indices.append(step)
# 替换: n_frames_actual = record_steps // NSTEP (直接计算)
# P4: apply_driving_force 中删除 t_vec 数组创建
t_vec = np.array([t, t, t], dtype=np.float64) # 删除此行
pos_drive = d["amp"] * np.cos(2.0 * np.pi * d["freq"] * t + d["phi"]) # 直接用标量 t
```
---
### 阶段三:架构重构(总工作量约 15-20 小时)
> 目标:提升长期可维护性,支持并发模拟、单元测试
> **重要说明**:此阶段是 workbuddy.md 建议的核心,以下是对其建议的细化和补充。
> 建议在阶段一、二完成并通过全案例验证后再开始。
#### 10. 全局变量封装为 `SimulationState`workbuddy.md §3.1)— 3-4h
封装后,阶段一中 B1 的补丁修复(新增三个全局变量)可以一并纳入 `SimulationState`,不需要额外保留。
封装时注意:外部引擎路径(`run_engine`)通过 `param.json` 传参,不受全局变量影响,可独立进行。
#### 11. `compute.py` 模块拆分(workbuddy.md §1.1)— 4-6h
拆分时建议**先拆 io.py**(文件读写),因为它与物理算法完全解耦,风险最低。
拆分顺序建议:`io.py``params.py``core.py``runner.py`
**补充**:同步删除已废弃的 `load_parameters()` 函数(102 行)和已被 `dynamics.py` 取代的 `compute.main()`25 行),见 claude.md §Q2。
#### 12. 添加单元测试(workbuddy.md §5.1)— 3-5h
优先覆盖以下三类:
1. 物理算法正确性:以简谐振子解析解验证 leapfrog、midpoint 方法(参照 `tools/NumericalMethods.py` 已有实现)
2. 文件 I/O 往返一致性:`save_display_txt → load_display_txt` 数值不变
3. 参数验证边界:质量为 0、键长为负、NT 为 0 等异常输入
#### 13. 案例 `input.txt` 格式统一(workbuddy.md §4.1)— 1-2h
`case01-05``input.txt` 补充缺失字段(`save_trajectory``camera_*``move_camera`),
统一 `step_sample: 0`(新版引擎已内置抽帧),清理旧格式注释。
#### 14. `dynamics.py` 绘图功能完整重建(B2 长期修复)— 2h
`display.txt` 的抽帧数据重建绘图逻辑(替代依赖完整轨迹的旧实现):
```python
disp_data = compute.load_display_txt(disp_path)
frames_x = disp_data["frames_x"] # (n_frames, n_atoms)
# 对每帧计算能量,绘制时序图
```
能量计算需要质量等物理量,依赖阶段一 B3 修复中在 header 补充的 `atom_masses` 字段。
---
### 三个引擎的综合评价
#### C 引擎(`engines/c/main.c`
| 维度 | 评价 |
|------|------|
| **功能完整性** | ✅ 最完整,支持 `display.txt` 直接输出,`save_trajectory` 控制 |
| **性能** | ✅ 基准引擎,比 Python 快 6-8 倍 |
| **一致性** | ✅ `save_trajectory` 默认值为 0,与 Python 行为一致 |
| **代码质量** | 🟡 JSON 解析为自行实现(非 cJSON 库),维护成本高 |
| **建议** | 作为参考实现,其他引擎向 C 引擎看齐 |
#### C++ 引擎(`engines/cpp/main.cpp`
| 维度 | 评价 |
|------|------|
| **功能完整性** | ✅ 功能与 C 引擎相当 |
| **性能** | 🟡 编译产物 3.3 MB(远大于 C 的 504 KB),有优化空间 |
| **一致性** | ⚠️ `save_trajectory` 默认值为 1(与 C 不一致),已在阶段一修复 |
| **代码质量** | 🟡 物理算法与 C 引擎重复,应提取到公共头文件 |
| **建议** | 统一 `param.json` 默认值;考虑与 C 引擎共用物理算法头文件 |
#### Fortran 引擎(`engines/fortran/main.f90`
| 维度 | 评价 |
|------|------|
| **功能完整性** | ❌ 不支持 `display.txt` 直接输出,使用时必然崩溃 |
| **性能** | ✅ 编译性能与 C 相当,适合大规模计算 |
| **一致性** | ❌ 输出 JSON 格式 trajectory.txt,与其他引擎行为完全不同 |
| **代码质量** | 🟡 代码结构清晰,但与 C/C++ 引擎物理算法重复 |
| **建议** | 阶段一 E3 修复为最高优先级;修复后可成为高性能替代引擎 |
---
### 综合优先级总表
| 阶段 | 编号 | 问题 | 来源 | 优先级 | 预估工时 |
|------|------|------|------|--------|---------|
| 一 | B3 | `plot_wave.py` 格式不匹配(波形动画失效) | Claude | 🔴 P0 | 1.5h |
| 一 | E3 | Fortran 引擎不支持 display.txt | 两者 | 🔴 P0 | 2h |
| 一 | B1 | `run_simulation``config` 未定义 | Claude | 🔴 P0 | 15min |
| 一 | B2 | `dynamics.py` 绘图块死代码 | Claude | 🔴 P0 | 30min |
| 一 | B4/B5 | 小错误修复(case06 文字、裸 except 等) | Claude | 🟡 P1 | 15min |
| 一 | Q1/E2 | 重复函数去除、C++ 默认值统一 | Claude | 🟡 P1 | 20min |
| 二 | P1 | 弹簧力向量化(Python 引擎 5-15x | Claude | 🟢 P1 | 1h |
| 二 | E4 | 外部引擎校准缓存 | 两者 | 🟢 P1 | 1h |
| 二 | P2-P4 | apply_fixed_constraints 等微优化 | Claude | 🟢 P2 | 1h |
| 三 | 架构 | 全局变量封装为 SimulationState | WorkBuddy | 🔵 P2 | 3-4h |
| 三 | 架构 | compute.py 模块拆分 | WorkBuddy | 🔵 P2 | 4-6h |
| 三 | 测试 | 添加 pytest 单元测试 | WorkBuddy | 🔵 P2 | 3-5h |
| 三 | 配置 | 6 案例 input.txt 格式统一 | WorkBuddy | 🔵 P3 | 1-2h |
| 三 | 绘图 | dynamics.py 绘图功能重建 | Claude | 🔵 P3 | 2h |
| 三 | 引擎 | C/C++/Fortran 共用物理算法头文件 | WorkBuddy | 🔵 P3 | 2-4h |
---
## 附录:快速执行清单
### 今天可以完成(总计约 30 分钟的小修复)
```
[ ] examples/case06/run_dynamics.py:34 "case01" → "case06"
[ ] draw.py:97 裸 except → except (ValueError, AttributeError):
[ ] dynamics.py 删除 _load_camera_kf(),改为从 compute 导入
[ ] engines/cpp/param.json "save_trajectory": 1 → 0
[ ] compute.py:1548-1550 config.get → 全局变量(B1 修复)
```
### 本周可以完成(核心功能恢复)
```
[ ] plot_wave.py 格式适配(B3
[ ] dynamics.py 绘图块保护(B2 临时修复)
[ ] Fortran 引擎 display.txt 支持(E3
[ ] 弹簧力向量化(P1
[ ] 引擎校准缓存(E4
```
### 下阶段规划(架构改善)
```
[ ] 全局变量 → SimulationState 类
[ ] compute.py 拆分为子模块
[ ] pytest 单元测试套件
[ ] 案例 input.txt 格式统一
```
---
*本文档综合 Claude Sonnet 4.6`claude.md`)与 WorkBuddy`workbuddy.md`)的分析报告生成。
所有代码改动建议均基于静态分析,实施前请先在独立分支验证。*