⚛︎ ⋆｡°✩ ⭐ ⋆｡°✩

# Dynamics 物理模拟实验室

用代码让小球动起来！从牛顿力学到分子模拟
🎯 适合高一同学 · 零基础也能上手

## 🤔 这是什么？

想象一下：你把一个弹珠从桌子上推下去——它会怎么运动？如果同时扔两个弹珠，它们会互相碰撞吗？如果弹珠之间用弹簧连着呢？

Dynamics 就是一个在电脑上做这些"弹珠实验"的程序。你只需要告诉电脑：

- 小球在哪里、多重、多快
- 有没有重力、有没有弹簧
- 跑多少步、画什么图

然后电脑就会帮你算出每个小球每一瞬间的位置和速度，最后画出一张漂亮的轨迹图！

🎮 把它想象成一个超级物理沙盒游戏
你设置物理规则，电脑负责计算，然后你看到结果。和 Minecraft 有点像，但这里的「物理引擎」是真的物理公式！

### 它能做什么？

- 模拟自由落体 —— 苹果为什么会往下掉？
- 模拟弹簧振动 —— 弹弹球为什么上下跳？
- 模拟双星绕转 —— 两颗星星为什么互相转？
- 画轨迹图 —— 把运动过程变成曲线图
- 3D 动画 —— 在 3D 空间里看小球飞

## 🛠️ 安装

1 安装 Python

从 python.org 下载安装包， 安装时一定记得勾选 "Add Python to PATH"。

2 安装依赖包

    终端pip install numpy pyyaml tqdm matplotlib

如果下载慢，试试国内镜像：`pip install -i https://pypi.tuna.tsinghua.edu.cn/simple ...`

3 下载程序

把整个项目文件夹放到电脑上。打开终端，`cd` 到项目目录。

4 验证安装

    终端py -3 examples/case01/run_dynamics.py --no-plot

看到 `[run] 完成!` 就说明成功了！

💡 小提示：如果你只想看看效果，装好 `numpy` 和 `pyyaml` 就能跑了。`matplotlib` 是用来画图的，建议也装上。

## 📖 快速物理课

别怕，你学过的物理知识在这里全用得上！

### 🌍 力（Force）

力是让物体运动状态改变的东西。程序里支持四种力：

力 | 生活中的例子 | 程序里的开关
--- | --- | ---
均匀重力 | 苹果从树上往下掉，方向朝地面 | `gravity_field`
万有引力 | 太阳和地球互相吸引，质量越大越明显 | `gravity_interaction`
弹簧力 | 蹦极的绳子把你拉回来 | `elastic_force`
阻尼（阻力） | 在水里挥手比在空气里费劲得多 | `damping_force`

### 🏃 运动

程序用 蛙跳法（Leapfrog） 来模拟运动。名字很形象：

🐸 蛙跳的步骤：

1. 前半步：根据当前受力，把速度往前推一小半步
2. 跳：用新的速度把位置往前推一步
3. 后半步：到新位置后重新算受力，再推另一半速度

就像青蛙跳一样——先蹲下蓄力（半步速度），跳出去（位置更新），再调整（后半步速度）！

### ⚡ 能量（Energy）

程序还会帮你计算各种能量，画出漂亮的能量图：

- 动能（蓝色）—— 运动的能量，速度越快越大
- 重力势能（绿色）—— 位置越高越大
- 弹性势能（橙色）—— 弹簧拉得越长越大
- 万有引力势能（紫色）—— 星星之间的引力势能
- 总能量（红色虚线）—— 所有能量加起来，理论上应该是不变的

💡 核心思想：能量守恒！ 如果没有外力干扰，总能量应该保持不变。 动能和势能之间互相转换——像荡秋千一样，荡到最高点速度最慢（动能最小、势能最大）， 荡到最低点速度最快（动能最大、势能最小）。

## 🚀 第一次运行

让我们来运行第一个模拟——两个小球用弹簧连着，在重力场中下落。

### 运行命令

    终端py -3 examples/case01/run_dynamics.py

你会看到：

1. 终端里跳出进度条 `|[compute] 计算中: 100%|` —— 电脑正在算
2. 然后弹出一个窗口，里面有 9 张图（位置、速度、能量）
3. 最后会生成动画文件

📈 这里会显示轨迹图：x-t, y-t, z-t, vx-t, vy-t, vz-t 和能量图
（运行程序后就能看到啦！）

### 只看不画图

如果不想看图片（比如在服务器上跑），加个 `--no-plot` 就行：

    终端py -3 examples/case01/run_dynamics.py --no-plot

### 输出文件

运行完后在 examples/case01/output/ 里会生成：

文件名 | 内容
--- | ---
trajectory.txt | 所有小球的全部轨迹数据（很大的文件）
display.txt | 抽帧后的显示数据（动画用）
trajectory_plots.png | 轨迹和能量图
dynamics.log | 运行日志（看看电脑算了多长时间）

## ⚙️ 调参数

所有参数都在 input.txt 里（注意：虽然是 .txt 后缀，但内容是 YAML 格式）。

### 最简单的改动

试试改这几个参数，看看效果有什么不同：

改变重力大小

    input.txtG: [0.0, 0.0, -9.8]    # 改成更大的数字，比如 -20

G 的 3 个数字分别对应 x、y、z 方向的重力分量。

把 z 方向改成 -50，小球"叮"一下就掉下去了！

改变弹簧硬度

    bond.txtk1 100.0 2.0

中间那个数字是弹簧的劲度系数（k），越大弹簧越硬。改成 1000 试试？

改变步长

    input.txtDT: 0.001         # 时间步长（秒）

DT 越小计算越精确，但跑得越慢。试试 0.0001 看看效果？

### 各种力开关

程序里每种力都可以独立开关：

    input.txt# ── 力开关（0=关闭, 1=开启）──────────────────
    gravity_field: 1         # 均匀重力场
    gravity_interaction: 0   # 原子间万有引力
    elastic_force: 1         # 弹簧键力
    damping_force: 0         # 阻尼（阻力）

💡 玩一玩：
- 关掉重力 `gravity_field: 0` → 小球就飘在空中了
- 打开万有引力 `gravity_interaction: 1` → 两个小球会互相吸引
- 打开阻尼 `damping_force: 1` → 小球会慢慢停下来

### 坐标文件

coord.txt 存放每个小球（原子）的初始位置和速度：

    coord.txtn mass radius x    y z vx vy vz  fix_x fix_y fix_z
    1 1    0.28  -1   0 0 0  0  0  0     0     0     0
    2 1    0.28   1   0 1 0  0  0  0     0     0     0

列名 | 含义
--- | ---
`n` | 小球编号
`mass` | 质量（越大越「重」，越不容易被推动）
`radius` | 半径（画出来的大小）
`x y z` | 初始位置坐标
`vx vy vz` | 初始速度
`fix_x fix_y fix_z` | 固定约束（1=锁定该方向不动，0=自由运动）

⚠️ 注意：`mass` 和 `radius` 必须 > 0。 如果设置了 `fix_x: 1`，那这个小球在 x 方向上就「钉死」了，拉不动。

## 🧪 动手实验

以下实验可以帮你理解不同的物理概念。每个实验都告诉你怎么改参数。

### 实验 1：自由落体

🎯 目标：观察小球在重力场中下落的过程，验证自由落体公式。
操作：

1. 把 coord.txt 改成只有 1 个原子，位置 `0 0 10`，速度全 0
2. 设 `gravity_field: 1`，关闭其他所有力
3. 运行 `py -3 examples/case01/run_dynamics.py`
4. 观察 z-t 图（z 坐标随时间变化）—— 应该是一条抛物线！

🤔 想一想：根据物理公式 z = ½gt²，你能从图中算出重力加速度 g 吗？

### 实验 2：弹簧振子

🎯 目标：观察弹簧振子的简谐振动。
操作：

1. 放两个原子，用弹簧连起来
2. 关掉重力 `gravity_field: 0`，打开 `elastic_force: 1`
3. 把其中一个原子拉远一点（改 coord.txt 的初始位置）
4. 观察两个小球来回振动

🤔 想一想：弹性势能和动能是怎么互相转换的？看看能量图，橙色线和蓝色线的变化规律。

### 实验 3：双星绕转

🎯 目标：模拟两颗星球在万有引力下互相绕转。
操作：

1. 放两个原子，给它们不同的质量（比如 10 和 1）
2. 关掉所有其他力，只打开 `gravity_interaction: 1`
3. 给轻的原子一个切向初速度（比如 `vx: 0 vy: 1.5 vz: 0`）
4. 观察轻的原子绕着重的原子转！

🤔 想一想：这和太阳系中行星绕太阳转的原理是一样的吗？哪个原子是「太阳」？

### 实验 4：单摆

🎯 目标：用固定约束做一个单摆。
操作：

1. 放两个原子：原子 1 在 `(0, 0, 5)`，原子 2 在 `(0, 0, 0)`
2. 原子 1 设 `fix_x: 1 fix_y: 1 fix_z: 1`（钉在天花板上）
3. 用弹簧连接两个原子
4. 打开重力，运行看效果 — 下面的原子会像摆锤一样摆动！

## 🔬 高手进阶

### 改变积分方法

程序支持 4 种计算方法，精度和速度不一样：

    input.txtmethod: leapfrog   # 可选: explicit_euler | implicit_euler | midpoint | leapfrog

方法 | 精度 | 特点
--- | --- | ---
`explicit_euler` | ⭐ | 最简单的方法，不精确但快
`implicit_euler` | ⭐⭐ | 比显式欧拉稳定一些
`midpoint` | ⭐⭐⭐ | 中点法，精度不错
`leapfrog` | ⭐⭐⭐⭐ | 默认方法，精度最高，还能很好地保持能量守恒

💡 试试：把 `method` 改成 `explicit_euler`，关掉所有阻尼，看能量图—— 你会发现总能量（红色虚线）慢慢增加，因为显式欧拉法不守恒能量！ 再换回 `leapfrog`，总能量几乎是一条水平线！

### 换成 C 语言引擎

Python 版本跑大模拟可能会慢。程序还支持用 C 语言引擎来加速：

    input.txtengine: c    # 改成 c  就用 C 引擎，比 Python 快 26 倍！

⚠️ 前提：需要先安装 C 编译器（gcc）。Windows 上推荐用 MSYS2 + MinGW64， 具体步骤见 INSTALL.md。

### 调整模拟规模

    input.txtNT: 100000       # 总步数（越大模拟时间越长）
    DT: 0.001         # 每步的时间（秒）
    NSTEP: 100        # 抽帧间隔（每 NSTEP 步记录一帧）
    T_total: 100.0    # 总模拟时间（秒），程序会自动计算 NT = T_total / DT

### 3D 动画

装好 VisPy 和 PyQt5 还能看 3D 动画：

    终端pip install vispy PyQt5
    py -3 draw.py examples/case01/output

出现 3D 窗口后，可以用鼠标拖拽旋转视角！

## ❓ 常见问题

Q: 报错 "pip 不是内部或外部命令"？

试试 `py -3 -m pip install ...`。Windows 上有时需要这样用。

Q: 为什么我改了参数但结果没变？

检查一下 `force_calc: 1` 有没有设置。如果 `force_calc: 0`，程序会使用缓存的结果。 或者把 `force_calc` 改成 1 强制重新计算。

Q: 总能量曲线为什么不是完全水平的？

因为程序用了硬壁边界（小球碰到盒子壁会弹回来），这种"碰撞"会导致微小的能量损失。 这是正常的物理现象，不是 Bug。如果用软壁边界会好很多。

Q: 为什么我的动画闪一下就没了？

先确认装好了 `vispy` 和 `PyQt5`：`pip install vispy PyQt5`。如果还是不行， 直接在终端运行 `py -3 draw.py examples/case01/output` 看错误信息。

Q: 为什么 C/C++/Fortran 引擎有"两个进度条"？

之前确实有两个，但现在已经修好了！外部引擎只会显示一个 `tqdm` 进度条， 引擎自己的输出被静默收集到日志文件里了。

Q: 我想模拟更多的原子，怎么加？

在 coord.txt 里增加行就可以。每行一个原子。 如果原子之间有弹簧连接，还要在 connection.txt 和 bond.txt 里添加对应的键。