docs: 更新 examples/Readme.md 并新增 Readme.html
- 覆盖全部 10 个案例(原 Readme 只到 case06) - 新增案例选择指南表格 - Readme.html 为深色主题独立 HTML 页面 (含卡片布局、标签分类、代码高亮、响应式设计) - 各案例详情对齐最新配置参数
This commit is contained in:
@@ -0,0 +1,436 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Dynamics 示例案例总览</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #0d1117;
|
||||
--surface: #161b22;
|
||||
--border: #30363d;
|
||||
--text: #c9d1d9;
|
||||
--text-dim: #8b949e;
|
||||
--accent: #58a6ff;
|
||||
--green: #3fb950;
|
||||
--orange: #d29922;
|
||||
--red: #f85149;
|
||||
}
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans SC", Helvetica, Arial, sans-serif;
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
line-height: 1.6;
|
||||
padding: 40px 24px;
|
||||
}
|
||||
.container { max-width: 960px; margin: 0 auto; }
|
||||
|
||||
h1 { font-size: 2rem; margin-bottom: 8px; color: #f0f6fc; }
|
||||
h1 small { font-size: 1rem; color: var(--text-dim); font-weight: 400; }
|
||||
.subtitle { color: var(--text-dim); margin-bottom: 32px; }
|
||||
|
||||
h2 {
|
||||
font-size: 1.4rem;
|
||||
margin-top: 40px;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
color: #f0f6fc;
|
||||
}
|
||||
|
||||
/* 案例总览表格 */
|
||||
.case-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||
gap: 16px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
.case-card {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
transition: border-color 0.2s, transform 0.2s;
|
||||
}
|
||||
.case-card:hover {
|
||||
border-color: var(--accent);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
.case-card .num {
|
||||
display: inline-block;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
background: var(--accent);
|
||||
color: #0d1117;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.case-card h3 {
|
||||
font-size: 1.05rem;
|
||||
margin-bottom: 6px;
|
||||
color: #f0f6fc;
|
||||
}
|
||||
.case-card p {
|
||||
font-size: 0.875rem;
|
||||
color: var(--text-dim);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.case-card .meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
.tag {
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.tag-python { background: #3572A533; color: #3572A5; }
|
||||
.tag-c { background: #55555533; color: #aaa; }
|
||||
.tag-fortran { background: #73422233; color: #e9954a; }
|
||||
.tag-gravity { background: #d2992233; color: var(--orange); }
|
||||
.tag-spring { background: #3fb95033; color: var(--green); }
|
||||
.tag-drive { background: #58a6ff33; color: var(--accent); }
|
||||
.tag-warning { background: #f8514933; color: var(--red); }
|
||||
|
||||
/* 详情区域 */
|
||||
.detail-card {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
padding: 20px 24px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.detail-card h3 {
|
||||
font-size: 1.1rem;
|
||||
margin-bottom: 8px;
|
||||
color: #f0f6fc;
|
||||
}
|
||||
.detail-card h3 a { color: var(--accent); text-decoration: none; }
|
||||
.detail-card h3 a:hover { text-decoration: underline; }
|
||||
.detail-card p { color: var(--text-dim); margin-bottom: 8px; }
|
||||
.detail-card ul {
|
||||
list-style: none;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.detail-card li { font-size: 0.8rem; }
|
||||
.detail-card .highlight {
|
||||
background: #1f242e;
|
||||
border-left: 3px solid var(--accent);
|
||||
padding: 8px 12px;
|
||||
margin-top: 8px;
|
||||
border-radius: 0 4px 4px 0;
|
||||
font-size: 0.875rem;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
/* 使用指南 */
|
||||
.guide {
|
||||
background: #1f242e;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
padding: 20px 24px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
.guide h3 { color: #f0f6fc; margin-bottom: 12px; }
|
||||
.guide code {
|
||||
display: block;
|
||||
background: #0d1117;
|
||||
padding: 12px 16px;
|
||||
border-radius: 6px;
|
||||
font-family: "SF Mono", "Fira Code", monospace;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 12px;
|
||||
color: var(--green);
|
||||
}
|
||||
.guide table { width: 100%; border-collapse: collapse; font-size: 0.875rem; }
|
||||
.guide th, .guide td {
|
||||
text-align: left;
|
||||
padding: 8px 12px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.guide th { color: var(--text-dim); font-weight: 600; }
|
||||
.guide td:first-child { color: var(--accent); font-weight: 500; }
|
||||
|
||||
@media (max-width: 640px) {
|
||||
body { padding: 16px; }
|
||||
.case-grid { grid-template-columns: 1fr; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
|
||||
<h1>Dynamics 示例案例 <small>v2.0</small></h1>
|
||||
<p class="subtitle">10 个从简单到复杂的物理模拟案例,展示分子动力学模拟框架的多种应用场景</p>
|
||||
|
||||
<h2>📋 案例总览</h2>
|
||||
<div class="case-grid">
|
||||
|
||||
<div class="case-card">
|
||||
<span class="num">01</span>
|
||||
<h3>双粒子弹簧系统</h3>
|
||||
<p>两个原子由弹簧连接,在重力场中运动</p>
|
||||
<div class="meta">
|
||||
<span class="tag tag-python">Python</span>
|
||||
<span class="tag tag-spring">弹簧</span>
|
||||
<span class="tag tag-gravity">重力</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="case-card">
|
||||
<span class="num">02</span>
|
||||
<h3>行星运动</h3>
|
||||
<p>地球绕太阳椭圆公转(万有引力)</p>
|
||||
<div class="meta">
|
||||
<span class="tag tag-python">Python</span>
|
||||
<span class="tag tag-gravity">万有引力</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="case-card">
|
||||
<span class="num">03</span>
|
||||
<h3>日地月系统(失稳)</h3>
|
||||
<p>三体系统参数不当导致轨道发散</p>
|
||||
<div class="meta">
|
||||
<span class="tag tag-python">Python</span>
|
||||
<span class="tag tag-gravity">万有引力</span>
|
||||
<span class="tag tag-warning">失败案例</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="case-card">
|
||||
<span class="num">04</span>
|
||||
<h3>日地月系统(稳定)</h3>
|
||||
<p>三体系统稳定椭圆轨道</p>
|
||||
<div class="meta">
|
||||
<span class="tag tag-python">Python</span>
|
||||
<span class="tag tag-gravity">万有引力</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="case-card">
|
||||
<span class="num">05</span>
|
||||
<h3>一维原子链纵波</h3>
|
||||
<p>驱动原子 1 沿 x 振动,产生纵波传播</p>
|
||||
<div class="meta">
|
||||
<span class="tag tag-python">Python</span>
|
||||
<span class="tag tag-spring">弹簧</span>
|
||||
<span class="tag tag-drive">驱动力</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="case-card">
|
||||
<span class="num">06</span>
|
||||
<h3>一维原子链横波</h3>
|
||||
<p>带阻尼的横波传播(FPU 非线性)</p>
|
||||
<div class="meta">
|
||||
<span class="tag tag-c">C 引擎</span>
|
||||
<span class="tag tag-spring">弹簧</span>
|
||||
<span class="tag tag-drive">驱动力</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="case-card">
|
||||
<span class="num">07</span>
|
||||
<h3>一维链横波·双端驱动</h3>
|
||||
<p>原子 1 + 原子 120 同时驱动,波相遇干涉</p>
|
||||
<div class="meta">
|
||||
<span class="tag tag-c">C 引擎</span>
|
||||
<span class="tag tag-spring">弹簧</span>
|
||||
<span class="tag tag-drive">驱动力</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="case-card">
|
||||
<span class="num">08</span>
|
||||
<h3>双原子弹簧·C 引擎测试</h3>
|
||||
<p>2 原子快速验证 C 引擎正确性</p>
|
||||
<div class="meta">
|
||||
<span class="tag tag-c">C 引擎</span>
|
||||
<span class="tag tag-spring">弹簧</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="case-card">
|
||||
<span class="num">09</span>
|
||||
<h3>一维链纵波·Fortran 引擎</h3>
|
||||
<p>Fortran 引擎驱动的纵波传播测试</p>
|
||||
<div class="meta">
|
||||
<span class="tag tag-fortran">Fortran</span>
|
||||
<span class="tag tag-spring">弹簧</span>
|
||||
<span class="tag tag-drive">驱动力</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="case-card">
|
||||
<span class="num">10</span>
|
||||
<h3>一维链纵波·能量分析</h3>
|
||||
<p>纵波传播 + 轨迹/能量图绘制</p>
|
||||
<div class="meta">
|
||||
<span class="tag tag-c">C 引擎</span>
|
||||
<span class="tag tag-spring">弹簧</span>
|
||||
<span class="tag tag-drive">驱动力</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<h2>📖 各案例详情</h2>
|
||||
|
||||
<div class="detail-card">
|
||||
<h3><a href="./case01/">case01 — 双粒子弹簧系统</a></h3>
|
||||
<ul>
|
||||
<li class="tag tag-python">Python 引擎</li>
|
||||
<li class="tag tag-spring">弹簧键力</li>
|
||||
<li class="tag tag-gravity">重力场</li>
|
||||
</ul>
|
||||
<p>两个原子通过弹簧连接,在均匀重力场(G=[0,0,-9.8])中自由运动。展示重力作用下的耦合振动与落体运动的复合。</p>
|
||||
<div class="highlight">🔬 教学案例:算法 leapfrog,渲染 Sphere 模式,建议作为入门第一个案例</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-card">
|
||||
<h3><a href="./case02/">case02 — 行星运动</a></h3>
|
||||
<ul>
|
||||
<li class="tag tag-python">Python 引擎</li>
|
||||
<li class="tag tag-gravity">万有引力</li>
|
||||
</ul>
|
||||
<p>模拟地球绕太阳的椭圆轨道运动。大质量中心体固定,小质量体绕行。</p>
|
||||
<div class="highlight">🌍 万有引力强度 gravity_strength=100.0,leapfrog 算法确保能量守恒</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-card">
|
||||
<h3><a href="./case03/">case03 — 日地月系统(失败案例)</a></h3>
|
||||
<ul>
|
||||
<li class="tag tag-python">Python 引擎</li>
|
||||
<li class="tag tag-gravity">万有引力</li>
|
||||
<li class="tag tag-warning">失稳</li>
|
||||
</ul>
|
||||
<p>三体系统(太阳-地球-月球)。初始条件或参数设置不当,轨道不稳定。展示数值模拟中参数选择的重要性。</p>
|
||||
</div>
|
||||
|
||||
<div class="detail-card">
|
||||
<h3><a href="./case04/">case04 — 日地月系统(成功案例)</a></h3>
|
||||
<ul>
|
||||
<li class="tag tag-python">Python 引擎</li>
|
||||
<li class="tag tag-gravity">万有引力</li>
|
||||
</ul>
|
||||
<p>与 case03 相同的三体系统,但采用恰当的初始条件,地球和月球维持稳定的椭圆轨道运动。</p>
|
||||
<div class="highlight">✅ 与 case03 对比学习:初始条件对数值稳定性的影响</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-card">
|
||||
<h3><a href="./case05/">case05 — 一维原子链纵波</a></h3>
|
||||
<ul>
|
||||
<li class="tag tag-python">Python 引擎</li>
|
||||
<li class="tag tag-spring">弹簧键力</li>
|
||||
<li class="tag tag-drive">驱动力</li>
|
||||
</ul>
|
||||
<p>60 原子沿 x 轴排列。原子 1 受 x 方向驱动力,产生沿链传播的纵波(压缩波)。原子 x 自由,y/z 锁定。</p>
|
||||
<div class="highlight">📈 纵波波速快(x 方向弹簧力线性),T_total=10, NSTEP=50</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-card">
|
||||
<h3><a href="./case06/">case06 — 一维原子链横波(带阻尼)</a></h3>
|
||||
<ul>
|
||||
<li class="tag tag-c">C 引擎</li>
|
||||
<li class="tag tag-spring">弹簧键力</li>
|
||||
<li class="tag tag-drive">驱动力</li>
|
||||
</ul>
|
||||
<p>120 原子沿 x 轴排列,带横向阻尼。驱动沿 z 方向,原子 z 自由,x/y 锁定。横波传播具有 FPU 型非线性。</p>
|
||||
<div class="highlight">⚡ C 引擎高性能计算,T_total=1000, NSTEP=500,支持运动相机</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-card">
|
||||
<h3><a href="./case07/">case07 — 一维链横波·双端驱动</a></h3>
|
||||
<ul>
|
||||
<li class="tag tag-c">C 引擎</li>
|
||||
<li class="tag tag-spring">弹簧键力</li>
|
||||
<li class="tag tag-drive">驱动力</li>
|
||||
</ul>
|
||||
<p>120 原子,原子 1 和原子 120 同时受 z 方向驱动(同频率、相位差 90°),两端向中间传播的横波相遇。</p>
|
||||
<div class="highlight">🌊 波干涉演示,视觉放大 display_amp=[1,1,10] 便于观察小幅度振动</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-card">
|
||||
<h3><a href="./case08/">case08 — 双原子弹簧(C 引擎快速测试)</a></h3>
|
||||
<ul>
|
||||
<li class="tag tag-c">C 引擎</li>
|
||||
<li class="tag tag-spring">弹簧键力</li>
|
||||
</ul>
|
||||
<p>2 原子弹簧系统,T_total=100 的短时模拟。用于快速验证 C 引擎的正确性和性能。</p>
|
||||
<div class="highlight">🧪 引擎快速验证用例,无动画输出</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-card">
|
||||
<h3><a href="./case09/">case09 — 一维链纵波·Fortran 引擎</a></h3>
|
||||
<ul>
|
||||
<li class="tag tag-fortran">Fortran 引擎</li>
|
||||
<li class="tag tag-spring">弹簧键力</li>
|
||||
<li class="tag tag-drive">驱动力</li>
|
||||
</ul>
|
||||
<p>40 原子沿 x 轴排列,Fortran 引擎驱动的纵波传播测试。验证 Fortran 引擎的输出兼容性。</p>
|
||||
<div class="highlight">🔧 Fortran 引擎兼容性验证,T_total=200, NSTEP=100</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-card">
|
||||
<h3><a href="./case10/">case10 — 一维链纵波·能量分析</a></h3>
|
||||
<ul>
|
||||
<li class="tag tag-c">C 引擎</li>
|
||||
<li class="tag tag-spring">弹簧键力</li>
|
||||
<li class="tag tag-drive">驱动力</li>
|
||||
</ul>
|
||||
<p>40 原子纵波传播,支持轨迹/能量图绘制(step_plot=1)。原子 x/y/z 全部自由。</p>
|
||||
<div class="highlight">📊 能量分析演示,T_total=10, NSTEP=20</div>
|
||||
</div>
|
||||
|
||||
<h2>🚀 使用方法</h2>
|
||||
<div class="guide">
|
||||
<h3>命令行</h3>
|
||||
<code># 进入案例目录并运行<br>cd examples/case05<br>python run_dynamics.py<br><br># 仅运行模拟,跳过动画<br>python run_dynamics.py --no-plot<br><br># 手动启动 3D 动画<br>python ../../draw.py output/</code>
|
||||
|
||||
<h3>案例选择指南</h3>
|
||||
<table>
|
||||
<tr><th>目标</th><th>推荐案例</th></tr>
|
||||
<tr><td>快速上手框架</td><td>case01</td></tr>
|
||||
<tr><td>天体力学/万有引力</td><td>case02 / case04</td></tr>
|
||||
<tr><td>波动物理(纵波)</td><td>case05</td></tr>
|
||||
<tr><td>波动物理(横波/非线性/阻尼)</td><td>case06</td></tr>
|
||||
<tr><td>双端驱动/波干涉</td><td>case07</td></tr>
|
||||
<tr><td>引擎性能对比</td><td>case08 (C) / case09 (Fortran)</td></tr>
|
||||
<tr><td>能量分析</td><td>case10</td></tr>
|
||||
</table>
|
||||
|
||||
<h3>配置</h3>
|
||||
<p style="color:var(--text-dim); font-size:0.875rem;">
|
||||
每个案例的 <code>input/input.txt</code> 可配置物理参数、力开关、算法、引擎、渲染方式等。
|
||||
从 case06 起支持 <code>save_trajectory</code> 开关、摄像机初始位置、<code>display_amp</code> 视觉放大等高级功能。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<h2>📁 框架结构</h2>
|
||||
<div class="detail-card">
|
||||
<pre style="font-size:0.825rem; color:var(--text-dim); line-height:1.5;">
|
||||
dynamics/
|
||||
├── dynamics.py # 统一运行入口
|
||||
├── compute.py # Python 物理引擎
|
||||
├── draw.py # VisPy 3D 动画
|
||||
├── plot_wave.py # 波形能量图
|
||||
├── engines/ # C / C++ / Fortran 引擎
|
||||
├── examples/ # 案例目录
|
||||
│ ├── case01/ ~ case10/
|
||||
└── output/ # 默认输出目录
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
+73
-16
@@ -1,19 +1,23 @@
|
||||
# Dynamics 示例案例
|
||||
|
||||
本目录包含 6 个从简单到复杂的物理模拟案例,均基于 `../dynamics.py` 框架运行。
|
||||
本目录包含 10 个从简单到复杂的物理模拟案例,均基于 `../dynamics.py` 框架运行。
|
||||
|
||||
---
|
||||
|
||||
## 案例一览
|
||||
|
||||
| 案例 | 标题 | 简介 | 原子数 | 力类型 |
|
||||
|---|---|---|---|---|
|
||||
| [case01](./case01/) | **双粒子弹簧系统** | 两个原子由弹簧连接,在重力场中运动 | 2 | 重力 + 弹簧 |
|
||||
| [case02](./case02/) | **行星运动** | 地球绕太阳椭圆公转(万有引力) | 2 | 万有引力 |
|
||||
| [case03](./case03/) | **日地月系统(失败)** | 地球绕太阳、月球绕地球,参数不当导致失稳 | 3 | 万有引力 |
|
||||
| [case04](./case04/) | **日地月系统(成功)** | 地球绕太阳、月球绕地球,稳定轨道 | 3 | 万有引力 |
|
||||
| [case05](./case05/) | **一维原子链纵波** | 驱动原子 1 沿 x 轴振动,产生纵波传播 | 60 | 弹簧 + 驱动力 |
|
||||
| [case06](./case06/) | **一维原子链横波** | 驱动原子 1 沿 z 轴振动,产生横波传播 | 120 | 弹簧 + 驱动力 |
|
||||
| 案例 | 标题 | 简介 | 原子数 | 引擎 | 力类型 |
|
||||
|------|------|------|--------|------|--------|
|
||||
| [case01](./case01/) | **双粒子弹簧系统** | 两个原子由弹簧连接,在重力场中运动 | 2 | Python | 重力 + 弹簧 |
|
||||
| [case02](./case02/) | **行星运动** | 地球绕太阳椭圆公转(万有引力) | 2 | Python | 万有引力 |
|
||||
| [case03](./case03/) | **日地月系统(失稳)** | 地球绕太阳、月球绕地球,参数不当导致失稳 | 3 | Python | 万有引力 |
|
||||
| [case04](./case04/) | **日地月系统(稳定)** | 地球绕太阳、月球绕地球,稳定轨道 | 3 | Python | 万有引力 |
|
||||
| [case05](./case05/) | **一维原子链纵波** | 驱动原子 1 沿 x 轴振动,产生纵波传播 | 60 | Python | 弹簧 + 驱动力 |
|
||||
| [case06](./case06/) | **一维原子链横波(阻尼)** | 驱动原子 1 沿 z 轴振动,带阻尼的横波传播 | 120 | C | 弹簧 + 阻尼 + 驱动力 |
|
||||
| [case07](./case07/) | **一维原子链横波(双端驱动)** | 原子 1 和原子 120 同时受 z 方向驱动 | 120 | C | 弹簧 + 阻尼 + 驱动力 |
|
||||
| [case08](./case08/) | **双原子弹簧(C 引擎测试)** | 两个原子弹簧系统,C 引擎快速验证 | 2 | C | 弹簧 + 阻尼 + 驱动力 |
|
||||
| [case09](./case09/) | **一维链纵波(Fortran 引擎)** | Fortran 引擎驱动的纵波传播测试 | 40 | Fortran | 弹簧 + 驱动力 |
|
||||
| [case10](./case10/) | **一维链纵波(能量分析)** | 纵波传播 + 轨迹/能量图绘制 | 40 | C | 弹簧 + 驱动力 |
|
||||
|
||||
---
|
||||
|
||||
@@ -26,14 +30,16 @@
|
||||
- **力开关**:重力场开,弹簧键力开
|
||||
- **算法**:leapfrog(蛙跳法)
|
||||
- **物理**:重力 m·g + 弹簧胡克力
|
||||
- **渲染**:Sphere 模式(精细网格球体)
|
||||
|
||||
### case02 — 行星运动
|
||||
|
||||
模拟地球绕太阳的椭圆轨道运动(一个固定大质量中心体 + 一个绕行小质量体)。采用万有引力相互作用。
|
||||
|
||||
- **力开关**:万有引力开(含强度参数)
|
||||
- **力开关**:万有引力开(含强度参数 `gravity_strength: 100.0`)
|
||||
- **算法**:leapfrog(蛙跳法)
|
||||
- **物理**:牛顿万有引力 F = G·m₁·m₂/r²
|
||||
- **渲染**:Sphere 模式
|
||||
|
||||
### case03 — 日地月系统(失败案例)
|
||||
|
||||
@@ -60,14 +66,53 @@
|
||||
- **波速**:快(x 方向弹簧力为线性)
|
||||
- **渲染**:Marker 模式(GPU 实例化,60 原子)
|
||||
|
||||
### case06 — 一维原子链横波
|
||||
### case06 — 一维原子链横波(带阻尼)
|
||||
|
||||
120 个原子沿 x 轴等间距排列(间距 1),相邻原子用弹簧(k=1.0, L₀=1.0)连接。驱动力沿 z 方向 `z(t)=0.5·cos(2π·0.1·t+90°)`,原子 z 方向自由(fix_z=0),x/y 锁定。振动在横向传播,形成**横波**。
|
||||
120 个原子沿 x 轴等间距排列(间距 1),相邻原子用弹簧(k=1.0, L₀=1.0)连接,带横向阻尼(B=[0.01, 0, 0.01])。驱动在 z 方向 `z(t)=0.5·cos(2π·0.1·t+90°)`,原子 z 方向自由(fix_z=0),x/y 锁定。
|
||||
|
||||
- **力开关**:弹簧键力开,驱动力开
|
||||
- **力开关**:弹簧键力开,驱动力开,阻尼开
|
||||
- **算法**:leapfrog(蛙跳法)
|
||||
- **引擎**:C(高性能)
|
||||
- **参数**:T_total=1000, NSTEP=500
|
||||
- **波速**:慢(z 方向弹簧力呈几何非线性,类似 FPU 系统)
|
||||
- **渲染**:Marker 模式(GPU 实例化,120 原子)
|
||||
|
||||
### case07 — 一维原子链横波(双端驱动)
|
||||
|
||||
120 个原子沿 x 轴排列,原子 1 **和**原子 120 同时受 z 方向驱动力驱动(频率相同,初相位错开 90°),产生两端向中间传播的横波相遇。
|
||||
|
||||
- **力开关**:弹簧键力开,驱动力开,阻尼开
|
||||
- **引擎**:C
|
||||
- **参数**:T_total=1000, NSTEP=500
|
||||
- **视觉放大**:z 方向位移放大 10 倍(`display_amp: [1, 1, 10]`),便于观察小幅度横波
|
||||
|
||||
### case08 — 双原子弹簧(C 引擎快速测试)
|
||||
|
||||
2 个原子的简单弹簧系统,用于快速验证 C 引擎的正确性和性能。T_total 仅为 100s。
|
||||
|
||||
- **力开关**:弹簧键力开,驱动力开,阻尼开
|
||||
- **引擎**:C
|
||||
- **用途**:引擎验证 / 调试
|
||||
- **视觉放大**:z 方向位移放大 10 倍
|
||||
- **动画**:关闭(step_animation=0),仅输出波形图
|
||||
|
||||
### case09 — 一维链纵波(Fortran 引擎)
|
||||
|
||||
40 个原子沿 x 轴排列,使用 **Fortran 引擎**驱动的纵波传播模拟。验证 Fortran 引擎的输出兼容性和性能。
|
||||
|
||||
- **力开关**:弹簧键力开,驱动力开,阻尼关
|
||||
- **引擎**:Fortran
|
||||
- **参数**:T_total=200, NSTEP=100
|
||||
- **视觉放大**:z 方向位移放大 10 倍
|
||||
|
||||
### case10 — 一维链纵波(能量分析)
|
||||
|
||||
40 个原子沿 x 轴排列,纵波传播。与 case05 相比,x/y/z 全部自由(fix_x/y/z 均为 0),物理行为更复杂。支持轨迹/能量图绘制(step_plot=1)。
|
||||
|
||||
- **力开关**:弹簧键力开,驱动力开,阻尼关
|
||||
- **引擎**:C
|
||||
- **参数**:T_total=10, NSTEP=20
|
||||
- **视觉放大**:z 方向位移放大 10 倍
|
||||
- **动画**:关闭(step_animation=0),仅输出轨迹/能量图
|
||||
|
||||
---
|
||||
|
||||
@@ -77,7 +122,7 @@
|
||||
# 进入任意案例目录
|
||||
cd examples/case05
|
||||
|
||||
# 完整运行(模拟 + 采样 + 3D 动画)
|
||||
# 完整运行(模拟 + 3D 动画)
|
||||
python run_dynamics.py
|
||||
|
||||
# 仅运行模拟,跳过 3D 动画
|
||||
@@ -89,6 +134,18 @@ python ../../draw.py output/
|
||||
|
||||
每个案例的 `input/input.txt` 中可配置所有物理参数、力开关、算法、渲染方式等。
|
||||
|
||||
## 案例选择指南
|
||||
|
||||
| 你想做什么 | 推荐案例 |
|
||||
|-----------|---------|
|
||||
| 快速上手、理解基本框架 | case01 |
|
||||
| 天体力学 / 万有引力 | case02 / case04 |
|
||||
| 波动物理(纵波) | case05 |
|
||||
| 波动物理(横波、非线性、阻尼) | case06 |
|
||||
| 双端驱动/波干涉 | case07 |
|
||||
| 对比不同引擎性能 | case08 (C) / case09 (Fortran) |
|
||||
| 能量分析 | case10 |
|
||||
|
||||
## 框架结构
|
||||
|
||||
```
|
||||
@@ -101,6 +158,6 @@ dynamics/
|
||||
├── examples/ # 案例(本目录)
|
||||
│ ├── case01/
|
||||
│ ├── ...
|
||||
│ └── case06/
|
||||
│ └── case10/
|
||||
└── output/ # 默认输出目录
|
||||
```
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
bond_name k rest_length
|
||||
k1 50.0 1.0
|
||||
bond_name k rest_length
|
||||
k1 10.0 1.0
|
||||
|
||||
+120
-120
@@ -1,121 +1,121 @@
|
||||
n mass radius x y z vx vy vz fix_x fix_y fix_z
|
||||
1 1 0.1 0 0 0 0 0 0 1 1 0
|
||||
2 1 0.1 1 0 0 0 0 0 1 1 0
|
||||
3 1 0.1 2 0 0 0 0 0 1 1 0
|
||||
4 1 0.1 3 0 0 0 0 0 1 1 0
|
||||
5 1 0.1 4 0 0 0 0 0 1 1 0
|
||||
6 1 0.1 5 0 0 0 0 0 1 1 0
|
||||
7 1 0.1 6 0 0 0 0 0 1 1 0
|
||||
8 1 0.1 7 0 0 0 0 0 1 1 0
|
||||
9 1 0.1 8 0 0 0 0 0 1 1 0
|
||||
10 1 0.1 9 0 0 0 0 0 1 1 0
|
||||
11 1 0.1 10 0 0 0 0 0 1 1 0
|
||||
12 1 0.1 11 0 0 0 0 0 1 1 0
|
||||
13 1 0.1 12 0 0 0 0 0 1 1 0
|
||||
14 1 0.1 13 0 0 0 0 0 1 1 0
|
||||
15 1 0.1 14 0 0 0 0 0 1 1 0
|
||||
16 1 0.1 15 0 0 0 0 0 1 1 0
|
||||
17 1 0.1 16 0 0 0 0 0 1 1 0
|
||||
18 1 0.1 17 0 0 0 0 0 1 1 0
|
||||
19 1 0.1 18 0 0 0 0 0 1 1 0
|
||||
20 1 0.1 19 0 0 0 0 0 1 1 0
|
||||
21 1 0.1 20 0 0 0 0 0 1 1 0
|
||||
22 1 0.1 21 0 0 0 0 0 1 1 0
|
||||
23 1 0.1 22 0 0 0 0 0 1 1 0
|
||||
24 1 0.1 23 0 0 0 0 0 1 1 0
|
||||
25 1 0.1 24 0 0 0 0 0 1 1 0
|
||||
26 1 0.1 25 0 0 0 0 0 1 1 0
|
||||
27 1 0.1 26 0 0 0 0 0 1 1 0
|
||||
28 1 0.1 27 0 0 0 0 0 1 1 0
|
||||
29 1 0.1 28 0 0 0 0 0 1 1 0
|
||||
30 1 0.1 29 0 0 0 0 0 1 1 0
|
||||
31 1 0.1 30 0 0 0 0 0 1 1 0
|
||||
32 1 0.1 31 0 0 0 0 0 1 1 0
|
||||
33 1 0.1 32 0 0 0 0 0 1 1 0
|
||||
34 1 0.1 33 0 0 0 0 0 1 1 0
|
||||
35 1 0.1 34 0 0 0 0 0 1 1 0
|
||||
36 1 0.1 35 0 0 0 0 0 1 1 0
|
||||
37 1 0.1 36 0 0 0 0 0 1 1 0
|
||||
38 1 0.1 37 0 0 0 0 0 1 1 0
|
||||
39 1 0.1 38 0 0 0 0 0 1 1 0
|
||||
40 1 0.1 39 0 0 0 0 0 1 1 0
|
||||
41 1 0.1 40 0 0 0 0 0 1 1 0
|
||||
42 1 0.1 41 0 0 0 0 0 1 1 0
|
||||
43 1 0.1 42 0 0 0 0 0 1 1 0
|
||||
44 1 0.1 43 0 0 0 0 0 1 1 0
|
||||
45 1 0.1 44 0 0 0 0 0 1 1 0
|
||||
46 1 0.1 45 0 0 0 0 0 1 1 0
|
||||
47 1 0.1 46 0 0 0 0 0 1 1 0
|
||||
48 1 0.1 47 0 0 0 0 0 1 1 0
|
||||
49 1 0.1 48 0 0 0 0 0 1 1 0
|
||||
50 1 0.1 49 0 0 0 0 0 1 1 0
|
||||
51 1 0.1 50 0 0 0 0 0 1 1 0
|
||||
52 1 0.1 51 0 0 0 0 0 1 1 0
|
||||
53 1 0.1 52 0 0 0 0 0 1 1 0
|
||||
54 1 0.1 53 0 0 0 0 0 1 1 0
|
||||
55 1 0.1 54 0 0 0 0 0 1 1 0
|
||||
56 1 0.1 55 0 0 0 0 0 1 1 0
|
||||
57 1 0.1 56 0 0 0 0 0 1 1 0
|
||||
58 1 0.1 57 0 0 0 0 0 1 1 0
|
||||
59 1 0.1 58 0 0 0 0 0 1 1 0
|
||||
60 1 0.1 59 0 0 0 0 0 1 1 0
|
||||
61 1 0.1 60 0 0 0 0 0 1 1 0
|
||||
62 1 0.1 61 0 0 0 0 0 1 1 0
|
||||
63 1 0.1 62 0 0 0 0 0 1 1 0
|
||||
64 1 0.1 63 0 0 0 0 0 1 1 0
|
||||
65 1 0.1 64 0 0 0 0 0 1 1 0
|
||||
66 1 0.1 65 0 0 0 0 0 1 1 0
|
||||
67 1 0.1 66 0 0 0 0 0 1 1 0
|
||||
68 1 0.1 67 0 0 0 0 0 1 1 0
|
||||
69 1 0.1 68 0 0 0 0 0 1 1 0
|
||||
70 1 0.1 69 0 0 0 0 0 1 1 0
|
||||
71 1 0.1 70 0 0 0 0 0 1 1 0
|
||||
72 1 0.1 71 0 0 0 0 0 1 1 0
|
||||
73 1 0.1 72 0 0 0 0 0 1 1 0
|
||||
74 1 0.1 73 0 0 0 0 0 1 1 0
|
||||
75 1 0.1 74 0 0 0 0 0 1 1 0
|
||||
76 1 0.1 75 0 0 0 0 0 1 1 0
|
||||
77 1 0.1 76 0 0 0 0 0 1 1 0
|
||||
78 1 0.1 77 0 0 0 0 0 1 1 0
|
||||
79 1 0.1 78 0 0 0 0 0 1 1 0
|
||||
80 1 0.1 79 0 0 0 0 0 1 1 0
|
||||
81 1 0.1 80 0 0 0 0 0 1 1 0
|
||||
82 1 0.1 81 0 0 0 0 0 1 1 0
|
||||
83 1 0.1 82 0 0 0 0 0 1 1 0
|
||||
84 1 0.1 83 0 0 0 0 0 1 1 0
|
||||
85 1 0.1 84 0 0 0 0 0 1 1 0
|
||||
86 1 0.1 85 0 0 0 0 0 1 1 0
|
||||
87 1 0.1 86 0 0 0 0 0 1 1 0
|
||||
88 1 0.1 87 0 0 0 0 0 1 1 0
|
||||
89 1 0.1 88 0 0 0 0 0 1 1 0
|
||||
90 1 0.1 89 0 0 0 0 0 1 1 0
|
||||
91 1 0.1 90 0 0 0 0 0 1 1 0
|
||||
92 1 0.1 91 0 0 0 0 0 1 1 0
|
||||
93 1 0.1 92 0 0 0 0 0 1 1 0
|
||||
94 1 0.1 93 0 0 0 0 0 1 1 0
|
||||
95 1 0.1 94 0 0 0 0 0 1 1 0
|
||||
96 1 0.1 95 0 0 0 0 0 1 1 0
|
||||
97 1 0.1 96 0 0 0 0 0 1 1 0
|
||||
98 1 0.1 97 0 0 0 0 0 1 1 0
|
||||
99 1 0.1 98 0 0 0 0 0 1 1 0
|
||||
100 1 0.1 99 0 0 0 0 0 1 1 0
|
||||
101 1 0.1 100 0 0 0 0 0 1 1 0
|
||||
102 1 0.1 101 0 0 0 0 0 1 1 0
|
||||
103 1 0.1 102 0 0 0 0 0 1 1 0
|
||||
104 1 0.1 103 0 0 0 0 0 1 1 0
|
||||
105 1 0.1 104 0 0 0 0 0 1 1 0
|
||||
106 1 0.1 105 0 0 0 0 0 1 1 0
|
||||
107 1 0.1 106 0 0 0 0 0 1 1 0
|
||||
108 1 0.1 107 0 0 0 0 0 1 1 0
|
||||
109 1 0.1 108 0 0 0 0 0 1 1 0
|
||||
110 1 0.1 109 0 0 0 0 0 1 1 0
|
||||
111 1 0.1 110 0 0 0 0 0 1 1 0
|
||||
112 1 0.1 111 0 0 0 0 0 1 1 0
|
||||
113 1 0.1 112 0 0 0 0 0 1 1 0
|
||||
114 1 0.1 113 0 0 0 0 0 1 1 0
|
||||
115 1 0.1 114 0 0 0 0 0 1 1 0
|
||||
116 1 0.1 115 0 0 0 0 0 1 1 0
|
||||
117 1 0.1 116 0 0 0 0 0 1 1 0
|
||||
118 1 0.1 117 0 0 0 0 0 1 1 0
|
||||
119 1 0.1 118 0 0 0 0 0 1 1 0
|
||||
120 1 0.1 119 0 0 0 0 0 1 1 1
|
||||
1 1 0.1 0 0 0 0 0 0 0 1 0
|
||||
2 1 0.1 1 0 0 0 0 0 0 1 0
|
||||
3 1 0.1 2 0 0 0 0 0 0 1 0
|
||||
4 1 0.1 3 0 0 0 0 0 0 1 0
|
||||
5 1 0.1 4 0 0 0 0 0 0 1 0
|
||||
6 1 0.1 5 0 0 0 0 0 0 1 0
|
||||
7 1 0.1 6 0 0 0 0 0 0 1 0
|
||||
8 1 0.1 7 0 0 0 0 0 0 1 0
|
||||
9 1 0.1 8 0 0 0 0 0 0 1 0
|
||||
10 1 0.1 9 0 0 0 0 0 0 1 0
|
||||
11 1 0.1 10 0 0 0 0 0 0 1 0
|
||||
12 1 0.1 11 0 0 0 0 0 0 1 0
|
||||
13 1 0.1 12 0 0 0 0 0 0 1 0
|
||||
14 1 0.1 13 0 0 0 0 0 0 1 0
|
||||
15 1 0.1 14 0 0 0 0 0 0 1 0
|
||||
16 1 0.1 15 0 0 0 0 0 0 1 0
|
||||
17 1 0.1 16 0 0 0 0 0 0 1 0
|
||||
18 1 0.1 17 0 0 0 0 0 0 1 0
|
||||
19 1 0.1 18 0 0 0 0 0 0 1 0
|
||||
20 1 0.1 19 0 0 0 0 0 0 1 0
|
||||
21 1 0.1 20 0 0 0 0 0 0 1 0
|
||||
22 1 0.1 21 0 0 0 0 0 0 1 0
|
||||
23 1 0.1 22 0 0 0 0 0 0 1 0
|
||||
24 1 0.1 23 0 0 0 0 0 0 1 0
|
||||
25 1 0.1 24 0 0 0 0 0 0 1 0
|
||||
26 1 0.1 25 0 0 0 0 0 0 1 0
|
||||
27 1 0.1 26 0 0 0 0 0 0 1 0
|
||||
28 1 0.1 27 0 0 0 0 0 0 1 0
|
||||
29 1 0.1 28 0 0 0 0 0 0 1 0
|
||||
30 1 0.1 29 0 0 0 0 0 0 1 0
|
||||
31 1 0.1 30 0 0 0 0 0 0 1 0
|
||||
32 1 0.1 31 0 0 0 0 0 0 1 0
|
||||
33 1 0.1 32 0 0 0 0 0 0 1 0
|
||||
34 1 0.1 33 0 0 0 0 0 0 1 0
|
||||
35 1 0.1 34 0 0 0 0 0 0 1 0
|
||||
36 1 0.1 35 0 0 0 0 0 0 1 0
|
||||
37 1 0.1 36 0 0 0 0 0 0 1 0
|
||||
38 1 0.1 37 0 0 0 0 0 0 1 0
|
||||
39 1 0.1 38 0 0 0 0 0 0 1 0
|
||||
40 1 0.1 39 0 0 0 0 0 0 1 0
|
||||
41 1 0.1 40 0 0 0 0 0 0 1 0
|
||||
42 1 0.1 41 0 0 0 0 0 0 1 0
|
||||
43 1 0.1 42 0 0 0 0 0 0 1 0
|
||||
44 1 0.1 43 0 0 0 0 0 0 1 0
|
||||
45 1 0.1 44 0 0 0 0 0 0 1 0
|
||||
46 1 0.1 45 0 0 0 0 0 0 1 0
|
||||
47 1 0.1 46 0 0 0 0 0 0 1 0
|
||||
48 1 0.1 47 0 0 0 0 0 0 1 0
|
||||
49 1 0.1 48 0 0 0 0 0 0 1 0
|
||||
50 1 0.1 49 0 0 0 0 0 0 1 0
|
||||
51 1 0.1 50 0 0 0 0 0 0 1 0
|
||||
52 1 0.1 51 0 0 0 0 0 0 1 0
|
||||
53 1 0.1 52 0 0 0 0 0 0 1 0
|
||||
54 1 0.1 53 0 0 0 0 0 0 1 0
|
||||
55 1 0.1 54 0 0 0 0 0 0 1 0
|
||||
56 1 0.1 55 0 0 0 0 0 0 1 0
|
||||
57 1 0.1 56 0 0 0 0 0 0 1 0
|
||||
58 1 0.1 57 0 0 0 0 0 0 1 0
|
||||
59 1 0.1 58 0 0 0 0 0 0 1 0
|
||||
60 1 0.1 59 0 0 0 0 0 0 1 0
|
||||
61 1 0.1 60 0 0 0 0 0 0 1 0
|
||||
62 1 0.1 61 0 0 0 0 0 0 1 0
|
||||
63 1 0.1 62 0 0 0 0 0 0 1 0
|
||||
64 1 0.1 63 0 0 0 0 0 0 1 0
|
||||
65 1 0.1 64 0 0 0 0 0 0 1 0
|
||||
66 1 0.1 65 0 0 0 0 0 0 1 0
|
||||
67 1 0.1 66 0 0 0 0 0 0 1 0
|
||||
68 1 0.1 67 0 0 0 0 0 0 1 0
|
||||
69 1 0.1 68 0 0 0 0 0 0 1 0
|
||||
70 1 0.1 69 0 0 0 0 0 0 1 0
|
||||
71 1 0.1 70 0 0 0 0 0 0 1 0
|
||||
72 1 0.1 71 0 0 0 0 0 0 1 0
|
||||
73 1 0.1 72 0 0 0 0 0 0 1 0
|
||||
74 1 0.1 73 0 0 0 0 0 0 1 0
|
||||
75 1 0.1 74 0 0 0 0 0 0 1 0
|
||||
76 1 0.1 75 0 0 0 0 0 0 1 0
|
||||
77 1 0.1 76 0 0 0 0 0 0 1 0
|
||||
78 1 0.1 77 0 0 0 0 0 0 1 0
|
||||
79 1 0.1 78 0 0 0 0 0 0 1 0
|
||||
80 1 0.1 79 0 0 0 0 0 0 1 0
|
||||
81 1 0.1 80 0 0 0 0 0 0 1 0
|
||||
82 1 0.1 81 0 0 0 0 0 0 1 0
|
||||
83 1 0.1 82 0 0 0 0 0 0 1 0
|
||||
84 1 0.1 83 0 0 0 0 0 0 1 0
|
||||
85 1 0.1 84 0 0 0 0 0 0 1 0
|
||||
86 1 0.1 85 0 0 0 0 0 0 1 0
|
||||
87 1 0.1 86 0 0 0 0 0 0 1 0
|
||||
88 1 0.1 87 0 0 0 0 0 0 1 0
|
||||
89 1 0.1 88 0 0 0 0 0 0 1 0
|
||||
90 1 0.1 89 0 0 0 0 0 0 1 0
|
||||
91 1 0.1 90 0 0 0 0 0 0 1 0
|
||||
92 1 0.1 91 0 0 0 0 0 0 1 0
|
||||
93 1 0.1 92 0 0 0 0 0 0 1 0
|
||||
94 1 0.1 93 0 0 0 0 0 0 1 0
|
||||
95 1 0.1 94 0 0 0 0 0 0 1 0
|
||||
96 1 0.1 95 0 0 0 0 0 0 1 0
|
||||
97 1 0.1 96 0 0 0 0 0 0 1 0
|
||||
98 1 0.1 97 0 0 0 0 0 0 1 0
|
||||
99 1 0.1 98 0 0 0 0 0 0 1 0
|
||||
100 1 0.1 99 0 0 0 0 0 0 1 0
|
||||
101 1 0.1 100 0 0 0 0 0 0 1 0
|
||||
102 1 0.1 101 0 0 0 0 0 0 1 0
|
||||
103 1 0.1 102 0 0 0 0 0 0 1 0
|
||||
104 1 0.1 103 0 0 0 0 0 0 1 0
|
||||
105 1 0.1 104 0 0 0 0 0 0 1 0
|
||||
106 1 0.1 105 0 0 0 0 0 0 1 0
|
||||
107 1 0.1 106 0 0 0 0 0 0 1 0
|
||||
108 1 0.1 107 0 0 0 0 0 0 1 0
|
||||
109 1 0.1 108 0 0 0 0 0 0 1 0
|
||||
110 1 0.1 109 0 0 0 0 0 0 1 0
|
||||
111 1 0.1 110 0 0 0 0 0 0 1 0
|
||||
112 1 0.1 111 0 0 0 0 0 0 1 0
|
||||
113 1 0.1 112 0 0 0 0 0 0 1 0
|
||||
114 1 0.1 113 0 0 0 0 0 0 1 0
|
||||
115 1 0.1 114 0 0 0 0 0 0 1 0
|
||||
116 1 0.1 115 0 0 0 0 0 0 1 0
|
||||
117 1 0.1 116 0 0 0 0 0 0 1 0
|
||||
118 1 0.1 117 0 0 0 0 0 0 1 0
|
||||
119 1 0.1 118 0 0 0 0 0 0 1 0
|
||||
120 1 0.1 119 0 0 0 0 0 1 1 1
|
||||
|
||||
@@ -19,10 +19,10 @@ save_trajectory: 0 # 0=不保留完整轨迹文件, 1=保留 trajectory.txt(
|
||||
|
||||
# ── 计算引擎 ──────────────────────────────────
|
||||
# 可选: python, c, cpp, fortran, java
|
||||
engine: python # 默认使用 python 引擎
|
||||
engine: c # 默认使用 python 引擎
|
||||
|
||||
# ── 盒子 ──────────────────────────────────────
|
||||
box_a: 80.0 # 立方体半边长,粒子被限制在 [-box_a, box_a]³ 内
|
||||
box_a: 300.0 # 立方体半边长,粒子被限制在 [-box_a, box_a]³ 内
|
||||
|
||||
# ── 初始构型 ──────────────────────────────────
|
||||
# 坐标文件格式:
|
||||
@@ -39,7 +39,7 @@ plot_atom: 1
|
||||
# ── 物理参数 ──────────────────────────────────
|
||||
# 三个方向分量分别对应 x, y, z
|
||||
G: [0.00, 0.00, 0.00] # 重力场分量 (m/s²)
|
||||
B: [0.02, 0.00, 0.02] # 阻尼分量
|
||||
B: [0.01, 0.00, 0.01] # 阻尼分量
|
||||
|
||||
# ── 力开关(0=关闭, 1=开启)──────────────────
|
||||
gravity_field: 0 # 均匀重力场 (G)
|
||||
@@ -66,13 +66,13 @@ warmup_steps: 0 # 默认 0(立即开始记录)
|
||||
|
||||
# 总模拟时间(秒),程序自动计算 NT = T_total / DT
|
||||
# 如果同时指定了 NT,以 NT 为准
|
||||
T_total: 100.0
|
||||
T_total: 1000.0
|
||||
|
||||
# 抽帧间隔(每 NSTEP 步取一帧用于动画)
|
||||
NSTEP: 10
|
||||
NSTEP: 500
|
||||
|
||||
# ── 时间步长 ──────────────────────────────────
|
||||
DT: 0.01 # 时间步长 (s)
|
||||
DT: 0.001 # 时间步长 (s)
|
||||
|
||||
# 抽帧范围:只保存 [sample_start, sample_end) 区间内的帧
|
||||
sample_start: null # null 表示从头开始(帧索引从 0 起)
|
||||
@@ -102,7 +102,10 @@ box_color_g: 0.80
|
||||
box_color_b: 0.85
|
||||
|
||||
# ── 摄像机初始位置 ────────────────────────────
|
||||
camera_distance: 40.0 # 摄像机到场景中心的距离
|
||||
camera_elevation: 0 # 俯仰角(度),负值=俯视
|
||||
camera_azimuth: 0 # 方位角(度)
|
||||
move_camera: 1 # 0=固定视角, 1=按 move_camera.txt 运动
|
||||
camera_distance: 120.0 # 摄像机到场景中心的距离
|
||||
camera_elevation: 0.0 # 俯仰角(度),负值=俯视
|
||||
camera_azimuth: 0.0 # 方位角(度)
|
||||
camera_center_x: 60.0 # 摄像机注视点 x
|
||||
camera_center_y: 0.0 # 摄像机注视点 y
|
||||
camera_center_z: 0.0 # 摄像机注视点 z
|
||||
move_camera: 0 # 0=固定视角, 1=按 move_camera.txt 运动
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# case06: 一维原子链横波模拟
|
||||
|
||||
60 个原子沿 x 轴排列,相邻原子用弹簧连接。原子 1 受 z 方向驱动力作用,产生沿链传播的横波。
|
||||
|
||||
## 物理设定
|
||||
|
||||
| 参数 | 值 |
|
||||
|---|---|
|
||||
| 原子数 | 120 |
|
||||
| 排列 | 沿 x 轴等间距排列,间距为 1 |
|
||||
| 约束 | 原子**沿 z 方向自由振动**(fix_x=1, fix_y=1, fix_z=0),x, y 锁定 |
|
||||
| 弹簧 | 劲度系数 k=1.0,原长 L₀=1.0 |
|
||||
| 重力 | 无 |
|
||||
| 万有引力 | 无 |
|
||||
| 阻尼 | 无 |
|
||||
| 驱动力 | 原子 1(z 方向驱动) |
|
||||
| 算法 | leapfrog(蛙跳法,能量守恒) |
|
||||
|
||||
## 驱动力
|
||||
|
||||
原子 1 的位置由 `input/driver.txt` 中的驱动力公式决定:
|
||||
|
||||
```math
|
||||
z(t) = A_z \cdot \cos(2\pi f_z t + \phi_z)
|
||||
```
|
||||
|
||||
当前参数:A_z = 0.5, f_z = 0.1 Hz, φ_z = 90°, period = all(全程驱动)。
|
||||
|
||||
## 动力学行为
|
||||
|
||||
原子 1 沿 z 方向的受迫振动通过弹簧逐次传递给相邻原子,形成沿链传播的**横波**。由于 z 方向的振动是横向的,弹簧大部分张力在 x 方向,z 方向的有效刚度是非线性的——等效于一个三次方恢复力(FPU 型非线性),因此波速较慢。
|
||||
|
||||
## 使用方法
|
||||
|
||||
```bash
|
||||
cd examples/case06
|
||||
python run_dynamics.py
|
||||
```
|
||||
|
||||
配置参数详见 `input/input.txt`,驱动力定义见 `input/driver.txt`,完整文档见 `doc/index.html`。
|
||||
@@ -0,0 +1,477 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>case06 — 一维原子链驱动力学模拟 | 物理原理 & 使用文档</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #f8f9fa;
|
||||
--card: #fff;
|
||||
--text: #1a1a2e;
|
||||
--accent: #2563eb;
|
||||
--accent-light: #dbeafe;
|
||||
--code-bg: #1e293b;
|
||||
--code-text: #e2e8f0;
|
||||
--border: #e2e8f0;
|
||||
--muted: #64748b;
|
||||
}
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Noto Sans SC", sans-serif;
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
/* ── Header ── */
|
||||
.hero {
|
||||
background: linear-gradient(135deg, #1e293b 0%, #334155 100%);
|
||||
color: #fff;
|
||||
padding: 56px 24px 48px;
|
||||
text-align: center;
|
||||
}
|
||||
.hero h1 { font-size: 2rem; font-weight: 700; letter-spacing: -0.02em; }
|
||||
.hero .subtitle {
|
||||
margin-top: 10px;
|
||||
font-size: 1.05rem;
|
||||
opacity: 0.8;
|
||||
}
|
||||
.hero .badge {
|
||||
display: inline-block;
|
||||
margin-top: 14px;
|
||||
padding: 4px 14px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255,255,255,0.12);
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
|
||||
/* ── Layout ── */
|
||||
.container { max-width: 820px; margin: 0 auto; padding: 32px 20px; }
|
||||
|
||||
section { margin-bottom: 44px; }
|
||||
h2 {
|
||||
font-size: 1.35rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 2px solid var(--accent);
|
||||
display: inline-block;
|
||||
}
|
||||
h3 {
|
||||
font-size: 1.05rem;
|
||||
font-weight: 600;
|
||||
margin: 20px 0 10px;
|
||||
}
|
||||
|
||||
p, li { margin-bottom: 10px; }
|
||||
ul, ol { padding-left: 22px; }
|
||||
strong { color: var(--accent); }
|
||||
|
||||
/* ── Cards ── */
|
||||
.card {
|
||||
background: var(--card);
|
||||
border-radius: 12px;
|
||||
padding: 20px 24px;
|
||||
margin-bottom: 16px;
|
||||
border: 1px solid var(--border);
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.04);
|
||||
}
|
||||
|
||||
/* ── Formula / Code blocks ── */
|
||||
.formula {
|
||||
background: var(--card);
|
||||
border-left: 4px solid var(--accent);
|
||||
padding: 14px 20px;
|
||||
margin: 14px 0;
|
||||
font-family: "Times New Roman", "STIX", serif;
|
||||
font-size: 1.05rem;
|
||||
overflow-x: auto;
|
||||
border-radius: 0 8px 8px 0;
|
||||
}
|
||||
code {
|
||||
background: var(--accent-light);
|
||||
padding: 2px 7px;
|
||||
border-radius: 4px;
|
||||
font-family: "JetBrains Mono", "Fira Code", monospace;
|
||||
font-size: 0.88em;
|
||||
}
|
||||
pre {
|
||||
background: var(--code-bg);
|
||||
color: var(--code-text);
|
||||
padding: 16px 20px;
|
||||
border-radius: 10px;
|
||||
overflow-x: auto;
|
||||
font-size: 0.85rem;
|
||||
line-height: 1.5;
|
||||
margin: 14px 0;
|
||||
}
|
||||
pre .cm { color: #94a3b8; font-style: italic; } /* comment */
|
||||
|
||||
/* ── Table ── */
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 14px 0;
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
th, td {
|
||||
padding: 8px 12px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
th { background: var(--accent-light); font-weight: 600; }
|
||||
|
||||
/* ── TOC ── */
|
||||
.toc { counter-reset: toc; }
|
||||
.toc li { counter-increment: toc; list-style: none; margin-bottom: 6px; }
|
||||
.toc li::before { content: counter(toc) ". "; font-weight: 600; color: var(--accent); }
|
||||
.toc a { color: var(--accent); text-decoration: none; }
|
||||
.toc a:hover { text-decoration: underline; }
|
||||
|
||||
/* ── Flow diagram ── */
|
||||
.flow { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; justify-content: center; margin: 16px 0; }
|
||||
.flow-step {
|
||||
background: var(--accent-light);
|
||||
border: 1px solid var(--accent);
|
||||
border-radius: 8px;
|
||||
padding: 8px 16px;
|
||||
font-size: 0.88rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
.flow-arrow { color: var(--muted); font-size: 1.2rem; }
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.hero h1 { font-size: 1.5rem; }
|
||||
.flow { flex-direction: column; }
|
||||
.flow-arrow { transform: rotate(90deg); }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- Header -->
|
||||
<!-- ============================================================ -->
|
||||
<header class="hero">
|
||||
<h1>一维原子链驱动力学模拟</h1>
|
||||
<p class="subtitle">120 个原子沿 x 轴排列 · 弹簧连接 · z 方向受迫振动</p>
|
||||
<span class="badge">case06 · examples/case06</span>
|
||||
</header>
|
||||
|
||||
<div class="container">
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- TOC -->
|
||||
<!-- ============================================================ -->
|
||||
<section>
|
||||
<h2>目录</h2>
|
||||
<ol class="toc">
|
||||
<li><a href="#physics">物理原理</a></li>
|
||||
<li><a href="#algorithm">数值算法</a></li>
|
||||
<li><a href="#driver">驱动力模型</a></li>
|
||||
<li><a href="#usage">使用方法</a></li>
|
||||
<li><a href="#params">参数参考</a></li>
|
||||
<li><a href="#files">文件结构</a></li>
|
||||
<li><a href="#troubleshoot">常见问题</a></li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 1. Physics -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="physics">
|
||||
<h2>一、物理原理</h2>
|
||||
|
||||
<div class="card">
|
||||
<h3>1.1 一维原子链</h3>
|
||||
<p>120 个原子沿 <strong>x 轴</strong> 等间距排列,原子间距为 1。相邻原子之间用 <strong>理想弹簧</strong> 连接,弹簧的劲度系数 <em>k</em> = 1.0,原长 <em>L</em>₀ = 1.0(与原子间距一致,初始状态弹簧无拉伸)。</p>
|
||||
<p>每个原子被限制在 <strong>z 方向</strong> 自由振动,x 和 y 方向锁定(<code>fix_x=1, fix_y=1, fix_z=0</code>)。</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>1.2 弹簧力(胡克定律)</h3>
|
||||
<p>当原子 <em>i</em> 和 <em>j</em> 之间有弹簧连接时,原子 <em>i</em> 受到的弹簧力为:</p>
|
||||
<div class="formula">
|
||||
<strong>F</strong> = −<em>k</em> · (<em>d</em> − <em>L</em>₀) · <strong>u</strong><sub><em>ij</em></sub>
|
||||
</div>
|
||||
<p>其中 <em>d</em> = |<strong>r</strong><sub><em>j</em></sub> − <strong>r</strong><sub><em>i</em></sub>| 为两原子间距离,<strong>u</strong><sub><em>ij</em></sub> 为从 <em>i</em> 指向 <em>j</em> 的单位向量。由于原子只在 z 方向振动,弹簧在 z 方向的分量是 <strong>几何非线性</strong> 的——对于小振幅近似,z 方向等效于一个三次方恢复力(FPU 型非线性)。</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>1.3 运动方程</h3>
|
||||
<p>对于第 <em>i</em> 个自由原子(非受驱),牛顿第二定律给出:</p>
|
||||
<div class="formula">
|
||||
<em>m</em> · <strong>a</strong><sub><em>i</em></sub> = <strong>F</strong><sub><em>i</em></sub><sup>spring</sup> + <strong>F</strong><sub><em>i</em></sub><sup>driving</sup>
|
||||
</div>
|
||||
<p>本案例中 <strong>唯一的外力</strong> 来自驱动力(仅施加于原子 1)。无重力、无万有引力、无阻尼,系统总能量守恒。</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>1.4 波传播</h3>
|
||||
<p>原子 1 的受迫振动通过弹簧逐次传递给相邻原子,形成沿链传播的 <strong>横波</strong>。由于横向振动的几何非线性(弹簧大部分张力在 x 方向,z 方向的有效刚度远小于 1),波的传播速度较慢,且高阶频率成分会在链中产生复杂的非线性动力学行为(类似 FPU 回波现象)。</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 2. Algorithm -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="algorithm">
|
||||
<h2>二、数值算法</h2>
|
||||
|
||||
<div class="card">
|
||||
<h3>2.1 蛙跳法(Leapfrog / Velocity-Verlet)</h3>
|
||||
<p>采用能量守恒特性优异的 <strong>蛙跳法</strong>(二阶辛积分器),更新公式为:</p>
|
||||
<div class="formula">
|
||||
<strong>v</strong>(<em>t</em> + ½Δ<em>t</em>) = <strong>v</strong>(<em>t</em>) + ½ <strong>a</strong>(<em>t</em>) · Δ<em>t</em><br>
|
||||
<strong>r</strong>(<em>t</em> + Δ<em>t</em>) = <strong>r</strong>(<em>t</em>) + <strong>v</strong>(<em>t</em> + ½Δ<em>t</em>) · Δ<em>t</em><br>
|
||||
<strong>a</strong>(<em>t</em> + Δ<em>t</em>) = <strong>F</strong>(<strong>r</strong>(<em>t</em> + Δ<em>t</em>), <strong>v</strong>(<em>t</em> + ½Δ<em>t</em>)) / <em>m</em><br>
|
||||
<strong>v</strong>(<em>t</em> + Δ<em>t</em>) = <strong>v</strong>(<em>t</em> + ½Δ<em>t</em>) + ½ <strong>a</strong>(<em>t</em> + Δ<em>t</em>) · Δ<em>t</em>
|
||||
</div>
|
||||
<p>蛙跳法在长时间模拟中能量漂移极小(本案例验证 <strong>< 0.004%</strong>),适合无阻尼的保守系统。</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>2.2 时间步长与采样</h3>
|
||||
<table>
|
||||
<tr><th>参数</th><th>值</th><th>说明</th></tr>
|
||||
<tr><td>DT</td><td>0.01 s</td><td>积分步长(远小于 1/ω ≈ 0.16 s,满足稳定性条件)</td></tr>
|
||||
<tr><td>T_total</td><td>100 s</td><td>总模拟时间 → NT = 10000 步</td></tr>
|
||||
<tr><td>NSTEP</td><td>50</td><td>每 NSTEP 步取一帧用于动画 → 200 帧</td></tr>
|
||||
<tr><td>method</td><td>leapfrog</td><td>蛙跳法(Velocity-Verlet)</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>2.3 计算流程</h3>
|
||||
<div class="flow">
|
||||
<span class="flow-step">读入 coord.txt<br>connection.txt<br>bond.txt</span>
|
||||
<span class="flow-arrow">→</span>
|
||||
<span class="flow-step">施加驱动力<br>(驱动原子 1)</span>
|
||||
<span class="flow-arrow">→</span>
|
||||
<span class="flow-step">记录轨迹</span>
|
||||
<span class="flow-arrow">→</span>
|
||||
<span class="flow-step">蛙跳法<br>更新位置/速度</span>
|
||||
<span class="flow-arrow">→</span>
|
||||
<span class="flow-step">固定约束<br>(x, y 锁定)</span>
|
||||
<span class="flow-arrow">→</span>
|
||||
<span class="flow-step" style="background:#fef3c7;border-color:#f59e0b;">循环<br>NT 次</span>
|
||||
</div>
|
||||
<p style="margin-top:12px;">注意:驱动力在 <strong>每次积分前</strong> 施加,确保受驱原子的位置正确传递给弹簧力计算。</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 3. Driving Force -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="driver">
|
||||
<h2>三、驱动力模型</h2>
|
||||
|
||||
<div class="card">
|
||||
<h3>3.1 定义文件</h3>
|
||||
<p>驱动力由 <code>input/driver.txt</code> 定义,格式如下:</p>
|
||||
<pre>n amp_x amp_y amp_z freq_x freq_y freq_z phi_x phi_y phi_z period
|
||||
1 0 0 5 0 0 1 0 0 90 all</pre>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>3.2 数学公式</h3>
|
||||
<p>受驱原子的位置由下式决定(<strong>完全替换</strong> coord.txt 中的初始坐标和固定约束):</p>
|
||||
<div class="formula">
|
||||
<strong>r</strong>(<em>t</em>) = <strong>A</strong> · cos(2π<em>f</em> · <em>t</em> + <strong>φ</strong>)
|
||||
</div>
|
||||
<p>速度由解析导数给出:</p>
|
||||
<div class="formula">
|
||||
<strong>v</strong>(<em>t</em>) = −<strong>A</strong> · 2π<em>f</em> · sin(2π<em>f</em> · <em>t</em> + <strong>φ</strong>)
|
||||
</div>
|
||||
<p>其中 <strong>A</strong> = (amp_x, amp_y, amp_z),<strong>f</strong> = (freq_x, freq_y, freq_z) 为不同方向的驱动频率,<strong>φ</strong> = (phi_x, phi_y, phi_z) 为相位(<strong>角度制</strong>,代码自动转换为弧度)。</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>3.3 本案例驱动参数</h3>
|
||||
<table>
|
||||
<tr><th>参数</th><th>值</th><th>含义</th></tr>
|
||||
<tr><td>amp_z</td><td>5.0</td><td>z 方向驱动振幅</td></tr>
|
||||
<tr><td>freq_z</td><td>1.0 Hz</td><td>驱动频率(周期 1 s)</td></tr>
|
||||
<tr><td>phi_z</td><td>90°</td><td>驱动相位 → z(0) = 5·cos(90°) = 0</td></tr>
|
||||
<tr><td>period</td><td>all</td><td>全程驱动,永不停止</td></tr>
|
||||
</table>
|
||||
<div class="formula">
|
||||
<em>z</em>(<em>t</em>) = 5.0 · cos(2π · 1.0 · <em>t</em> + 90°)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>3.4 有限周期驱动</h3>
|
||||
<p><code>period</code> 参数支持三种模式:</p>
|
||||
<ul>
|
||||
<li><strong>all</strong> — 全程驱动</li>
|
||||
<li><strong>数值</strong> — 驱动指定周期数后 <strong>静止</strong>(冻结在最终位置,速度归零)。例如 <code>period: 1</code> 表示驱动 1 个完整周期后停止。</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>3.5 驱动与固定约束的关系</h3>
|
||||
<p>对于受驱原子(<code>driver.txt</code> 中 <code>n</code> 指定的原子),其在 <code>coord.txt</code> 中的初始坐标和 <code>fix_x/fix_y/fix_z</code> 约束被 <strong>完全忽略</strong>。原子的位置和速度完全由驱动力公式决定。</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 4. Usage -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="usage">
|
||||
<h2>四、使用方法</h2>
|
||||
|
||||
<div class="card">
|
||||
<h3>4.1 完整运行(模拟 + 动画)</h3>
|
||||
<pre>cd examples/case06
|
||||
python run_dynamics.py</pre>
|
||||
<p>这步会依次执行:物理模拟 → 抽帧 → 打开 VisPy 3D 动画窗口。</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>4.2 仅查看已有结果</h3>
|
||||
<p>如果已经跑完模拟且生成了 <code>output/display.txt</code>,可以通过修改 <code>input.txt</code> 跳过计算,只开动画:</p>
|
||||
<pre>step_simulate: 0 # 跳过模拟
|
||||
step_sample: 0 # 跳过抽帧
|
||||
step_animation: 1 # 播放动画</pre>
|
||||
<p>然后运行:<code>python run_dynamics.py</code></p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>4.3 手动 3D 动画</h3>
|
||||
<p>也可以单独启动 VisPy 窗口:</p>
|
||||
<pre>python ../../draw.py output/</pre>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>4.4 强制重新计算</h3>
|
||||
<p>修改参数后需要重新运行模拟时,设置:</p>
|
||||
<pre>force_calc: 1 # 忽略缓存,强制重新计算</pre>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>4.5 动画交互</h3>
|
||||
<table>
|
||||
<tr><th>操作</th><th>效果</th></tr>
|
||||
<tr><td>鼠标拖动</td><td>旋转视角</td></tr>
|
||||
<tr><td>滚轮</td><td>缩放</td></tr>
|
||||
<tr><td>W / S 键</td><td>相机沿 Z 轴向前 / 向后移动(靠近/远离场景)</td></tr>
|
||||
<tr><td>A / D 键</td><td>视角向右 / 向左平移</td></tr>
|
||||
<tr><td>E / Q 键</td><td>视角上升 / 下降(屏幕方向)</td></tr>
|
||||
<tr><td>C / X 键</td><td>增大 / 减小步长</td></tr>
|
||||
<tr><td>V 键</td><td>切换透视 / 正交投影</td></tr>
|
||||
<tr><td>左上角 <strong>reset</strong> 按钮</td><td>复位视角到初始位置</td></tr>
|
||||
<tr><td>左上角 <strong>info</strong> 按钮</td><td>切换信息面板显示/隐藏</td></tr>
|
||||
<tr><td>左上角 <strong>axes</strong> 按钮</td><td>切换坐标轴显示/隐藏</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 5. Parameters -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="params">
|
||||
<h2>五、参数参考</h2>
|
||||
|
||||
<div class="card">
|
||||
<h3>5.1 input.txt 关键参数</h3>
|
||||
<table>
|
||||
<tr><th>参数</th><th>默认值</th><th>说明</th></tr>
|
||||
<tr><td>gravity_field</td><td>0</td><td>均匀重力场(已关闭)</td></tr>
|
||||
<tr><td>gravity_interaction</td><td>0</td><td>原子间万有引力(已关闭)</td></tr>
|
||||
<tr><td>elastic_force</td><td>1</td><td>弹簧键力(已开启)</td></tr>
|
||||
<tr><td>damping_force</td><td>0</td><td>阻尼(已关闭)</td></tr>
|
||||
<tr><td><strong>driving_force</strong></td><td><strong>1</strong></td><td>驱动力开关(1=开启,需 driver.txt)</td></tr>
|
||||
<tr><td>method</td><td>leapfrog</td><td>数值积分方法</td></tr>
|
||||
<tr><td>DT</td><td>0.01</td><td>积分步长 (s)</td></tr>
|
||||
<tr><td>T_total</td><td>100.0</td><td>总模拟时间 (s)</td></tr>
|
||||
<tr><td>NSTEP</td><td>50</td><td>抽帧步数间隔</td></tr>
|
||||
<tr><td>engine</td><td>python</td><td>计算引擎(python / c / cpp / fortran)</td></tr>
|
||||
<tr><td>use_marker</td><td>1</td><td>渲染模式(0=Sphere 网格, 1=Marker GPU 实例化)</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>5.2 流程控制参数</h3>
|
||||
<table>
|
||||
<tr><th>参数</th><th>0</th><th>1</th></tr>
|
||||
<tr><td>step_simulate</td><td>跳过模拟(加载已有轨迹)</td><td>运行物理模拟</td></tr>
|
||||
<tr><td>step_sample</td><td>跳过抽帧</td><td>从轨迹抽取显示帧</td></tr>
|
||||
<tr><td>step_plot</td><td>不生成图表</td><td>生成轨迹/能量图</td></tr>
|
||||
<tr><td><strong>step_plot_wave</strong></td><td>不生成波形图</td><td>生成波形能量动画 GIF</td></tr>
|
||||
<tr><td>step_animation</td><td>不启动动画</td><td>自动打开 VisPy 3D 窗口</td></tr>
|
||||
<tr><td>force_calc</td><td>自动检测缓存</td><td>强制重新计算</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 6. File Structure -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="files">
|
||||
<h2>六、文件结构</h2>
|
||||
|
||||
<pre>case06/
|
||||
├── input/
|
||||
│ ├── input.txt # 主配置文件(YAML 格式)
|
||||
│ ├── coord.txt # 原子坐标(120 个原子)
|
||||
│ ├── connection.txt # 弹簧连接关系(59 条键)
|
||||
│ ├── bond.txt # 弹簧参数(k=1.0, L₀=1.0)
|
||||
│ └── <strong>driver.txt</strong> # <span class="cm">驱动力定义(本案例新增)</span>
|
||||
├── output/
|
||||
│ ├── trajectory.txt # 全量轨迹数据(50000 步 × 120 原子)
|
||||
│ ├── display.txt # 抽帧后的动画数据(500 帧 × 120 原子)
|
||||
│ ├── dynamics.log # 计算日志
|
||||
│ ├── animation.log # 动画启动日志(闪退时排查用)
|
||||
│ └── wave_animation.gif # 波形能量动画(step_plot_wave=1 时生成)
|
||||
├── doc/
|
||||
│ └── index.html # <span class="cm">本文档</span>
|
||||
├── Readme.md # 案例简介
|
||||
└── run_dynamics.py # 案例运行入口</pre>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 7. Troubleshooting -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="troubleshoot">
|
||||
<h2>七、常见问题</h2>
|
||||
|
||||
<div class="card">
|
||||
<h3>7.1 动画窗口闪退</h3>
|
||||
<p>如果 VisPy 窗口一闪就消失,请检查:</p>
|
||||
<ul>
|
||||
<li><code>output/animation.log</code> 中是否有错误信息</li>
|
||||
<li><code>output/display.txt</code> 是否存在(需先跑 <code>step_sample: 1</code>)</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>7.2 原子不振动</h3>
|
||||
<p>可能原因:</p>
|
||||
<ul>
|
||||
<li><strong>NSTEP 过大</strong>:抽帧间隔大于驱动周期的一半时,动画会丢失振动细节。建议 NSTEP ≤ 1/(freq · DT · 10)</li>
|
||||
<li><strong>相位 φ 使采样点落在零值</strong>:试试 <code>phi_z: 0</code> 让原子在 t=0 处于振幅峰值</li>
|
||||
<li>确认 <code>driving_force: 1</code> 且 <code>driver.txt</code> 中 amp_z 不为 0</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>7.3 渲染性能慢</h3>
|
||||
<p>原子数多时动画卡顿:</p>
|
||||
<ul>
|
||||
<li>设置 <code>use_marker: 1</code>(使用 GPU 实例化渲染替代独立网格球体)</li>
|
||||
<li>增大 <code>NSTEP</code> 减少动画帧数</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<hr style="border:none;border-top:1px solid var(--border);margin:40px 0;">
|
||||
|
||||
<footer style="text-align:center;color:var(--muted);font-size:0.85rem;margin-bottom:40px;">
|
||||
Dynamics Simulation Framework · 生成于 2026-06-10
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,2 @@
|
||||
bond_name k rest_length
|
||||
k1 500.0 1.0
|
||||
@@ -0,0 +1,120 @@
|
||||
n1 n2 bond_name
|
||||
1 2 k1
|
||||
2 3 k1
|
||||
3 4 k1
|
||||
4 5 k1
|
||||
5 6 k1
|
||||
6 7 k1
|
||||
7 8 k1
|
||||
8 9 k1
|
||||
9 10 k1
|
||||
10 11 k1
|
||||
11 12 k1
|
||||
12 13 k1
|
||||
13 14 k1
|
||||
14 15 k1
|
||||
15 16 k1
|
||||
16 17 k1
|
||||
17 18 k1
|
||||
18 19 k1
|
||||
19 20 k1
|
||||
20 21 k1
|
||||
21 22 k1
|
||||
22 23 k1
|
||||
23 24 k1
|
||||
24 25 k1
|
||||
25 26 k1
|
||||
26 27 k1
|
||||
27 28 k1
|
||||
28 29 k1
|
||||
29 30 k1
|
||||
30 31 k1
|
||||
31 32 k1
|
||||
32 33 k1
|
||||
33 34 k1
|
||||
34 35 k1
|
||||
35 36 k1
|
||||
36 37 k1
|
||||
37 38 k1
|
||||
38 39 k1
|
||||
39 40 k1
|
||||
40 41 k1
|
||||
41 42 k1
|
||||
42 43 k1
|
||||
43 44 k1
|
||||
44 45 k1
|
||||
45 46 k1
|
||||
46 47 k1
|
||||
47 48 k1
|
||||
48 49 k1
|
||||
49 50 k1
|
||||
50 51 k1
|
||||
51 52 k1
|
||||
52 53 k1
|
||||
53 54 k1
|
||||
54 55 k1
|
||||
55 56 k1
|
||||
56 57 k1
|
||||
57 58 k1
|
||||
58 59 k1
|
||||
59 60 k1
|
||||
60 61 k1
|
||||
61 62 k1
|
||||
62 63 k1
|
||||
63 64 k1
|
||||
64 65 k1
|
||||
65 66 k1
|
||||
66 67 k1
|
||||
67 68 k1
|
||||
68 69 k1
|
||||
69 70 k1
|
||||
70 71 k1
|
||||
71 72 k1
|
||||
72 73 k1
|
||||
73 74 k1
|
||||
74 75 k1
|
||||
75 76 k1
|
||||
76 77 k1
|
||||
77 78 k1
|
||||
78 79 k1
|
||||
79 80 k1
|
||||
80 81 k1
|
||||
81 82 k1
|
||||
82 83 k1
|
||||
83 84 k1
|
||||
84 85 k1
|
||||
85 86 k1
|
||||
86 87 k1
|
||||
87 88 k1
|
||||
88 89 k1
|
||||
89 90 k1
|
||||
90 91 k1
|
||||
91 92 k1
|
||||
92 93 k1
|
||||
93 94 k1
|
||||
94 95 k1
|
||||
95 96 k1
|
||||
96 97 k1
|
||||
97 98 k1
|
||||
98 99 k1
|
||||
99 100 k1
|
||||
100 101 k1
|
||||
101 102 k1
|
||||
102 103 k1
|
||||
103 104 k1
|
||||
104 105 k1
|
||||
105 106 k1
|
||||
106 107 k1
|
||||
107 108 k1
|
||||
108 109 k1
|
||||
109 110 k1
|
||||
110 111 k1
|
||||
111 112 k1
|
||||
112 113 k1
|
||||
113 114 k1
|
||||
114 115 k1
|
||||
115 116 k1
|
||||
116 117 k1
|
||||
117 118 k1
|
||||
118 119 k1
|
||||
119 120 k1
|
||||
@@ -0,0 +1,121 @@
|
||||
n mass radius x y z vx vy vz fix_x fix_y fix_z
|
||||
1 1 0.1 0 0 0 0 0 0 0 1 0
|
||||
2 1 0.1 1 0 0 0 0 0 0 1 0
|
||||
3 1 0.1 2 0 0 0 0 0 0 1 0
|
||||
4 1 0.1 3 0 0 0 0 0 0 1 0
|
||||
5 1 0.1 4 0 0 0 0 0 0 1 0
|
||||
6 1 0.1 5 0 0 0 0 0 0 1 0
|
||||
7 1 0.1 6 0 0 0 0 0 0 1 0
|
||||
8 1 0.1 7 0 0 0 0 0 0 1 0
|
||||
9 1 0.1 8 0 0 0 0 0 0 1 0
|
||||
10 1 0.1 9 0 0 0 0 0 0 1 0
|
||||
11 1 0.1 10 0 0 0 0 0 0 1 0
|
||||
12 1 0.1 11 0 0 0 0 0 0 1 0
|
||||
13 1 0.1 12 0 0 0 0 0 0 1 0
|
||||
14 1 0.1 13 0 0 0 0 0 0 1 0
|
||||
15 1 0.1 14 0 0 0 0 0 0 1 0
|
||||
16 1 0.1 15 0 0 0 0 0 0 1 0
|
||||
17 1 0.1 16 0 0 0 0 0 0 1 0
|
||||
18 1 0.1 17 0 0 0 0 0 0 1 0
|
||||
19 1 0.1 18 0 0 0 0 0 0 1 0
|
||||
20 1 0.1 19 0 0 0 0 0 0 1 0
|
||||
21 1 0.1 20 0 0 0 0 0 0 1 0
|
||||
22 1 0.1 21 0 0 0 0 0 0 1 0
|
||||
23 1 0.1 22 0 0 0 0 0 0 1 0
|
||||
24 1 0.1 23 0 0 0 0 0 0 1 0
|
||||
25 1 0.1 24 0 0 0 0 0 0 1 0
|
||||
26 1 0.1 25 0 0 0 0 0 0 1 0
|
||||
27 1 0.1 26 0 0 0 0 0 0 1 0
|
||||
28 1 0.1 27 0 0 0 0 0 0 1 0
|
||||
29 1 0.1 28 0 0 0 0 0 0 1 0
|
||||
30 1 0.1 29 0 0 0 0 0 0 1 0
|
||||
31 1 0.1 30 0 0 0 0 0 0 1 0
|
||||
32 1 0.1 31 0 0 0 0 0 0 1 0
|
||||
33 1 0.1 32 0 0 0 0 0 0 1 0
|
||||
34 1 0.1 33 0 0 0 0 0 0 1 0
|
||||
35 1 0.1 34 0 0 0 0 0 0 1 0
|
||||
36 1 0.1 35 0 0 0 0 0 0 1 0
|
||||
37 1 0.1 36 0 0 0 0 0 0 1 0
|
||||
38 1 0.1 37 0 0 0 0 0 0 1 0
|
||||
39 1 0.1 38 0 0 0 0 0 0 1 0
|
||||
40 1 0.1 39 0 0 0 0 0 0 1 0
|
||||
41 1 0.1 40 0 0 0 0 0 0 1 0
|
||||
42 1 0.1 41 0 0 0 0 0 0 1 0
|
||||
43 1 0.1 42 0 0 0 0 0 0 1 0
|
||||
44 1 0.1 43 0 0 0 0 0 0 1 0
|
||||
45 1 0.1 44 0 0 0 0 0 0 1 0
|
||||
46 1 0.1 45 0 0 0 0 0 0 1 0
|
||||
47 1 0.1 46 0 0 0 0 0 0 1 0
|
||||
48 1 0.1 47 0 0 0 0 0 0 1 0
|
||||
49 1 0.1 48 0 0 0 0 0 0 1 0
|
||||
50 1 0.1 49 0 0 0 0 0 0 1 0
|
||||
51 1 0.1 50 0 0 0 0 0 0 1 0
|
||||
52 1 0.1 51 0 0 0 0 0 0 1 0
|
||||
53 1 0.1 52 0 0 0 0 0 0 1 0
|
||||
54 1 0.1 53 0 0 0 0 0 0 1 0
|
||||
55 1 0.1 54 0 0 0 0 0 0 1 0
|
||||
56 1 0.1 55 0 0 0 0 0 0 1 0
|
||||
57 1 0.1 56 0 0 0 0 0 0 1 0
|
||||
58 1 0.1 57 0 0 0 0 0 0 1 0
|
||||
59 1 0.1 58 0 0 0 0 0 0 1 0
|
||||
60 1 0.1 59 0 0 0 0 0 0 1 0
|
||||
61 1 0.1 60 0 0 0 0 0 0 1 0
|
||||
62 1 0.1 61 0 0 0 0 0 0 1 0
|
||||
63 1 0.1 62 0 0 0 0 0 0 1 0
|
||||
64 1 0.1 63 0 0 0 0 0 0 1 0
|
||||
65 1 0.1 64 0 0 0 0 0 0 1 0
|
||||
66 1 0.1 65 0 0 0 0 0 0 1 0
|
||||
67 1 0.1 66 0 0 0 0 0 0 1 0
|
||||
68 1 0.1 67 0 0 0 0 0 0 1 0
|
||||
69 1 0.1 68 0 0 0 0 0 0 1 0
|
||||
70 1 0.1 69 0 0 0 0 0 0 1 0
|
||||
71 1 0.1 70 0 0 0 0 0 0 1 0
|
||||
72 1 0.1 71 0 0 0 0 0 0 1 0
|
||||
73 1 0.1 72 0 0 0 0 0 0 1 0
|
||||
74 1 0.1 73 0 0 0 0 0 0 1 0
|
||||
75 1 0.1 74 0 0 0 0 0 0 1 0
|
||||
76 1 0.1 75 0 0 0 0 0 0 1 0
|
||||
77 1 0.1 76 0 0 0 0 0 0 1 0
|
||||
78 1 0.1 77 0 0 0 0 0 0 1 0
|
||||
79 1 0.1 78 0 0 0 0 0 0 1 0
|
||||
80 1 0.1 79 0 0 0 0 0 0 1 0
|
||||
81 1 0.1 80 0 0 0 0 0 0 1 0
|
||||
82 1 0.1 81 0 0 0 0 0 0 1 0
|
||||
83 1 0.1 82 0 0 0 0 0 0 1 0
|
||||
84 1 0.1 83 0 0 0 0 0 0 1 0
|
||||
85 1 0.1 84 0 0 0 0 0 0 1 0
|
||||
86 1 0.1 85 0 0 0 0 0 0 1 0
|
||||
87 1 0.1 86 0 0 0 0 0 0 1 0
|
||||
88 1 0.1 87 0 0 0 0 0 0 1 0
|
||||
89 1 0.1 88 0 0 0 0 0 0 1 0
|
||||
90 1 0.1 89 0 0 0 0 0 0 1 0
|
||||
91 1 0.1 90 0 0 0 0 0 0 1 0
|
||||
92 1 0.1 91 0 0 0 0 0 0 1 0
|
||||
93 1 0.1 92 0 0 0 0 0 0 1 0
|
||||
94 1 0.1 93 0 0 0 0 0 0 1 0
|
||||
95 1 0.1 94 0 0 0 0 0 0 1 0
|
||||
96 1 0.1 95 0 0 0 0 0 0 1 0
|
||||
97 1 0.1 96 0 0 0 0 0 0 1 0
|
||||
98 1 0.1 97 0 0 0 0 0 0 1 0
|
||||
99 1 0.1 98 0 0 0 0 0 0 1 0
|
||||
100 1 0.1 99 0 0 0 0 0 0 1 0
|
||||
101 1 0.1 100 0 0 0 0 0 0 1 0
|
||||
102 1 0.1 101 0 0 0 0 0 0 1 0
|
||||
103 1 0.1 102 0 0 0 0 0 0 1 0
|
||||
104 1 0.1 103 0 0 0 0 0 0 1 0
|
||||
105 1 0.1 104 0 0 0 0 0 0 1 0
|
||||
106 1 0.1 105 0 0 0 0 0 0 1 0
|
||||
107 1 0.1 106 0 0 0 0 0 0 1 0
|
||||
108 1 0.1 107 0 0 0 0 0 0 1 0
|
||||
109 1 0.1 108 0 0 0 0 0 0 1 0
|
||||
110 1 0.1 109 0 0 0 0 0 0 1 0
|
||||
111 1 0.1 110 0 0 0 0 0 0 1 0
|
||||
112 1 0.1 111 0 0 0 0 0 0 1 0
|
||||
113 1 0.1 112 0 0 0 0 0 0 1 0
|
||||
114 1 0.1 113 0 0 0 0 0 0 1 0
|
||||
115 1 0.1 114 0 0 0 0 0 0 1 0
|
||||
116 1 0.1 115 0 0 0 0 0 0 1 0
|
||||
117 1 0.1 116 0 0 0 0 0 0 1 0
|
||||
118 1 0.1 117 0 0 0 0 0 0 1 0
|
||||
119 1 0.1 118 0 0 0 0 0 0 1 0
|
||||
120 1 0.1 119 0 0 0 0 0 1 1 1
|
||||
@@ -0,0 +1,3 @@
|
||||
n amp_x amp_y amp_z freq_x freq_y freq_z phi_x phi_y phi_z period
|
||||
1 0 0 0.1 0 0 0.01333 0 0 90 all
|
||||
120 0 0 0.1 0 0 0.01333 0 0 90 all
|
||||
@@ -0,0 +1,114 @@
|
||||
# 物理模拟参数配置
|
||||
# 格式:YAML
|
||||
# 用法:python run_dynamics.py
|
||||
|
||||
# ── 流程控制 ──────────────────────────────────
|
||||
# 每步用 0/1 单独开关,1=执行,0=跳过
|
||||
# 依赖关系:抽帧依赖模拟结果,绘图依赖模拟+抽帧
|
||||
step_simulate: 1 # 运行物理模拟 → output/display.txt(引擎直接抽帧)
|
||||
step_sample: 0 # (旧版)从 trajectory.txt 重新抽帧,默认0=不执行
|
||||
step_plot: 0 # 绘制轨迹/能量图 → output/trajectory_plots.png
|
||||
step_animation: 0 # 自动播放 VisPy 3D 动画窗口(需安装 vispy)
|
||||
step_plot_wave: 1 # 绘制波形能量动画
|
||||
force_calc: 1 # 强制重新计算:1=跳过缓存强算,0=自动使用已有输出
|
||||
plot_wave_save_gif: 0 # 输出波形 GIF(需 step_plot_wave=1)
|
||||
plot_wave_save_mp4: 0 # 输出波形 MP4(需 step_plot_wave=1)
|
||||
|
||||
# ── 文件保存 ──────────────────────────────────
|
||||
save_trajectory: 0 # 0=不保留完整轨迹文件, 1=保留 trajectory.txt(用于后续单独抽帧)
|
||||
|
||||
# ── 计算引擎 ──────────────────────────────────
|
||||
# 可选: python, c, cpp, fortran, java
|
||||
engine: c # 默认使用 python 引擎
|
||||
|
||||
# ── 盒子 ──────────────────────────────────────
|
||||
box_a: 300.0 # 立方体半边长,粒子被限制在 [-box_a, box_a]³ 内
|
||||
|
||||
# ── 初始构型 ──────────────────────────────────
|
||||
# 坐标文件格式:
|
||||
# 第一行:n mass radius x y z vx vy vz fix_x fix_y fix_z
|
||||
# 后续行:原子序号 质量 半径 x y z vx vy vz fix_x fix_y fix_z
|
||||
coord_file: input/coord.txt
|
||||
connection_file: input/connection.txt
|
||||
bond_file: input/bond.txt
|
||||
driver_file: input/driver.txt # 驱动力定义文件(driving_force=1 时生效)
|
||||
|
||||
# 绘图/动画展示的原子序号(对应 coord_file 第一列 n)
|
||||
plot_atom: 1
|
||||
|
||||
# ── 物理参数 ──────────────────────────────────
|
||||
# 三个方向分量分别对应 x, y, z
|
||||
G: [0.000, 0.000, 0.000] # 重力场分量 (m/s²)
|
||||
B: [0.005, 0.000, 0.005] # 阻尼分量
|
||||
|
||||
# ── 力开关(0=关闭, 1=开启)──────────────────
|
||||
gravity_field: 0 # 均匀重力场 (G)
|
||||
gravity_interaction: 0 # 原子间万有引力
|
||||
elastic_force: 1 # 弹簧键力
|
||||
damping_force: 1 # 阻尼 (B)
|
||||
driving_force: 1 # 驱动力(需 driver_file 定义)
|
||||
#
|
||||
gravity_strength: 1.0 # 万有引力强度(仅 gravity_interaction=1 时有效)
|
||||
|
||||
# ── 数值算法 ──────────────────────────────────
|
||||
# 可选:
|
||||
# explicit_euler 显式欧拉法
|
||||
# implicit_euler 隐式欧拉法
|
||||
# midpoint 中点法
|
||||
# leapfrog 蛙跳法
|
||||
method: leapfrog
|
||||
|
||||
# ── 步骤控制 ──────────────────────────────────
|
||||
# 以下参数控制哪些步骤被执行和保存
|
||||
|
||||
# 预热步数:模拟开始时跳过不保存的步数(用于稳定初始状态)
|
||||
warmup_steps: 0 # 默认 0(立即开始记录)
|
||||
|
||||
# 总模拟时间(秒),程序自动计算 NT = T_total / DT
|
||||
# 如果同时指定了 NT,以 NT 为准
|
||||
T_total: 1000.0
|
||||
|
||||
# 抽帧间隔(每 NSTEP 步取一帧用于动画)
|
||||
NSTEP: 500
|
||||
|
||||
# ── 时间步长 ──────────────────────────────────
|
||||
DT: 0.001 # 时间步长 (s)
|
||||
|
||||
# 抽帧范围:只保存 [sample_start, sample_end) 区间内的帧
|
||||
sample_start: null # null 表示从头开始(帧索引从 0 起)
|
||||
sample_end: null # null 表示到末尾
|
||||
|
||||
|
||||
|
||||
# ── 渲染方式 ──────────────────────────────────
|
||||
# 3D 动画中原子渲染方式:
|
||||
# 0 = Sphere (网格球体,效果精细,原子数少时推荐)
|
||||
# 1 = Marker (GPU 实例化点,原子数多时性能更佳)
|
||||
use_marker: 1
|
||||
|
||||
# ── 显示参数 ──────────────────────────────────
|
||||
# 盒子透明度:单个数值(统一)或 6 个数的数组,按 [-x,+x,-y,+y,-z,+z] 顺序
|
||||
alpha: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
|
||||
|
||||
# 小球颜色
|
||||
# 小球半径从 coord_file 的 radius 列读取
|
||||
ball_color_r: 0.20 # R 分量 (0~1)
|
||||
ball_color_g: 0.60 # G 分量
|
||||
ball_color_b: 0.90 # B 分量
|
||||
|
||||
# 盒子面颜色
|
||||
box_color_r: 0.80
|
||||
box_color_g: 0.80
|
||||
box_color_b: 0.85
|
||||
|
||||
# ── 摄像机初始位置 ────────────────────────────
|
||||
camera_distance: 120.0 # 摄像机到场景中心的距离
|
||||
camera_elevation: 0.0 # 俯仰角(度),负值=俯视
|
||||
camera_azimuth: 0.0 # 方位角(度)
|
||||
camera_center_x: 60.0 # 摄像机注视点 x
|
||||
camera_center_y: 0.0 # 摄像机注视点 y
|
||||
camera_center_z: 0.0 # 摄像机注视点 z
|
||||
move_camera: 0 # 0=固定视角, 1=按 move_camera.txt 运动
|
||||
|
||||
# ── 视觉放大 ──────────────────────────────────
|
||||
display_amp: [1.0, 1.0, 10.0] # x/y/z 方向视觉位移放大倍数(不影响物理)
|
||||
@@ -0,0 +1,9 @@
|
||||
# move_camera.txt — 摄像机速度段驱动
|
||||
# 格式: start-end vx=f vy=f vz=f rx=d ry=d rz=d
|
||||
# vx/vy/vz: 平移速度(每帧移动单位)
|
||||
# rx/ry/rz: 旋转速度(每帧度数)
|
||||
# rx → elevation(俯仰), ry → azimuth(方位), rz → (预留)
|
||||
#
|
||||
# 示例:前60帧向右平移+绕x旋转,30-90帧向上平移+绕y绕z旋转
|
||||
all vx=0.02
|
||||
# 30-90 vy=0.02 ry=1 rz=1
|
||||
@@ -0,0 +1,54 @@
|
||||
"""
|
||||
Case runner for Dynamics case06 — 1D atomic chain (transverse wave).
|
||||
|
||||
This script keeps program and data separated:
|
||||
- program: ../../dynamics.py
|
||||
- input: ./input
|
||||
- output: ./output
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
CASE_DIR = Path(__file__).resolve().parent
|
||||
DYNAMICS_PATH = Path("..") / ".." / "dynamics.py"
|
||||
INPUT_DIR = Path("input")
|
||||
OUTPUT_DIR = Path("output")
|
||||
CONFIG_FILE = INPUT_DIR / "input.txt"
|
||||
|
||||
|
||||
def load_dynamics_module(module_path: Path):
|
||||
spec = importlib.util.spec_from_file_location("dynamics_module", module_path)
|
||||
if spec is None or spec.loader is None:
|
||||
raise ImportError(f"无法加载 dynamics.py: {module_path}")
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="运行 Dynamics 示例案例 case06")
|
||||
parser.add_argument("--no-plot", action="store_true", help="跳过 matplotlib 绘图")
|
||||
args = parser.parse_args()
|
||||
|
||||
dynamics_path = (CASE_DIR / DYNAMICS_PATH).resolve()
|
||||
input_dir = (CASE_DIR / INPUT_DIR).resolve()
|
||||
output_dir = (CASE_DIR / OUTPUT_DIR).resolve()
|
||||
config_path = (CASE_DIR / CONFIG_FILE).resolve()
|
||||
|
||||
module = load_dynamics_module(dynamics_path)
|
||||
module.run_case(
|
||||
config_path=config_path,
|
||||
runtime_base=CASE_DIR,
|
||||
input_dir=input_dir,
|
||||
output_dir=output_dir,
|
||||
no_plot=args.no_plot,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,40 @@
|
||||
# case06: 一维原子链横波模拟
|
||||
|
||||
60 个原子沿 x 轴排列,相邻原子用弹簧连接。原子 1 受 z 方向驱动力作用,产生沿链传播的横波。
|
||||
|
||||
## 物理设定
|
||||
|
||||
| 参数 | 值 |
|
||||
|---|---|
|
||||
| 原子数 | 120 |
|
||||
| 排列 | 沿 x 轴等间距排列,间距为 1 |
|
||||
| 约束 | 原子**沿 z 方向自由振动**(fix_x=1, fix_y=1, fix_z=0),x, y 锁定 |
|
||||
| 弹簧 | 劲度系数 k=1.0,原长 L₀=1.0 |
|
||||
| 重力 | 无 |
|
||||
| 万有引力 | 无 |
|
||||
| 阻尼 | 无 |
|
||||
| 驱动力 | 原子 1(z 方向驱动) |
|
||||
| 算法 | leapfrog(蛙跳法,能量守恒) |
|
||||
|
||||
## 驱动力
|
||||
|
||||
原子 1 的位置由 `input/driver.txt` 中的驱动力公式决定:
|
||||
|
||||
```math
|
||||
z(t) = A_z \cdot \cos(2\pi f_z t + \phi_z)
|
||||
```
|
||||
|
||||
当前参数:A_z = 0.5, f_z = 0.1 Hz, φ_z = 90°, period = all(全程驱动)。
|
||||
|
||||
## 动力学行为
|
||||
|
||||
原子 1 沿 z 方向的受迫振动通过弹簧逐次传递给相邻原子,形成沿链传播的**横波**。由于 z 方向的振动是横向的,弹簧大部分张力在 x 方向,z 方向的有效刚度是非线性的——等效于一个三次方恢复力(FPU 型非线性),因此波速较慢。
|
||||
|
||||
## 使用方法
|
||||
|
||||
```bash
|
||||
cd examples/case06
|
||||
python run_dynamics.py
|
||||
```
|
||||
|
||||
配置参数详见 `input/input.txt`,驱动力定义见 `input/driver.txt`,完整文档见 `doc/index.html`。
|
||||
@@ -0,0 +1,477 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>case06 — 一维原子链驱动力学模拟 | 物理原理 & 使用文档</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #f8f9fa;
|
||||
--card: #fff;
|
||||
--text: #1a1a2e;
|
||||
--accent: #2563eb;
|
||||
--accent-light: #dbeafe;
|
||||
--code-bg: #1e293b;
|
||||
--code-text: #e2e8f0;
|
||||
--border: #e2e8f0;
|
||||
--muted: #64748b;
|
||||
}
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Noto Sans SC", sans-serif;
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
/* ── Header ── */
|
||||
.hero {
|
||||
background: linear-gradient(135deg, #1e293b 0%, #334155 100%);
|
||||
color: #fff;
|
||||
padding: 56px 24px 48px;
|
||||
text-align: center;
|
||||
}
|
||||
.hero h1 { font-size: 2rem; font-weight: 700; letter-spacing: -0.02em; }
|
||||
.hero .subtitle {
|
||||
margin-top: 10px;
|
||||
font-size: 1.05rem;
|
||||
opacity: 0.8;
|
||||
}
|
||||
.hero .badge {
|
||||
display: inline-block;
|
||||
margin-top: 14px;
|
||||
padding: 4px 14px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255,255,255,0.12);
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
|
||||
/* ── Layout ── */
|
||||
.container { max-width: 820px; margin: 0 auto; padding: 32px 20px; }
|
||||
|
||||
section { margin-bottom: 44px; }
|
||||
h2 {
|
||||
font-size: 1.35rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 2px solid var(--accent);
|
||||
display: inline-block;
|
||||
}
|
||||
h3 {
|
||||
font-size: 1.05rem;
|
||||
font-weight: 600;
|
||||
margin: 20px 0 10px;
|
||||
}
|
||||
|
||||
p, li { margin-bottom: 10px; }
|
||||
ul, ol { padding-left: 22px; }
|
||||
strong { color: var(--accent); }
|
||||
|
||||
/* ── Cards ── */
|
||||
.card {
|
||||
background: var(--card);
|
||||
border-radius: 12px;
|
||||
padding: 20px 24px;
|
||||
margin-bottom: 16px;
|
||||
border: 1px solid var(--border);
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.04);
|
||||
}
|
||||
|
||||
/* ── Formula / Code blocks ── */
|
||||
.formula {
|
||||
background: var(--card);
|
||||
border-left: 4px solid var(--accent);
|
||||
padding: 14px 20px;
|
||||
margin: 14px 0;
|
||||
font-family: "Times New Roman", "STIX", serif;
|
||||
font-size: 1.05rem;
|
||||
overflow-x: auto;
|
||||
border-radius: 0 8px 8px 0;
|
||||
}
|
||||
code {
|
||||
background: var(--accent-light);
|
||||
padding: 2px 7px;
|
||||
border-radius: 4px;
|
||||
font-family: "JetBrains Mono", "Fira Code", monospace;
|
||||
font-size: 0.88em;
|
||||
}
|
||||
pre {
|
||||
background: var(--code-bg);
|
||||
color: var(--code-text);
|
||||
padding: 16px 20px;
|
||||
border-radius: 10px;
|
||||
overflow-x: auto;
|
||||
font-size: 0.85rem;
|
||||
line-height: 1.5;
|
||||
margin: 14px 0;
|
||||
}
|
||||
pre .cm { color: #94a3b8; font-style: italic; } /* comment */
|
||||
|
||||
/* ── Table ── */
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 14px 0;
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
th, td {
|
||||
padding: 8px 12px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
th { background: var(--accent-light); font-weight: 600; }
|
||||
|
||||
/* ── TOC ── */
|
||||
.toc { counter-reset: toc; }
|
||||
.toc li { counter-increment: toc; list-style: none; margin-bottom: 6px; }
|
||||
.toc li::before { content: counter(toc) ". "; font-weight: 600; color: var(--accent); }
|
||||
.toc a { color: var(--accent); text-decoration: none; }
|
||||
.toc a:hover { text-decoration: underline; }
|
||||
|
||||
/* ── Flow diagram ── */
|
||||
.flow { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; justify-content: center; margin: 16px 0; }
|
||||
.flow-step {
|
||||
background: var(--accent-light);
|
||||
border: 1px solid var(--accent);
|
||||
border-radius: 8px;
|
||||
padding: 8px 16px;
|
||||
font-size: 0.88rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
.flow-arrow { color: var(--muted); font-size: 1.2rem; }
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.hero h1 { font-size: 1.5rem; }
|
||||
.flow { flex-direction: column; }
|
||||
.flow-arrow { transform: rotate(90deg); }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- Header -->
|
||||
<!-- ============================================================ -->
|
||||
<header class="hero">
|
||||
<h1>一维原子链驱动力学模拟</h1>
|
||||
<p class="subtitle">120 个原子沿 x 轴排列 · 弹簧连接 · z 方向受迫振动</p>
|
||||
<span class="badge">case06 · examples/case06</span>
|
||||
</header>
|
||||
|
||||
<div class="container">
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- TOC -->
|
||||
<!-- ============================================================ -->
|
||||
<section>
|
||||
<h2>目录</h2>
|
||||
<ol class="toc">
|
||||
<li><a href="#physics">物理原理</a></li>
|
||||
<li><a href="#algorithm">数值算法</a></li>
|
||||
<li><a href="#driver">驱动力模型</a></li>
|
||||
<li><a href="#usage">使用方法</a></li>
|
||||
<li><a href="#params">参数参考</a></li>
|
||||
<li><a href="#files">文件结构</a></li>
|
||||
<li><a href="#troubleshoot">常见问题</a></li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 1. Physics -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="physics">
|
||||
<h2>一、物理原理</h2>
|
||||
|
||||
<div class="card">
|
||||
<h3>1.1 一维原子链</h3>
|
||||
<p>120 个原子沿 <strong>x 轴</strong> 等间距排列,原子间距为 1。相邻原子之间用 <strong>理想弹簧</strong> 连接,弹簧的劲度系数 <em>k</em> = 1.0,原长 <em>L</em>₀ = 1.0(与原子间距一致,初始状态弹簧无拉伸)。</p>
|
||||
<p>每个原子被限制在 <strong>z 方向</strong> 自由振动,x 和 y 方向锁定(<code>fix_x=1, fix_y=1, fix_z=0</code>)。</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>1.2 弹簧力(胡克定律)</h3>
|
||||
<p>当原子 <em>i</em> 和 <em>j</em> 之间有弹簧连接时,原子 <em>i</em> 受到的弹簧力为:</p>
|
||||
<div class="formula">
|
||||
<strong>F</strong> = −<em>k</em> · (<em>d</em> − <em>L</em>₀) · <strong>u</strong><sub><em>ij</em></sub>
|
||||
</div>
|
||||
<p>其中 <em>d</em> = |<strong>r</strong><sub><em>j</em></sub> − <strong>r</strong><sub><em>i</em></sub>| 为两原子间距离,<strong>u</strong><sub><em>ij</em></sub> 为从 <em>i</em> 指向 <em>j</em> 的单位向量。由于原子只在 z 方向振动,弹簧在 z 方向的分量是 <strong>几何非线性</strong> 的——对于小振幅近似,z 方向等效于一个三次方恢复力(FPU 型非线性)。</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>1.3 运动方程</h3>
|
||||
<p>对于第 <em>i</em> 个自由原子(非受驱),牛顿第二定律给出:</p>
|
||||
<div class="formula">
|
||||
<em>m</em> · <strong>a</strong><sub><em>i</em></sub> = <strong>F</strong><sub><em>i</em></sub><sup>spring</sup> + <strong>F</strong><sub><em>i</em></sub><sup>driving</sup>
|
||||
</div>
|
||||
<p>本案例中 <strong>唯一的外力</strong> 来自驱动力(仅施加于原子 1)。无重力、无万有引力、无阻尼,系统总能量守恒。</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>1.4 波传播</h3>
|
||||
<p>原子 1 的受迫振动通过弹簧逐次传递给相邻原子,形成沿链传播的 <strong>横波</strong>。由于横向振动的几何非线性(弹簧大部分张力在 x 方向,z 方向的有效刚度远小于 1),波的传播速度较慢,且高阶频率成分会在链中产生复杂的非线性动力学行为(类似 FPU 回波现象)。</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 2. Algorithm -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="algorithm">
|
||||
<h2>二、数值算法</h2>
|
||||
|
||||
<div class="card">
|
||||
<h3>2.1 蛙跳法(Leapfrog / Velocity-Verlet)</h3>
|
||||
<p>采用能量守恒特性优异的 <strong>蛙跳法</strong>(二阶辛积分器),更新公式为:</p>
|
||||
<div class="formula">
|
||||
<strong>v</strong>(<em>t</em> + ½Δ<em>t</em>) = <strong>v</strong>(<em>t</em>) + ½ <strong>a</strong>(<em>t</em>) · Δ<em>t</em><br>
|
||||
<strong>r</strong>(<em>t</em> + Δ<em>t</em>) = <strong>r</strong>(<em>t</em>) + <strong>v</strong>(<em>t</em> + ½Δ<em>t</em>) · Δ<em>t</em><br>
|
||||
<strong>a</strong>(<em>t</em> + Δ<em>t</em>) = <strong>F</strong>(<strong>r</strong>(<em>t</em> + Δ<em>t</em>), <strong>v</strong>(<em>t</em> + ½Δ<em>t</em>)) / <em>m</em><br>
|
||||
<strong>v</strong>(<em>t</em> + Δ<em>t</em>) = <strong>v</strong>(<em>t</em> + ½Δ<em>t</em>) + ½ <strong>a</strong>(<em>t</em> + Δ<em>t</em>) · Δ<em>t</em>
|
||||
</div>
|
||||
<p>蛙跳法在长时间模拟中能量漂移极小(本案例验证 <strong>< 0.004%</strong>),适合无阻尼的保守系统。</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>2.2 时间步长与采样</h3>
|
||||
<table>
|
||||
<tr><th>参数</th><th>值</th><th>说明</th></tr>
|
||||
<tr><td>DT</td><td>0.01 s</td><td>积分步长(远小于 1/ω ≈ 0.16 s,满足稳定性条件)</td></tr>
|
||||
<tr><td>T_total</td><td>100 s</td><td>总模拟时间 → NT = 10000 步</td></tr>
|
||||
<tr><td>NSTEP</td><td>50</td><td>每 NSTEP 步取一帧用于动画 → 200 帧</td></tr>
|
||||
<tr><td>method</td><td>leapfrog</td><td>蛙跳法(Velocity-Verlet)</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>2.3 计算流程</h3>
|
||||
<div class="flow">
|
||||
<span class="flow-step">读入 coord.txt<br>connection.txt<br>bond.txt</span>
|
||||
<span class="flow-arrow">→</span>
|
||||
<span class="flow-step">施加驱动力<br>(驱动原子 1)</span>
|
||||
<span class="flow-arrow">→</span>
|
||||
<span class="flow-step">记录轨迹</span>
|
||||
<span class="flow-arrow">→</span>
|
||||
<span class="flow-step">蛙跳法<br>更新位置/速度</span>
|
||||
<span class="flow-arrow">→</span>
|
||||
<span class="flow-step">固定约束<br>(x, y 锁定)</span>
|
||||
<span class="flow-arrow">→</span>
|
||||
<span class="flow-step" style="background:#fef3c7;border-color:#f59e0b;">循环<br>NT 次</span>
|
||||
</div>
|
||||
<p style="margin-top:12px;">注意:驱动力在 <strong>每次积分前</strong> 施加,确保受驱原子的位置正确传递给弹簧力计算。</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 3. Driving Force -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="driver">
|
||||
<h2>三、驱动力模型</h2>
|
||||
|
||||
<div class="card">
|
||||
<h3>3.1 定义文件</h3>
|
||||
<p>驱动力由 <code>input/driver.txt</code> 定义,格式如下:</p>
|
||||
<pre>n amp_x amp_y amp_z freq_x freq_y freq_z phi_x phi_y phi_z period
|
||||
1 0 0 5 0 0 1 0 0 90 all</pre>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>3.2 数学公式</h3>
|
||||
<p>受驱原子的位置由下式决定(<strong>完全替换</strong> coord.txt 中的初始坐标和固定约束):</p>
|
||||
<div class="formula">
|
||||
<strong>r</strong>(<em>t</em>) = <strong>A</strong> · cos(2π<em>f</em> · <em>t</em> + <strong>φ</strong>)
|
||||
</div>
|
||||
<p>速度由解析导数给出:</p>
|
||||
<div class="formula">
|
||||
<strong>v</strong>(<em>t</em>) = −<strong>A</strong> · 2π<em>f</em> · sin(2π<em>f</em> · <em>t</em> + <strong>φ</strong>)
|
||||
</div>
|
||||
<p>其中 <strong>A</strong> = (amp_x, amp_y, amp_z),<strong>f</strong> = (freq_x, freq_y, freq_z) 为不同方向的驱动频率,<strong>φ</strong> = (phi_x, phi_y, phi_z) 为相位(<strong>角度制</strong>,代码自动转换为弧度)。</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>3.3 本案例驱动参数</h3>
|
||||
<table>
|
||||
<tr><th>参数</th><th>值</th><th>含义</th></tr>
|
||||
<tr><td>amp_z</td><td>5.0</td><td>z 方向驱动振幅</td></tr>
|
||||
<tr><td>freq_z</td><td>1.0 Hz</td><td>驱动频率(周期 1 s)</td></tr>
|
||||
<tr><td>phi_z</td><td>90°</td><td>驱动相位 → z(0) = 5·cos(90°) = 0</td></tr>
|
||||
<tr><td>period</td><td>all</td><td>全程驱动,永不停止</td></tr>
|
||||
</table>
|
||||
<div class="formula">
|
||||
<em>z</em>(<em>t</em>) = 5.0 · cos(2π · 1.0 · <em>t</em> + 90°)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>3.4 有限周期驱动</h3>
|
||||
<p><code>period</code> 参数支持三种模式:</p>
|
||||
<ul>
|
||||
<li><strong>all</strong> — 全程驱动</li>
|
||||
<li><strong>数值</strong> — 驱动指定周期数后 <strong>静止</strong>(冻结在最终位置,速度归零)。例如 <code>period: 1</code> 表示驱动 1 个完整周期后停止。</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>3.5 驱动与固定约束的关系</h3>
|
||||
<p>对于受驱原子(<code>driver.txt</code> 中 <code>n</code> 指定的原子),其在 <code>coord.txt</code> 中的初始坐标和 <code>fix_x/fix_y/fix_z</code> 约束被 <strong>完全忽略</strong>。原子的位置和速度完全由驱动力公式决定。</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 4. Usage -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="usage">
|
||||
<h2>四、使用方法</h2>
|
||||
|
||||
<div class="card">
|
||||
<h3>4.1 完整运行(模拟 + 动画)</h3>
|
||||
<pre>cd examples/case06
|
||||
python run_dynamics.py</pre>
|
||||
<p>这步会依次执行:物理模拟 → 抽帧 → 打开 VisPy 3D 动画窗口。</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>4.2 仅查看已有结果</h3>
|
||||
<p>如果已经跑完模拟且生成了 <code>output/display.txt</code>,可以通过修改 <code>input.txt</code> 跳过计算,只开动画:</p>
|
||||
<pre>step_simulate: 0 # 跳过模拟
|
||||
step_sample: 0 # 跳过抽帧
|
||||
step_animation: 1 # 播放动画</pre>
|
||||
<p>然后运行:<code>python run_dynamics.py</code></p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>4.3 手动 3D 动画</h3>
|
||||
<p>也可以单独启动 VisPy 窗口:</p>
|
||||
<pre>python ../../draw.py output/</pre>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>4.4 强制重新计算</h3>
|
||||
<p>修改参数后需要重新运行模拟时,设置:</p>
|
||||
<pre>force_calc: 1 # 忽略缓存,强制重新计算</pre>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>4.5 动画交互</h3>
|
||||
<table>
|
||||
<tr><th>操作</th><th>效果</th></tr>
|
||||
<tr><td>鼠标拖动</td><td>旋转视角</td></tr>
|
||||
<tr><td>滚轮</td><td>缩放</td></tr>
|
||||
<tr><td>W / S 键</td><td>相机沿 Z 轴向前 / 向后移动(靠近/远离场景)</td></tr>
|
||||
<tr><td>A / D 键</td><td>视角向右 / 向左平移</td></tr>
|
||||
<tr><td>E / Q 键</td><td>视角上升 / 下降(屏幕方向)</td></tr>
|
||||
<tr><td>C / X 键</td><td>增大 / 减小步长</td></tr>
|
||||
<tr><td>V 键</td><td>切换透视 / 正交投影</td></tr>
|
||||
<tr><td>左上角 <strong>reset</strong> 按钮</td><td>复位视角到初始位置</td></tr>
|
||||
<tr><td>左上角 <strong>info</strong> 按钮</td><td>切换信息面板显示/隐藏</td></tr>
|
||||
<tr><td>左上角 <strong>axes</strong> 按钮</td><td>切换坐标轴显示/隐藏</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 5. Parameters -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="params">
|
||||
<h2>五、参数参考</h2>
|
||||
|
||||
<div class="card">
|
||||
<h3>5.1 input.txt 关键参数</h3>
|
||||
<table>
|
||||
<tr><th>参数</th><th>默认值</th><th>说明</th></tr>
|
||||
<tr><td>gravity_field</td><td>0</td><td>均匀重力场(已关闭)</td></tr>
|
||||
<tr><td>gravity_interaction</td><td>0</td><td>原子间万有引力(已关闭)</td></tr>
|
||||
<tr><td>elastic_force</td><td>1</td><td>弹簧键力(已开启)</td></tr>
|
||||
<tr><td>damping_force</td><td>0</td><td>阻尼(已关闭)</td></tr>
|
||||
<tr><td><strong>driving_force</strong></td><td><strong>1</strong></td><td>驱动力开关(1=开启,需 driver.txt)</td></tr>
|
||||
<tr><td>method</td><td>leapfrog</td><td>数值积分方法</td></tr>
|
||||
<tr><td>DT</td><td>0.01</td><td>积分步长 (s)</td></tr>
|
||||
<tr><td>T_total</td><td>100.0</td><td>总模拟时间 (s)</td></tr>
|
||||
<tr><td>NSTEP</td><td>50</td><td>抽帧步数间隔</td></tr>
|
||||
<tr><td>engine</td><td>python</td><td>计算引擎(python / c / cpp / fortran)</td></tr>
|
||||
<tr><td>use_marker</td><td>1</td><td>渲染模式(0=Sphere 网格, 1=Marker GPU 实例化)</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>5.2 流程控制参数</h3>
|
||||
<table>
|
||||
<tr><th>参数</th><th>0</th><th>1</th></tr>
|
||||
<tr><td>step_simulate</td><td>跳过模拟(加载已有轨迹)</td><td>运行物理模拟</td></tr>
|
||||
<tr><td>step_sample</td><td>跳过抽帧</td><td>从轨迹抽取显示帧</td></tr>
|
||||
<tr><td>step_plot</td><td>不生成图表</td><td>生成轨迹/能量图</td></tr>
|
||||
<tr><td><strong>step_plot_wave</strong></td><td>不生成波形图</td><td>生成波形能量动画 GIF</td></tr>
|
||||
<tr><td>step_animation</td><td>不启动动画</td><td>自动打开 VisPy 3D 窗口</td></tr>
|
||||
<tr><td>force_calc</td><td>自动检测缓存</td><td>强制重新计算</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 6. File Structure -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="files">
|
||||
<h2>六、文件结构</h2>
|
||||
|
||||
<pre>case06/
|
||||
├── input/
|
||||
│ ├── input.txt # 主配置文件(YAML 格式)
|
||||
│ ├── coord.txt # 原子坐标(120 个原子)
|
||||
│ ├── connection.txt # 弹簧连接关系(59 条键)
|
||||
│ ├── bond.txt # 弹簧参数(k=1.0, L₀=1.0)
|
||||
│ └── <strong>driver.txt</strong> # <span class="cm">驱动力定义(本案例新增)</span>
|
||||
├── output/
|
||||
│ ├── trajectory.txt # 全量轨迹数据(50000 步 × 120 原子)
|
||||
│ ├── display.txt # 抽帧后的动画数据(500 帧 × 120 原子)
|
||||
│ ├── dynamics.log # 计算日志
|
||||
│ ├── animation.log # 动画启动日志(闪退时排查用)
|
||||
│ └── wave_animation.gif # 波形能量动画(step_plot_wave=1 时生成)
|
||||
├── doc/
|
||||
│ └── index.html # <span class="cm">本文档</span>
|
||||
├── Readme.md # 案例简介
|
||||
└── run_dynamics.py # 案例运行入口</pre>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 7. Troubleshooting -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="troubleshoot">
|
||||
<h2>七、常见问题</h2>
|
||||
|
||||
<div class="card">
|
||||
<h3>7.1 动画窗口闪退</h3>
|
||||
<p>如果 VisPy 窗口一闪就消失,请检查:</p>
|
||||
<ul>
|
||||
<li><code>output/animation.log</code> 中是否有错误信息</li>
|
||||
<li><code>output/display.txt</code> 是否存在(需先跑 <code>step_sample: 1</code>)</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>7.2 原子不振动</h3>
|
||||
<p>可能原因:</p>
|
||||
<ul>
|
||||
<li><strong>NSTEP 过大</strong>:抽帧间隔大于驱动周期的一半时,动画会丢失振动细节。建议 NSTEP ≤ 1/(freq · DT · 10)</li>
|
||||
<li><strong>相位 φ 使采样点落在零值</strong>:试试 <code>phi_z: 0</code> 让原子在 t=0 处于振幅峰值</li>
|
||||
<li>确认 <code>driving_force: 1</code> 且 <code>driver.txt</code> 中 amp_z 不为 0</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>7.3 渲染性能慢</h3>
|
||||
<p>原子数多时动画卡顿:</p>
|
||||
<ul>
|
||||
<li>设置 <code>use_marker: 1</code>(使用 GPU 实例化渲染替代独立网格球体)</li>
|
||||
<li>增大 <code>NSTEP</code> 减少动画帧数</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<hr style="border:none;border-top:1px solid var(--border);margin:40px 0;">
|
||||
|
||||
<footer style="text-align:center;color:var(--muted);font-size:0.85rem;margin-bottom:40px;">
|
||||
Dynamics Simulation Framework · 生成于 2026-06-10
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,2 @@
|
||||
bond_name k rest_length
|
||||
k1 0.1 1.0
|
||||
@@ -0,0 +1,2 @@
|
||||
n1 n2 bond_name
|
||||
1 2 k1
|
||||
@@ -0,0 +1,3 @@
|
||||
n mass radius x y z vx vy vz fix_x fix_y fix_z
|
||||
1 1 0.1 0 0 0 0 0 0 0 1 0
|
||||
2 1 0.1 1 0 0 0 0 0 0 1 0
|
||||
@@ -0,0 +1,2 @@
|
||||
n amp_x amp_y amp_z freq_x freq_y freq_z phi_x phi_y phi_z period
|
||||
1 0.1 0 0.0 0.02 0 0 90 0 0 all
|
||||
@@ -0,0 +1,114 @@
|
||||
# 物理模拟参数配置
|
||||
# 格式:YAML
|
||||
# 用法:python run_dynamics.py
|
||||
|
||||
# ── 流程控制 ──────────────────────────────────
|
||||
# 每步用 0/1 单独开关,1=执行,0=跳过
|
||||
# 依赖关系:抽帧依赖模拟结果,绘图依赖模拟+抽帧
|
||||
step_simulate: 1 # 运行物理模拟 → output/display.txt(引擎直接抽帧)
|
||||
step_sample: 0 # (旧版)从 trajectory.txt 重新抽帧,默认0=不执行
|
||||
step_plot: 0 # 绘制轨迹/能量图 → output/trajectory_plots.png
|
||||
step_animation: 0 # 自动播放 VisPy 3D 动画窗口(需安装 vispy)
|
||||
step_plot_wave: 1 # 绘制波形能量动画
|
||||
force_calc: 1 # 强制重新计算:1=跳过缓存强算,0=自动使用已有输出
|
||||
plot_wave_save_gif: 0 # 输出波形 GIF(需 step_plot_wave=1)
|
||||
plot_wave_save_mp4: 0 # 输出波形 MP4(需 step_plot_wave=1)
|
||||
|
||||
# ── 文件保存 ──────────────────────────────────
|
||||
save_trajectory: 0 # 0=不保留完整轨迹文件, 1=保留 trajectory.txt(用于后续单独抽帧)
|
||||
|
||||
# ── 计算引擎 ──────────────────────────────────
|
||||
# 可选: python, c, cpp, fortran, java
|
||||
engine: c # 默认使用 python 引擎
|
||||
|
||||
# ── 盒子 ──────────────────────────────────────
|
||||
box_a: 300.0 # 立方体半边长,粒子被限制在 [-box_a, box_a]³ 内
|
||||
|
||||
# ── 初始构型 ──────────────────────────────────
|
||||
# 坐标文件格式:
|
||||
# 第一行:n mass radius x y z vx vy vz fix_x fix_y fix_z
|
||||
# 后续行:原子序号 质量 半径 x y z vx vy vz fix_x fix_y fix_z
|
||||
coord_file: input/coord.txt
|
||||
connection_file: input/connection.txt
|
||||
bond_file: input/bond.txt
|
||||
driver_file: input/driver.txt # 驱动力定义文件(driving_force=1 时生效)
|
||||
|
||||
# 绘图/动画展示的原子序号(对应 coord_file 第一列 n)
|
||||
plot_atom: 1
|
||||
|
||||
# ── 物理参数 ──────────────────────────────────
|
||||
# 三个方向分量分别对应 x, y, z
|
||||
G: [0.000, 0.000, 0.000] # 重力场分量 (m/s²)
|
||||
B: [0.005, 0.000, 0.005] # 阻尼分量
|
||||
|
||||
# ── 力开关(0=关闭, 1=开启)──────────────────
|
||||
gravity_field: 0 # 均匀重力场 (G)
|
||||
gravity_interaction: 0 # 原子间万有引力
|
||||
elastic_force: 1 # 弹簧键力
|
||||
damping_force: 1 # 阻尼 (B)
|
||||
driving_force: 1 # 驱动力(需 driver_file 定义)
|
||||
#
|
||||
gravity_strength: 1.0 # 万有引力强度(仅 gravity_interaction=1 时有效)
|
||||
|
||||
# ── 数值算法 ──────────────────────────────────
|
||||
# 可选:
|
||||
# explicit_euler 显式欧拉法
|
||||
# implicit_euler 隐式欧拉法
|
||||
# midpoint 中点法
|
||||
# leapfrog 蛙跳法
|
||||
method: leapfrog
|
||||
|
||||
# ── 步骤控制 ──────────────────────────────────
|
||||
# 以下参数控制哪些步骤被执行和保存
|
||||
|
||||
# 预热步数:模拟开始时跳过不保存的步数(用于稳定初始状态)
|
||||
warmup_steps: 0 # 默认 0(立即开始记录)
|
||||
|
||||
# 总模拟时间(秒),程序自动计算 NT = T_total / DT
|
||||
# 如果同时指定了 NT,以 NT 为准
|
||||
T_total: 100.0
|
||||
|
||||
# 抽帧间隔(每 NSTEP 步取一帧用于动画)
|
||||
NSTEP: 500
|
||||
|
||||
# ── 时间步长 ──────────────────────────────────
|
||||
DT: 0.001 # 时间步长 (s)
|
||||
|
||||
# 抽帧范围:只保存 [sample_start, sample_end) 区间内的帧
|
||||
sample_start: null # null 表示从头开始(帧索引从 0 起)
|
||||
sample_end: null # null 表示到末尾
|
||||
|
||||
|
||||
|
||||
# ── 渲染方式 ──────────────────────────────────
|
||||
# 3D 动画中原子渲染方式:
|
||||
# 0 = Sphere (网格球体,效果精细,原子数少时推荐)
|
||||
# 1 = Marker (GPU 实例化点,原子数多时性能更佳)
|
||||
use_marker: 1
|
||||
|
||||
# ── 显示参数 ──────────────────────────────────
|
||||
# 盒子透明度:单个数值(统一)或 6 个数的数组,按 [-x,+x,-y,+y,-z,+z] 顺序
|
||||
alpha: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
|
||||
|
||||
# 小球颜色
|
||||
# 小球半径从 coord_file 的 radius 列读取
|
||||
ball_color_r: 0.20 # R 分量 (0~1)
|
||||
ball_color_g: 0.60 # G 分量
|
||||
ball_color_b: 0.90 # B 分量
|
||||
|
||||
# 盒子面颜色
|
||||
box_color_r: 0.80
|
||||
box_color_g: 0.80
|
||||
box_color_b: 0.85
|
||||
|
||||
# ── 摄像机初始位置 ────────────────────────────
|
||||
camera_distance: 10.0 # 摄像机到场景中心的距离
|
||||
camera_elevation: 0.0 # 俯仰角(度),负值=俯视
|
||||
camera_azimuth: 0.0 # 方位角(度)
|
||||
camera_center_x: 0.0 # 摄像机注视点 x
|
||||
camera_center_y: 0.0 # 摄像机注视点 y
|
||||
camera_center_z: 0.0 # 摄像机注视点 z
|
||||
move_camera: 0 # 0=固定视角, 1=按 move_camera.txt 运动
|
||||
|
||||
# ── 视觉放大 ──────────────────────────────────
|
||||
display_amp: [1.0, 1.0, 10.0] # x/y/z 方向视觉位移放大倍数(不影响物理)
|
||||
@@ -0,0 +1,9 @@
|
||||
# move_camera.txt — 摄像机速度段驱动
|
||||
# 格式: start-end vx=f vy=f vz=f rx=d ry=d rz=d
|
||||
# vx/vy/vz: 平移速度(每帧移动单位)
|
||||
# rx/ry/rz: 旋转速度(每帧度数)
|
||||
# rx → elevation(俯仰), ry → azimuth(方位), rz → (预留)
|
||||
#
|
||||
# 示例:前60帧向右平移+绕x旋转,30-90帧向上平移+绕y绕z旋转
|
||||
all vx=0.02
|
||||
# 30-90 vy=0.02 ry=1 rz=1
|
||||
@@ -0,0 +1,54 @@
|
||||
"""
|
||||
Case runner for Dynamics case06 — 1D atomic chain (transverse wave).
|
||||
|
||||
This script keeps program and data separated:
|
||||
- program: ../../dynamics.py
|
||||
- input: ./input
|
||||
- output: ./output
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
CASE_DIR = Path(__file__).resolve().parent
|
||||
DYNAMICS_PATH = Path("..") / ".." / "dynamics.py"
|
||||
INPUT_DIR = Path("input")
|
||||
OUTPUT_DIR = Path("output")
|
||||
CONFIG_FILE = INPUT_DIR / "input.txt"
|
||||
|
||||
|
||||
def load_dynamics_module(module_path: Path):
|
||||
spec = importlib.util.spec_from_file_location("dynamics_module", module_path)
|
||||
if spec is None or spec.loader is None:
|
||||
raise ImportError(f"无法加载 dynamics.py: {module_path}")
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="运行 Dynamics 示例案例 case06")
|
||||
parser.add_argument("--no-plot", action="store_true", help="跳过 matplotlib 绘图")
|
||||
args = parser.parse_args()
|
||||
|
||||
dynamics_path = (CASE_DIR / DYNAMICS_PATH).resolve()
|
||||
input_dir = (CASE_DIR / INPUT_DIR).resolve()
|
||||
output_dir = (CASE_DIR / OUTPUT_DIR).resolve()
|
||||
config_path = (CASE_DIR / CONFIG_FILE).resolve()
|
||||
|
||||
module = load_dynamics_module(dynamics_path)
|
||||
module.run_case(
|
||||
config_path=config_path,
|
||||
runtime_base=CASE_DIR,
|
||||
input_dir=input_dir,
|
||||
output_dir=output_dir,
|
||||
no_plot=args.no_plot,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,40 @@
|
||||
# case06: 一维原子链横波模拟
|
||||
|
||||
60 个原子沿 x 轴排列,相邻原子用弹簧连接。原子 1 受 z 方向驱动力作用,产生沿链传播的横波。
|
||||
|
||||
## 物理设定
|
||||
|
||||
| 参数 | 值 |
|
||||
|---|---|
|
||||
| 原子数 | 120 |
|
||||
| 排列 | 沿 x 轴等间距排列,间距为 1 |
|
||||
| 约束 | 原子**沿 z 方向自由振动**(fix_x=1, fix_y=1, fix_z=0),x, y 锁定 |
|
||||
| 弹簧 | 劲度系数 k=1.0,原长 L₀=1.0 |
|
||||
| 重力 | 无 |
|
||||
| 万有引力 | 无 |
|
||||
| 阻尼 | 无 |
|
||||
| 驱动力 | 原子 1(z 方向驱动) |
|
||||
| 算法 | leapfrog(蛙跳法,能量守恒) |
|
||||
|
||||
## 驱动力
|
||||
|
||||
原子 1 的位置由 `input/driver.txt` 中的驱动力公式决定:
|
||||
|
||||
```math
|
||||
z(t) = A_z \cdot \cos(2\pi f_z t + \phi_z)
|
||||
```
|
||||
|
||||
当前参数:A_z = 0.5, f_z = 0.1 Hz, φ_z = 90°, period = all(全程驱动)。
|
||||
|
||||
## 动力学行为
|
||||
|
||||
原子 1 沿 z 方向的受迫振动通过弹簧逐次传递给相邻原子,形成沿链传播的**横波**。由于 z 方向的振动是横向的,弹簧大部分张力在 x 方向,z 方向的有效刚度是非线性的——等效于一个三次方恢复力(FPU 型非线性),因此波速较慢。
|
||||
|
||||
## 使用方法
|
||||
|
||||
```bash
|
||||
cd examples/case06
|
||||
python run_dynamics.py
|
||||
```
|
||||
|
||||
配置参数详见 `input/input.txt`,驱动力定义见 `input/driver.txt`,完整文档见 `doc/index.html`。
|
||||
@@ -0,0 +1,477 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>case06 — 一维原子链驱动力学模拟 | 物理原理 & 使用文档</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #f8f9fa;
|
||||
--card: #fff;
|
||||
--text: #1a1a2e;
|
||||
--accent: #2563eb;
|
||||
--accent-light: #dbeafe;
|
||||
--code-bg: #1e293b;
|
||||
--code-text: #e2e8f0;
|
||||
--border: #e2e8f0;
|
||||
--muted: #64748b;
|
||||
}
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Noto Sans SC", sans-serif;
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
/* ── Header ── */
|
||||
.hero {
|
||||
background: linear-gradient(135deg, #1e293b 0%, #334155 100%);
|
||||
color: #fff;
|
||||
padding: 56px 24px 48px;
|
||||
text-align: center;
|
||||
}
|
||||
.hero h1 { font-size: 2rem; font-weight: 700; letter-spacing: -0.02em; }
|
||||
.hero .subtitle {
|
||||
margin-top: 10px;
|
||||
font-size: 1.05rem;
|
||||
opacity: 0.8;
|
||||
}
|
||||
.hero .badge {
|
||||
display: inline-block;
|
||||
margin-top: 14px;
|
||||
padding: 4px 14px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255,255,255,0.12);
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
|
||||
/* ── Layout ── */
|
||||
.container { max-width: 820px; margin: 0 auto; padding: 32px 20px; }
|
||||
|
||||
section { margin-bottom: 44px; }
|
||||
h2 {
|
||||
font-size: 1.35rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 2px solid var(--accent);
|
||||
display: inline-block;
|
||||
}
|
||||
h3 {
|
||||
font-size: 1.05rem;
|
||||
font-weight: 600;
|
||||
margin: 20px 0 10px;
|
||||
}
|
||||
|
||||
p, li { margin-bottom: 10px; }
|
||||
ul, ol { padding-left: 22px; }
|
||||
strong { color: var(--accent); }
|
||||
|
||||
/* ── Cards ── */
|
||||
.card {
|
||||
background: var(--card);
|
||||
border-radius: 12px;
|
||||
padding: 20px 24px;
|
||||
margin-bottom: 16px;
|
||||
border: 1px solid var(--border);
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.04);
|
||||
}
|
||||
|
||||
/* ── Formula / Code blocks ── */
|
||||
.formula {
|
||||
background: var(--card);
|
||||
border-left: 4px solid var(--accent);
|
||||
padding: 14px 20px;
|
||||
margin: 14px 0;
|
||||
font-family: "Times New Roman", "STIX", serif;
|
||||
font-size: 1.05rem;
|
||||
overflow-x: auto;
|
||||
border-radius: 0 8px 8px 0;
|
||||
}
|
||||
code {
|
||||
background: var(--accent-light);
|
||||
padding: 2px 7px;
|
||||
border-radius: 4px;
|
||||
font-family: "JetBrains Mono", "Fira Code", monospace;
|
||||
font-size: 0.88em;
|
||||
}
|
||||
pre {
|
||||
background: var(--code-bg);
|
||||
color: var(--code-text);
|
||||
padding: 16px 20px;
|
||||
border-radius: 10px;
|
||||
overflow-x: auto;
|
||||
font-size: 0.85rem;
|
||||
line-height: 1.5;
|
||||
margin: 14px 0;
|
||||
}
|
||||
pre .cm { color: #94a3b8; font-style: italic; } /* comment */
|
||||
|
||||
/* ── Table ── */
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 14px 0;
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
th, td {
|
||||
padding: 8px 12px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
th { background: var(--accent-light); font-weight: 600; }
|
||||
|
||||
/* ── TOC ── */
|
||||
.toc { counter-reset: toc; }
|
||||
.toc li { counter-increment: toc; list-style: none; margin-bottom: 6px; }
|
||||
.toc li::before { content: counter(toc) ". "; font-weight: 600; color: var(--accent); }
|
||||
.toc a { color: var(--accent); text-decoration: none; }
|
||||
.toc a:hover { text-decoration: underline; }
|
||||
|
||||
/* ── Flow diagram ── */
|
||||
.flow { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; justify-content: center; margin: 16px 0; }
|
||||
.flow-step {
|
||||
background: var(--accent-light);
|
||||
border: 1px solid var(--accent);
|
||||
border-radius: 8px;
|
||||
padding: 8px 16px;
|
||||
font-size: 0.88rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
.flow-arrow { color: var(--muted); font-size: 1.2rem; }
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.hero h1 { font-size: 1.5rem; }
|
||||
.flow { flex-direction: column; }
|
||||
.flow-arrow { transform: rotate(90deg); }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- Header -->
|
||||
<!-- ============================================================ -->
|
||||
<header class="hero">
|
||||
<h1>一维原子链驱动力学模拟</h1>
|
||||
<p class="subtitle">120 个原子沿 x 轴排列 · 弹簧连接 · z 方向受迫振动</p>
|
||||
<span class="badge">case06 · examples/case06</span>
|
||||
</header>
|
||||
|
||||
<div class="container">
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- TOC -->
|
||||
<!-- ============================================================ -->
|
||||
<section>
|
||||
<h2>目录</h2>
|
||||
<ol class="toc">
|
||||
<li><a href="#physics">物理原理</a></li>
|
||||
<li><a href="#algorithm">数值算法</a></li>
|
||||
<li><a href="#driver">驱动力模型</a></li>
|
||||
<li><a href="#usage">使用方法</a></li>
|
||||
<li><a href="#params">参数参考</a></li>
|
||||
<li><a href="#files">文件结构</a></li>
|
||||
<li><a href="#troubleshoot">常见问题</a></li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 1. Physics -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="physics">
|
||||
<h2>一、物理原理</h2>
|
||||
|
||||
<div class="card">
|
||||
<h3>1.1 一维原子链</h3>
|
||||
<p>120 个原子沿 <strong>x 轴</strong> 等间距排列,原子间距为 1。相邻原子之间用 <strong>理想弹簧</strong> 连接,弹簧的劲度系数 <em>k</em> = 1.0,原长 <em>L</em>₀ = 1.0(与原子间距一致,初始状态弹簧无拉伸)。</p>
|
||||
<p>每个原子被限制在 <strong>z 方向</strong> 自由振动,x 和 y 方向锁定(<code>fix_x=1, fix_y=1, fix_z=0</code>)。</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>1.2 弹簧力(胡克定律)</h3>
|
||||
<p>当原子 <em>i</em> 和 <em>j</em> 之间有弹簧连接时,原子 <em>i</em> 受到的弹簧力为:</p>
|
||||
<div class="formula">
|
||||
<strong>F</strong> = −<em>k</em> · (<em>d</em> − <em>L</em>₀) · <strong>u</strong><sub><em>ij</em></sub>
|
||||
</div>
|
||||
<p>其中 <em>d</em> = |<strong>r</strong><sub><em>j</em></sub> − <strong>r</strong><sub><em>i</em></sub>| 为两原子间距离,<strong>u</strong><sub><em>ij</em></sub> 为从 <em>i</em> 指向 <em>j</em> 的单位向量。由于原子只在 z 方向振动,弹簧在 z 方向的分量是 <strong>几何非线性</strong> 的——对于小振幅近似,z 方向等效于一个三次方恢复力(FPU 型非线性)。</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>1.3 运动方程</h3>
|
||||
<p>对于第 <em>i</em> 个自由原子(非受驱),牛顿第二定律给出:</p>
|
||||
<div class="formula">
|
||||
<em>m</em> · <strong>a</strong><sub><em>i</em></sub> = <strong>F</strong><sub><em>i</em></sub><sup>spring</sup> + <strong>F</strong><sub><em>i</em></sub><sup>driving</sup>
|
||||
</div>
|
||||
<p>本案例中 <strong>唯一的外力</strong> 来自驱动力(仅施加于原子 1)。无重力、无万有引力、无阻尼,系统总能量守恒。</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>1.4 波传播</h3>
|
||||
<p>原子 1 的受迫振动通过弹簧逐次传递给相邻原子,形成沿链传播的 <strong>横波</strong>。由于横向振动的几何非线性(弹簧大部分张力在 x 方向,z 方向的有效刚度远小于 1),波的传播速度较慢,且高阶频率成分会在链中产生复杂的非线性动力学行为(类似 FPU 回波现象)。</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 2. Algorithm -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="algorithm">
|
||||
<h2>二、数值算法</h2>
|
||||
|
||||
<div class="card">
|
||||
<h3>2.1 蛙跳法(Leapfrog / Velocity-Verlet)</h3>
|
||||
<p>采用能量守恒特性优异的 <strong>蛙跳法</strong>(二阶辛积分器),更新公式为:</p>
|
||||
<div class="formula">
|
||||
<strong>v</strong>(<em>t</em> + ½Δ<em>t</em>) = <strong>v</strong>(<em>t</em>) + ½ <strong>a</strong>(<em>t</em>) · Δ<em>t</em><br>
|
||||
<strong>r</strong>(<em>t</em> + Δ<em>t</em>) = <strong>r</strong>(<em>t</em>) + <strong>v</strong>(<em>t</em> + ½Δ<em>t</em>) · Δ<em>t</em><br>
|
||||
<strong>a</strong>(<em>t</em> + Δ<em>t</em>) = <strong>F</strong>(<strong>r</strong>(<em>t</em> + Δ<em>t</em>), <strong>v</strong>(<em>t</em> + ½Δ<em>t</em>)) / <em>m</em><br>
|
||||
<strong>v</strong>(<em>t</em> + Δ<em>t</em>) = <strong>v</strong>(<em>t</em> + ½Δ<em>t</em>) + ½ <strong>a</strong>(<em>t</em> + Δ<em>t</em>) · Δ<em>t</em>
|
||||
</div>
|
||||
<p>蛙跳法在长时间模拟中能量漂移极小(本案例验证 <strong>< 0.004%</strong>),适合无阻尼的保守系统。</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>2.2 时间步长与采样</h3>
|
||||
<table>
|
||||
<tr><th>参数</th><th>值</th><th>说明</th></tr>
|
||||
<tr><td>DT</td><td>0.01 s</td><td>积分步长(远小于 1/ω ≈ 0.16 s,满足稳定性条件)</td></tr>
|
||||
<tr><td>T_total</td><td>100 s</td><td>总模拟时间 → NT = 10000 步</td></tr>
|
||||
<tr><td>NSTEP</td><td>50</td><td>每 NSTEP 步取一帧用于动画 → 200 帧</td></tr>
|
||||
<tr><td>method</td><td>leapfrog</td><td>蛙跳法(Velocity-Verlet)</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>2.3 计算流程</h3>
|
||||
<div class="flow">
|
||||
<span class="flow-step">读入 coord.txt<br>connection.txt<br>bond.txt</span>
|
||||
<span class="flow-arrow">→</span>
|
||||
<span class="flow-step">施加驱动力<br>(驱动原子 1)</span>
|
||||
<span class="flow-arrow">→</span>
|
||||
<span class="flow-step">记录轨迹</span>
|
||||
<span class="flow-arrow">→</span>
|
||||
<span class="flow-step">蛙跳法<br>更新位置/速度</span>
|
||||
<span class="flow-arrow">→</span>
|
||||
<span class="flow-step">固定约束<br>(x, y 锁定)</span>
|
||||
<span class="flow-arrow">→</span>
|
||||
<span class="flow-step" style="background:#fef3c7;border-color:#f59e0b;">循环<br>NT 次</span>
|
||||
</div>
|
||||
<p style="margin-top:12px;">注意:驱动力在 <strong>每次积分前</strong> 施加,确保受驱原子的位置正确传递给弹簧力计算。</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 3. Driving Force -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="driver">
|
||||
<h2>三、驱动力模型</h2>
|
||||
|
||||
<div class="card">
|
||||
<h3>3.1 定义文件</h3>
|
||||
<p>驱动力由 <code>input/driver.txt</code> 定义,格式如下:</p>
|
||||
<pre>n amp_x amp_y amp_z freq_x freq_y freq_z phi_x phi_y phi_z period
|
||||
1 0 0 5 0 0 1 0 0 90 all</pre>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>3.2 数学公式</h3>
|
||||
<p>受驱原子的位置由下式决定(<strong>完全替换</strong> coord.txt 中的初始坐标和固定约束):</p>
|
||||
<div class="formula">
|
||||
<strong>r</strong>(<em>t</em>) = <strong>A</strong> · cos(2π<em>f</em> · <em>t</em> + <strong>φ</strong>)
|
||||
</div>
|
||||
<p>速度由解析导数给出:</p>
|
||||
<div class="formula">
|
||||
<strong>v</strong>(<em>t</em>) = −<strong>A</strong> · 2π<em>f</em> · sin(2π<em>f</em> · <em>t</em> + <strong>φ</strong>)
|
||||
</div>
|
||||
<p>其中 <strong>A</strong> = (amp_x, amp_y, amp_z),<strong>f</strong> = (freq_x, freq_y, freq_z) 为不同方向的驱动频率,<strong>φ</strong> = (phi_x, phi_y, phi_z) 为相位(<strong>角度制</strong>,代码自动转换为弧度)。</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>3.3 本案例驱动参数</h3>
|
||||
<table>
|
||||
<tr><th>参数</th><th>值</th><th>含义</th></tr>
|
||||
<tr><td>amp_z</td><td>5.0</td><td>z 方向驱动振幅</td></tr>
|
||||
<tr><td>freq_z</td><td>1.0 Hz</td><td>驱动频率(周期 1 s)</td></tr>
|
||||
<tr><td>phi_z</td><td>90°</td><td>驱动相位 → z(0) = 5·cos(90°) = 0</td></tr>
|
||||
<tr><td>period</td><td>all</td><td>全程驱动,永不停止</td></tr>
|
||||
</table>
|
||||
<div class="formula">
|
||||
<em>z</em>(<em>t</em>) = 5.0 · cos(2π · 1.0 · <em>t</em> + 90°)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>3.4 有限周期驱动</h3>
|
||||
<p><code>period</code> 参数支持三种模式:</p>
|
||||
<ul>
|
||||
<li><strong>all</strong> — 全程驱动</li>
|
||||
<li><strong>数值</strong> — 驱动指定周期数后 <strong>静止</strong>(冻结在最终位置,速度归零)。例如 <code>period: 1</code> 表示驱动 1 个完整周期后停止。</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>3.5 驱动与固定约束的关系</h3>
|
||||
<p>对于受驱原子(<code>driver.txt</code> 中 <code>n</code> 指定的原子),其在 <code>coord.txt</code> 中的初始坐标和 <code>fix_x/fix_y/fix_z</code> 约束被 <strong>完全忽略</strong>。原子的位置和速度完全由驱动力公式决定。</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 4. Usage -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="usage">
|
||||
<h2>四、使用方法</h2>
|
||||
|
||||
<div class="card">
|
||||
<h3>4.1 完整运行(模拟 + 动画)</h3>
|
||||
<pre>cd examples/case06
|
||||
python run_dynamics.py</pre>
|
||||
<p>这步会依次执行:物理模拟 → 抽帧 → 打开 VisPy 3D 动画窗口。</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>4.2 仅查看已有结果</h3>
|
||||
<p>如果已经跑完模拟且生成了 <code>output/display.txt</code>,可以通过修改 <code>input.txt</code> 跳过计算,只开动画:</p>
|
||||
<pre>step_simulate: 0 # 跳过模拟
|
||||
step_sample: 0 # 跳过抽帧
|
||||
step_animation: 1 # 播放动画</pre>
|
||||
<p>然后运行:<code>python run_dynamics.py</code></p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>4.3 手动 3D 动画</h3>
|
||||
<p>也可以单独启动 VisPy 窗口:</p>
|
||||
<pre>python ../../draw.py output/</pre>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>4.4 强制重新计算</h3>
|
||||
<p>修改参数后需要重新运行模拟时,设置:</p>
|
||||
<pre>force_calc: 1 # 忽略缓存,强制重新计算</pre>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>4.5 动画交互</h3>
|
||||
<table>
|
||||
<tr><th>操作</th><th>效果</th></tr>
|
||||
<tr><td>鼠标拖动</td><td>旋转视角</td></tr>
|
||||
<tr><td>滚轮</td><td>缩放</td></tr>
|
||||
<tr><td>W / S 键</td><td>相机沿 Z 轴向前 / 向后移动(靠近/远离场景)</td></tr>
|
||||
<tr><td>A / D 键</td><td>视角向右 / 向左平移</td></tr>
|
||||
<tr><td>E / Q 键</td><td>视角上升 / 下降(屏幕方向)</td></tr>
|
||||
<tr><td>C / X 键</td><td>增大 / 减小步长</td></tr>
|
||||
<tr><td>V 键</td><td>切换透视 / 正交投影</td></tr>
|
||||
<tr><td>左上角 <strong>reset</strong> 按钮</td><td>复位视角到初始位置</td></tr>
|
||||
<tr><td>左上角 <strong>info</strong> 按钮</td><td>切换信息面板显示/隐藏</td></tr>
|
||||
<tr><td>左上角 <strong>axes</strong> 按钮</td><td>切换坐标轴显示/隐藏</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 5. Parameters -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="params">
|
||||
<h2>五、参数参考</h2>
|
||||
|
||||
<div class="card">
|
||||
<h3>5.1 input.txt 关键参数</h3>
|
||||
<table>
|
||||
<tr><th>参数</th><th>默认值</th><th>说明</th></tr>
|
||||
<tr><td>gravity_field</td><td>0</td><td>均匀重力场(已关闭)</td></tr>
|
||||
<tr><td>gravity_interaction</td><td>0</td><td>原子间万有引力(已关闭)</td></tr>
|
||||
<tr><td>elastic_force</td><td>1</td><td>弹簧键力(已开启)</td></tr>
|
||||
<tr><td>damping_force</td><td>0</td><td>阻尼(已关闭)</td></tr>
|
||||
<tr><td><strong>driving_force</strong></td><td><strong>1</strong></td><td>驱动力开关(1=开启,需 driver.txt)</td></tr>
|
||||
<tr><td>method</td><td>leapfrog</td><td>数值积分方法</td></tr>
|
||||
<tr><td>DT</td><td>0.01</td><td>积分步长 (s)</td></tr>
|
||||
<tr><td>T_total</td><td>100.0</td><td>总模拟时间 (s)</td></tr>
|
||||
<tr><td>NSTEP</td><td>50</td><td>抽帧步数间隔</td></tr>
|
||||
<tr><td>engine</td><td>python</td><td>计算引擎(python / c / cpp / fortran)</td></tr>
|
||||
<tr><td>use_marker</td><td>1</td><td>渲染模式(0=Sphere 网格, 1=Marker GPU 实例化)</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>5.2 流程控制参数</h3>
|
||||
<table>
|
||||
<tr><th>参数</th><th>0</th><th>1</th></tr>
|
||||
<tr><td>step_simulate</td><td>跳过模拟(加载已有轨迹)</td><td>运行物理模拟</td></tr>
|
||||
<tr><td>step_sample</td><td>跳过抽帧</td><td>从轨迹抽取显示帧</td></tr>
|
||||
<tr><td>step_plot</td><td>不生成图表</td><td>生成轨迹/能量图</td></tr>
|
||||
<tr><td><strong>step_plot_wave</strong></td><td>不生成波形图</td><td>生成波形能量动画 GIF</td></tr>
|
||||
<tr><td>step_animation</td><td>不启动动画</td><td>自动打开 VisPy 3D 窗口</td></tr>
|
||||
<tr><td>force_calc</td><td>自动检测缓存</td><td>强制重新计算</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 6. File Structure -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="files">
|
||||
<h2>六、文件结构</h2>
|
||||
|
||||
<pre>case06/
|
||||
├── input/
|
||||
│ ├── input.txt # 主配置文件(YAML 格式)
|
||||
│ ├── coord.txt # 原子坐标(120 个原子)
|
||||
│ ├── connection.txt # 弹簧连接关系(59 条键)
|
||||
│ ├── bond.txt # 弹簧参数(k=1.0, L₀=1.0)
|
||||
│ └── <strong>driver.txt</strong> # <span class="cm">驱动力定义(本案例新增)</span>
|
||||
├── output/
|
||||
│ ├── trajectory.txt # 全量轨迹数据(50000 步 × 120 原子)
|
||||
│ ├── display.txt # 抽帧后的动画数据(500 帧 × 120 原子)
|
||||
│ ├── dynamics.log # 计算日志
|
||||
│ ├── animation.log # 动画启动日志(闪退时排查用)
|
||||
│ └── wave_animation.gif # 波形能量动画(step_plot_wave=1 时生成)
|
||||
├── doc/
|
||||
│ └── index.html # <span class="cm">本文档</span>
|
||||
├── Readme.md # 案例简介
|
||||
└── run_dynamics.py # 案例运行入口</pre>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 7. Troubleshooting -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="troubleshoot">
|
||||
<h2>七、常见问题</h2>
|
||||
|
||||
<div class="card">
|
||||
<h3>7.1 动画窗口闪退</h3>
|
||||
<p>如果 VisPy 窗口一闪就消失,请检查:</p>
|
||||
<ul>
|
||||
<li><code>output/animation.log</code> 中是否有错误信息</li>
|
||||
<li><code>output/display.txt</code> 是否存在(需先跑 <code>step_sample: 1</code>)</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>7.2 原子不振动</h3>
|
||||
<p>可能原因:</p>
|
||||
<ul>
|
||||
<li><strong>NSTEP 过大</strong>:抽帧间隔大于驱动周期的一半时,动画会丢失振动细节。建议 NSTEP ≤ 1/(freq · DT · 10)</li>
|
||||
<li><strong>相位 φ 使采样点落在零值</strong>:试试 <code>phi_z: 0</code> 让原子在 t=0 处于振幅峰值</li>
|
||||
<li>确认 <code>driving_force: 1</code> 且 <code>driver.txt</code> 中 amp_z 不为 0</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>7.3 渲染性能慢</h3>
|
||||
<p>原子数多时动画卡顿:</p>
|
||||
<ul>
|
||||
<li>设置 <code>use_marker: 1</code>(使用 GPU 实例化渲染替代独立网格球体)</li>
|
||||
<li>增大 <code>NSTEP</code> 减少动画帧数</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<hr style="border:none;border-top:1px solid var(--border);margin:40px 0;">
|
||||
|
||||
<footer style="text-align:center;color:var(--muted);font-size:0.85rem;margin-bottom:40px;">
|
||||
Dynamics Simulation Framework · 生成于 2026-06-10
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,2 @@
|
||||
bond_name k rest_length
|
||||
k1 300.0 1.0
|
||||
@@ -0,0 +1,40 @@
|
||||
n1 n2 bond_name
|
||||
1 2 k1
|
||||
2 3 k1
|
||||
3 4 k1
|
||||
4 5 k1
|
||||
5 6 k1
|
||||
6 7 k1
|
||||
7 8 k1
|
||||
8 9 k1
|
||||
9 10 k1
|
||||
10 11 k1
|
||||
11 12 k1
|
||||
12 13 k1
|
||||
13 14 k1
|
||||
14 15 k1
|
||||
15 16 k1
|
||||
16 17 k1
|
||||
17 18 k1
|
||||
18 19 k1
|
||||
19 20 k1
|
||||
20 21 k1
|
||||
21 22 k1
|
||||
22 23 k1
|
||||
23 24 k1
|
||||
24 25 k1
|
||||
25 26 k1
|
||||
26 27 k1
|
||||
27 28 k1
|
||||
28 29 k1
|
||||
29 30 k1
|
||||
30 31 k1
|
||||
31 32 k1
|
||||
32 33 k1
|
||||
33 34 k1
|
||||
34 35 k1
|
||||
35 36 k1
|
||||
36 37 k1
|
||||
37 38 k1
|
||||
38 39 k1
|
||||
39 40 k1
|
||||
@@ -0,0 +1,41 @@
|
||||
n mass radius x y z vx vy vz fix_x fix_y fix_z
|
||||
1 1 0.1 0 0 0 0 0 0 0 1 0
|
||||
2 1 0.1 1 0 0 0 0 0 0 1 0
|
||||
3 1 0.1 2 0 0 0 0 0 0 1 0
|
||||
4 1 0.1 3 0 0 0 0 0 0 1 0
|
||||
5 1 0.1 4 0 0 0 0 0 0 1 0
|
||||
6 1 0.1 5 0 0 0 0 0 0 1 0
|
||||
7 1 0.1 6 0 0 0 0 0 0 1 0
|
||||
8 1 0.1 7 0 0 0 0 0 0 1 0
|
||||
9 1 0.1 8 0 0 0 0 0 0 1 0
|
||||
10 1 0.1 9 0 0 0 0 0 0 1 0
|
||||
11 1 0.1 10 0 0 0 0 0 0 1 0
|
||||
12 1 0.1 11 0 0 0 0 0 0 1 0
|
||||
13 1 0.1 12 0 0 0 0 0 0 1 0
|
||||
14 1 0.1 13 0 0 0 0 0 0 1 0
|
||||
15 1 0.1 14 0 0 0 0 0 0 1 0
|
||||
16 1 0.1 15 0 0 0 0 0 0 1 0
|
||||
17 1 0.1 16 0 0 0 0 0 0 1 0
|
||||
18 1 0.1 17 0 0 0 0 0 0 1 0
|
||||
19 1 0.1 18 0 0 0 0 0 0 1 0
|
||||
20 1 0.1 19 0 0 0 0 0 0 1 0
|
||||
21 1 0.1 20 0 0 0 0 0 0 1 0
|
||||
22 1 0.1 21 0 0 0 0 0 0 1 0
|
||||
23 1 0.1 22 0 0 0 0 0 0 1 0
|
||||
24 1 0.1 23 0 0 0 0 0 0 1 0
|
||||
25 1 0.1 24 0 0 0 0 0 0 1 0
|
||||
26 1 0.1 25 0 0 0 0 0 0 1 0
|
||||
27 1 0.1 26 0 0 0 0 0 0 1 0
|
||||
28 1 0.1 27 0 0 0 0 0 0 1 0
|
||||
29 1 0.1 28 0 0 0 0 0 0 1 0
|
||||
30 1 0.1 29 0 0 0 0 0 0 1 0
|
||||
31 1 0.1 30 0 0 0 0 0 0 1 0
|
||||
32 1 0.1 31 0 0 0 0 0 0 1 0
|
||||
33 1 0.1 32 0 0 0 0 0 0 1 0
|
||||
34 1 0.1 33 0 0 0 0 0 0 1 0
|
||||
35 1 0.1 34 0 0 0 0 0 0 1 0
|
||||
36 1 0.1 35 0 0 0 0 0 0 1 0
|
||||
37 1 0.1 36 0 0 0 0 0 0 1 0
|
||||
38 1 0.1 37 0 0 0 0 0 0 1 0
|
||||
39 1 0.1 38 0 0 0 0 0 0 1 0
|
||||
40 1 0.1 39 0 0 0 0 0 1 1 1
|
||||
@@ -0,0 +1,2 @@
|
||||
n amp_x amp_y amp_z freq_x freq_y freq_z phi_x phi_y phi_z period
|
||||
1 0 0 0.1 0 0 0.04 0 0 90 all
|
||||
@@ -0,0 +1,114 @@
|
||||
# 物理模拟参数配置
|
||||
# 格式:YAML
|
||||
# 用法:python run_dynamics.py
|
||||
|
||||
# ── 流程控制 ──────────────────────────────────
|
||||
# 每步用 0/1 单独开关,1=执行,0=跳过
|
||||
# 依赖关系:抽帧依赖模拟结果,绘图依赖模拟+抽帧
|
||||
step_simulate: 1 # 运行物理模拟 → output/display.txt(引擎直接抽帧)
|
||||
step_sample: 0 # (旧版)从 trajectory.txt 重新抽帧,默认0=不执行
|
||||
step_plot: 0 # 绘制轨迹/能量图 → output/trajectory_plots.png
|
||||
step_animation: 1 # 自动播放 VisPy 3D 动画窗口(需安装 vispy)
|
||||
step_plot_wave: 1 # 绘制波形能量动画
|
||||
force_calc: 1 # 强制重新计算:1=跳过缓存强算,0=自动使用已有输出
|
||||
plot_wave_save_gif: 0 # 输出波形 GIF(需 step_plot_wave=1)
|
||||
plot_wave_save_mp4: 0 # 输出波形 MP4(需 step_plot_wave=1)
|
||||
|
||||
# ── 文件保存 ──────────────────────────────────
|
||||
save_trajectory: 0 # 0=不保留完整轨迹文件, 1=保留 trajectory.txt(用于后续单独抽帧)
|
||||
|
||||
# ── 计算引擎 ──────────────────────────────────
|
||||
# 可选: python, c, cpp, fortran, java
|
||||
engine: fortran # 默认使用 python 引擎
|
||||
|
||||
# ── 盒子 ──────────────────────────────────────
|
||||
box_a: 300.0 # 立方体半边长,粒子被限制在 [-box_a, box_a]³ 内
|
||||
|
||||
# ── 初始构型 ──────────────────────────────────
|
||||
# 坐标文件格式:
|
||||
# 第一行:n mass radius x y z vx vy vz fix_x fix_y fix_z
|
||||
# 后续行:原子序号 质量 半径 x y z vx vy vz fix_x fix_y fix_z
|
||||
coord_file: input/coord.txt
|
||||
connection_file: input/connection.txt
|
||||
bond_file: input/bond.txt
|
||||
driver_file: input/driver.txt # 驱动力定义文件(driving_force=1 时生效)
|
||||
|
||||
# 绘图/动画展示的原子序号(对应 coord_file 第一列 n)
|
||||
plot_atom: 1
|
||||
|
||||
# ── 物理参数 ──────────────────────────────────
|
||||
# 三个方向分量分别对应 x, y, z
|
||||
G: [0.000, 0.000, 0.000] # 重力场分量 (m/s²)
|
||||
B: [0.005, 0.000, 0.005] # 阻尼分量
|
||||
|
||||
# ── 力开关(0=关闭, 1=开启)──────────────────
|
||||
gravity_field: 0 # 均匀重力场 (G)
|
||||
gravity_interaction: 0 # 原子间万有引力
|
||||
elastic_force: 1 # 弹簧键力
|
||||
damping_force: 0 # 阻尼 (B)
|
||||
driving_force: 1 # 驱动力(需 driver_file 定义)
|
||||
#
|
||||
gravity_strength: 1.0 # 万有引力强度(仅 gravity_interaction=1 时有效)
|
||||
|
||||
# ── 数值算法 ──────────────────────────────────
|
||||
# 可选:
|
||||
# explicit_euler 显式欧拉法
|
||||
# implicit_euler 隐式欧拉法
|
||||
# midpoint 中点法
|
||||
# leapfrog 蛙跳法
|
||||
method: leapfrog
|
||||
|
||||
# ── 步骤控制 ──────────────────────────────────
|
||||
# 以下参数控制哪些步骤被执行和保存
|
||||
|
||||
# 预热步数:模拟开始时跳过不保存的步数(用于稳定初始状态)
|
||||
warmup_steps: 0 # 默认 0(立即开始记录)
|
||||
|
||||
# 总模拟时间(秒),程序自动计算 NT = T_total / DT
|
||||
# 如果同时指定了 NT,以 NT 为准
|
||||
T_total: 200.0
|
||||
|
||||
# 抽帧间隔(每 NSTEP 步取一帧用于动画)
|
||||
NSTEP: 100
|
||||
|
||||
# ── 时间步长 ──────────────────────────────────
|
||||
DT: 0.001 # 时间步长 (s)
|
||||
|
||||
# 抽帧范围:只保存 [sample_start, sample_end) 区间内的帧
|
||||
sample_start: null # null 表示从头开始(帧索引从 0 起)
|
||||
sample_end: null # null 表示到末尾
|
||||
|
||||
|
||||
|
||||
# ── 渲染方式 ──────────────────────────────────
|
||||
# 3D 动画中原子渲染方式:
|
||||
# 0 = Sphere (网格球体,效果精细,原子数少时推荐)
|
||||
# 1 = Marker (GPU 实例化点,原子数多时性能更佳)
|
||||
use_marker: 1
|
||||
|
||||
# ── 显示参数 ──────────────────────────────────
|
||||
# 盒子透明度:单个数值(统一)或 6 个数的数组,按 [-x,+x,-y,+y,-z,+z] 顺序
|
||||
alpha: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
|
||||
|
||||
# 小球颜色
|
||||
# 小球半径从 coord_file 的 radius 列读取
|
||||
ball_color_r: 0.20 # R 分量 (0~1)
|
||||
ball_color_g: 0.60 # G 分量
|
||||
ball_color_b: 0.90 # B 分量
|
||||
|
||||
# 盒子面颜色
|
||||
box_color_r: 0.80
|
||||
box_color_g: 0.80
|
||||
box_color_b: 0.85
|
||||
|
||||
# ── 摄像机初始位置 ────────────────────────────
|
||||
camera_distance: 60.0 # 摄像机到场景中心的距离
|
||||
camera_elevation: 0.0 # 俯仰角(度),负值=俯视
|
||||
camera_azimuth: 0.0 # 方位角(度)
|
||||
camera_center_x: 30.0 # 摄像机注视点 x
|
||||
camera_center_y: 0.0 # 摄像机注视点 y
|
||||
camera_center_z: 0.0 # 摄像机注视点 z
|
||||
move_camera: 0 # 0=固定视角, 1=按 move_camera.txt 运动
|
||||
|
||||
# ── 视觉放大 ──────────────────────────────────
|
||||
display_amp: [1.0, 1.0, 10.0] # x/y/z 方向视觉位移放大倍数(不影响物理)
|
||||
@@ -0,0 +1,9 @@
|
||||
# move_camera.txt — 摄像机速度段驱动
|
||||
# 格式: start-end vx=f vy=f vz=f rx=d ry=d rz=d
|
||||
# vx/vy/vz: 平移速度(每帧移动单位)
|
||||
# rx/ry/rz: 旋转速度(每帧度数)
|
||||
# rx → elevation(俯仰), ry → azimuth(方位), rz → (预留)
|
||||
#
|
||||
# 示例:前60帧向右平移+绕x旋转,30-90帧向上平移+绕y绕z旋转
|
||||
all vx=0.02
|
||||
# 30-90 vy=0.02 ry=1 rz=1
|
||||
@@ -0,0 +1,54 @@
|
||||
"""
|
||||
Case runner for Dynamics case06 — 1D atomic chain (transverse wave).
|
||||
|
||||
This script keeps program and data separated:
|
||||
- program: ../../dynamics.py
|
||||
- input: ./input
|
||||
- output: ./output
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
CASE_DIR = Path(__file__).resolve().parent
|
||||
DYNAMICS_PATH = Path("..") / ".." / "dynamics.py"
|
||||
INPUT_DIR = Path("input")
|
||||
OUTPUT_DIR = Path("output")
|
||||
CONFIG_FILE = INPUT_DIR / "input.txt"
|
||||
|
||||
|
||||
def load_dynamics_module(module_path: Path):
|
||||
spec = importlib.util.spec_from_file_location("dynamics_module", module_path)
|
||||
if spec is None or spec.loader is None:
|
||||
raise ImportError(f"无法加载 dynamics.py: {module_path}")
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="运行 Dynamics 示例案例 case06")
|
||||
parser.add_argument("--no-plot", action="store_true", help="跳过 matplotlib 绘图")
|
||||
args = parser.parse_args()
|
||||
|
||||
dynamics_path = (CASE_DIR / DYNAMICS_PATH).resolve()
|
||||
input_dir = (CASE_DIR / INPUT_DIR).resolve()
|
||||
output_dir = (CASE_DIR / OUTPUT_DIR).resolve()
|
||||
config_path = (CASE_DIR / CONFIG_FILE).resolve()
|
||||
|
||||
module = load_dynamics_module(dynamics_path)
|
||||
module.run_case(
|
||||
config_path=config_path,
|
||||
runtime_base=CASE_DIR,
|
||||
input_dir=input_dir,
|
||||
output_dir=output_dir,
|
||||
no_plot=args.no_plot,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,40 @@
|
||||
# case06: 一维原子链横波模拟
|
||||
|
||||
60 个原子沿 x 轴排列,相邻原子用弹簧连接。原子 1 受 z 方向驱动力作用,产生沿链传播的横波。
|
||||
|
||||
## 物理设定
|
||||
|
||||
| 参数 | 值 |
|
||||
|---|---|
|
||||
| 原子数 | 120 |
|
||||
| 排列 | 沿 x 轴等间距排列,间距为 1 |
|
||||
| 约束 | 原子**沿 z 方向自由振动**(fix_x=1, fix_y=1, fix_z=0),x, y 锁定 |
|
||||
| 弹簧 | 劲度系数 k=1.0,原长 L₀=1.0 |
|
||||
| 重力 | 无 |
|
||||
| 万有引力 | 无 |
|
||||
| 阻尼 | 无 |
|
||||
| 驱动力 | 原子 1(z 方向驱动) |
|
||||
| 算法 | leapfrog(蛙跳法,能量守恒) |
|
||||
|
||||
## 驱动力
|
||||
|
||||
原子 1 的位置由 `input/driver.txt` 中的驱动力公式决定:
|
||||
|
||||
```math
|
||||
z(t) = A_z \cdot \cos(2\pi f_z t + \phi_z)
|
||||
```
|
||||
|
||||
当前参数:A_z = 0.5, f_z = 0.1 Hz, φ_z = 90°, period = all(全程驱动)。
|
||||
|
||||
## 动力学行为
|
||||
|
||||
原子 1 沿 z 方向的受迫振动通过弹簧逐次传递给相邻原子,形成沿链传播的**横波**。由于 z 方向的振动是横向的,弹簧大部分张力在 x 方向,z 方向的有效刚度是非线性的——等效于一个三次方恢复力(FPU 型非线性),因此波速较慢。
|
||||
|
||||
## 使用方法
|
||||
|
||||
```bash
|
||||
cd examples/case06
|
||||
python run_dynamics.py
|
||||
```
|
||||
|
||||
配置参数详见 `input/input.txt`,驱动力定义见 `input/driver.txt`,完整文档见 `doc/index.html`。
|
||||
@@ -0,0 +1,477 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>case06 — 一维原子链驱动力学模拟 | 物理原理 & 使用文档</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #f8f9fa;
|
||||
--card: #fff;
|
||||
--text: #1a1a2e;
|
||||
--accent: #2563eb;
|
||||
--accent-light: #dbeafe;
|
||||
--code-bg: #1e293b;
|
||||
--code-text: #e2e8f0;
|
||||
--border: #e2e8f0;
|
||||
--muted: #64748b;
|
||||
}
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Noto Sans SC", sans-serif;
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
/* ── Header ── */
|
||||
.hero {
|
||||
background: linear-gradient(135deg, #1e293b 0%, #334155 100%);
|
||||
color: #fff;
|
||||
padding: 56px 24px 48px;
|
||||
text-align: center;
|
||||
}
|
||||
.hero h1 { font-size: 2rem; font-weight: 700; letter-spacing: -0.02em; }
|
||||
.hero .subtitle {
|
||||
margin-top: 10px;
|
||||
font-size: 1.05rem;
|
||||
opacity: 0.8;
|
||||
}
|
||||
.hero .badge {
|
||||
display: inline-block;
|
||||
margin-top: 14px;
|
||||
padding: 4px 14px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255,255,255,0.12);
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
|
||||
/* ── Layout ── */
|
||||
.container { max-width: 820px; margin: 0 auto; padding: 32px 20px; }
|
||||
|
||||
section { margin-bottom: 44px; }
|
||||
h2 {
|
||||
font-size: 1.35rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 2px solid var(--accent);
|
||||
display: inline-block;
|
||||
}
|
||||
h3 {
|
||||
font-size: 1.05rem;
|
||||
font-weight: 600;
|
||||
margin: 20px 0 10px;
|
||||
}
|
||||
|
||||
p, li { margin-bottom: 10px; }
|
||||
ul, ol { padding-left: 22px; }
|
||||
strong { color: var(--accent); }
|
||||
|
||||
/* ── Cards ── */
|
||||
.card {
|
||||
background: var(--card);
|
||||
border-radius: 12px;
|
||||
padding: 20px 24px;
|
||||
margin-bottom: 16px;
|
||||
border: 1px solid var(--border);
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.04);
|
||||
}
|
||||
|
||||
/* ── Formula / Code blocks ── */
|
||||
.formula {
|
||||
background: var(--card);
|
||||
border-left: 4px solid var(--accent);
|
||||
padding: 14px 20px;
|
||||
margin: 14px 0;
|
||||
font-family: "Times New Roman", "STIX", serif;
|
||||
font-size: 1.05rem;
|
||||
overflow-x: auto;
|
||||
border-radius: 0 8px 8px 0;
|
||||
}
|
||||
code {
|
||||
background: var(--accent-light);
|
||||
padding: 2px 7px;
|
||||
border-radius: 4px;
|
||||
font-family: "JetBrains Mono", "Fira Code", monospace;
|
||||
font-size: 0.88em;
|
||||
}
|
||||
pre {
|
||||
background: var(--code-bg);
|
||||
color: var(--code-text);
|
||||
padding: 16px 20px;
|
||||
border-radius: 10px;
|
||||
overflow-x: auto;
|
||||
font-size: 0.85rem;
|
||||
line-height: 1.5;
|
||||
margin: 14px 0;
|
||||
}
|
||||
pre .cm { color: #94a3b8; font-style: italic; } /* comment */
|
||||
|
||||
/* ── Table ── */
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 14px 0;
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
th, td {
|
||||
padding: 8px 12px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
th { background: var(--accent-light); font-weight: 600; }
|
||||
|
||||
/* ── TOC ── */
|
||||
.toc { counter-reset: toc; }
|
||||
.toc li { counter-increment: toc; list-style: none; margin-bottom: 6px; }
|
||||
.toc li::before { content: counter(toc) ". "; font-weight: 600; color: var(--accent); }
|
||||
.toc a { color: var(--accent); text-decoration: none; }
|
||||
.toc a:hover { text-decoration: underline; }
|
||||
|
||||
/* ── Flow diagram ── */
|
||||
.flow { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; justify-content: center; margin: 16px 0; }
|
||||
.flow-step {
|
||||
background: var(--accent-light);
|
||||
border: 1px solid var(--accent);
|
||||
border-radius: 8px;
|
||||
padding: 8px 16px;
|
||||
font-size: 0.88rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
.flow-arrow { color: var(--muted); font-size: 1.2rem; }
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.hero h1 { font-size: 1.5rem; }
|
||||
.flow { flex-direction: column; }
|
||||
.flow-arrow { transform: rotate(90deg); }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- Header -->
|
||||
<!-- ============================================================ -->
|
||||
<header class="hero">
|
||||
<h1>一维原子链驱动力学模拟</h1>
|
||||
<p class="subtitle">120 个原子沿 x 轴排列 · 弹簧连接 · z 方向受迫振动</p>
|
||||
<span class="badge">case06 · examples/case06</span>
|
||||
</header>
|
||||
|
||||
<div class="container">
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- TOC -->
|
||||
<!-- ============================================================ -->
|
||||
<section>
|
||||
<h2>目录</h2>
|
||||
<ol class="toc">
|
||||
<li><a href="#physics">物理原理</a></li>
|
||||
<li><a href="#algorithm">数值算法</a></li>
|
||||
<li><a href="#driver">驱动力模型</a></li>
|
||||
<li><a href="#usage">使用方法</a></li>
|
||||
<li><a href="#params">参数参考</a></li>
|
||||
<li><a href="#files">文件结构</a></li>
|
||||
<li><a href="#troubleshoot">常见问题</a></li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 1. Physics -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="physics">
|
||||
<h2>一、物理原理</h2>
|
||||
|
||||
<div class="card">
|
||||
<h3>1.1 一维原子链</h3>
|
||||
<p>120 个原子沿 <strong>x 轴</strong> 等间距排列,原子间距为 1。相邻原子之间用 <strong>理想弹簧</strong> 连接,弹簧的劲度系数 <em>k</em> = 1.0,原长 <em>L</em>₀ = 1.0(与原子间距一致,初始状态弹簧无拉伸)。</p>
|
||||
<p>每个原子被限制在 <strong>z 方向</strong> 自由振动,x 和 y 方向锁定(<code>fix_x=1, fix_y=1, fix_z=0</code>)。</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>1.2 弹簧力(胡克定律)</h3>
|
||||
<p>当原子 <em>i</em> 和 <em>j</em> 之间有弹簧连接时,原子 <em>i</em> 受到的弹簧力为:</p>
|
||||
<div class="formula">
|
||||
<strong>F</strong> = −<em>k</em> · (<em>d</em> − <em>L</em>₀) · <strong>u</strong><sub><em>ij</em></sub>
|
||||
</div>
|
||||
<p>其中 <em>d</em> = |<strong>r</strong><sub><em>j</em></sub> − <strong>r</strong><sub><em>i</em></sub>| 为两原子间距离,<strong>u</strong><sub><em>ij</em></sub> 为从 <em>i</em> 指向 <em>j</em> 的单位向量。由于原子只在 z 方向振动,弹簧在 z 方向的分量是 <strong>几何非线性</strong> 的——对于小振幅近似,z 方向等效于一个三次方恢复力(FPU 型非线性)。</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>1.3 运动方程</h3>
|
||||
<p>对于第 <em>i</em> 个自由原子(非受驱),牛顿第二定律给出:</p>
|
||||
<div class="formula">
|
||||
<em>m</em> · <strong>a</strong><sub><em>i</em></sub> = <strong>F</strong><sub><em>i</em></sub><sup>spring</sup> + <strong>F</strong><sub><em>i</em></sub><sup>driving</sup>
|
||||
</div>
|
||||
<p>本案例中 <strong>唯一的外力</strong> 来自驱动力(仅施加于原子 1)。无重力、无万有引力、无阻尼,系统总能量守恒。</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>1.4 波传播</h3>
|
||||
<p>原子 1 的受迫振动通过弹簧逐次传递给相邻原子,形成沿链传播的 <strong>横波</strong>。由于横向振动的几何非线性(弹簧大部分张力在 x 方向,z 方向的有效刚度远小于 1),波的传播速度较慢,且高阶频率成分会在链中产生复杂的非线性动力学行为(类似 FPU 回波现象)。</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 2. Algorithm -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="algorithm">
|
||||
<h2>二、数值算法</h2>
|
||||
|
||||
<div class="card">
|
||||
<h3>2.1 蛙跳法(Leapfrog / Velocity-Verlet)</h3>
|
||||
<p>采用能量守恒特性优异的 <strong>蛙跳法</strong>(二阶辛积分器),更新公式为:</p>
|
||||
<div class="formula">
|
||||
<strong>v</strong>(<em>t</em> + ½Δ<em>t</em>) = <strong>v</strong>(<em>t</em>) + ½ <strong>a</strong>(<em>t</em>) · Δ<em>t</em><br>
|
||||
<strong>r</strong>(<em>t</em> + Δ<em>t</em>) = <strong>r</strong>(<em>t</em>) + <strong>v</strong>(<em>t</em> + ½Δ<em>t</em>) · Δ<em>t</em><br>
|
||||
<strong>a</strong>(<em>t</em> + Δ<em>t</em>) = <strong>F</strong>(<strong>r</strong>(<em>t</em> + Δ<em>t</em>), <strong>v</strong>(<em>t</em> + ½Δ<em>t</em>)) / <em>m</em><br>
|
||||
<strong>v</strong>(<em>t</em> + Δ<em>t</em>) = <strong>v</strong>(<em>t</em> + ½Δ<em>t</em>) + ½ <strong>a</strong>(<em>t</em> + Δ<em>t</em>) · Δ<em>t</em>
|
||||
</div>
|
||||
<p>蛙跳法在长时间模拟中能量漂移极小(本案例验证 <strong>< 0.004%</strong>),适合无阻尼的保守系统。</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>2.2 时间步长与采样</h3>
|
||||
<table>
|
||||
<tr><th>参数</th><th>值</th><th>说明</th></tr>
|
||||
<tr><td>DT</td><td>0.01 s</td><td>积分步长(远小于 1/ω ≈ 0.16 s,满足稳定性条件)</td></tr>
|
||||
<tr><td>T_total</td><td>100 s</td><td>总模拟时间 → NT = 10000 步</td></tr>
|
||||
<tr><td>NSTEP</td><td>50</td><td>每 NSTEP 步取一帧用于动画 → 200 帧</td></tr>
|
||||
<tr><td>method</td><td>leapfrog</td><td>蛙跳法(Velocity-Verlet)</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>2.3 计算流程</h3>
|
||||
<div class="flow">
|
||||
<span class="flow-step">读入 coord.txt<br>connection.txt<br>bond.txt</span>
|
||||
<span class="flow-arrow">→</span>
|
||||
<span class="flow-step">施加驱动力<br>(驱动原子 1)</span>
|
||||
<span class="flow-arrow">→</span>
|
||||
<span class="flow-step">记录轨迹</span>
|
||||
<span class="flow-arrow">→</span>
|
||||
<span class="flow-step">蛙跳法<br>更新位置/速度</span>
|
||||
<span class="flow-arrow">→</span>
|
||||
<span class="flow-step">固定约束<br>(x, y 锁定)</span>
|
||||
<span class="flow-arrow">→</span>
|
||||
<span class="flow-step" style="background:#fef3c7;border-color:#f59e0b;">循环<br>NT 次</span>
|
||||
</div>
|
||||
<p style="margin-top:12px;">注意:驱动力在 <strong>每次积分前</strong> 施加,确保受驱原子的位置正确传递给弹簧力计算。</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 3. Driving Force -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="driver">
|
||||
<h2>三、驱动力模型</h2>
|
||||
|
||||
<div class="card">
|
||||
<h3>3.1 定义文件</h3>
|
||||
<p>驱动力由 <code>input/driver.txt</code> 定义,格式如下:</p>
|
||||
<pre>n amp_x amp_y amp_z freq_x freq_y freq_z phi_x phi_y phi_z period
|
||||
1 0 0 5 0 0 1 0 0 90 all</pre>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>3.2 数学公式</h3>
|
||||
<p>受驱原子的位置由下式决定(<strong>完全替换</strong> coord.txt 中的初始坐标和固定约束):</p>
|
||||
<div class="formula">
|
||||
<strong>r</strong>(<em>t</em>) = <strong>A</strong> · cos(2π<em>f</em> · <em>t</em> + <strong>φ</strong>)
|
||||
</div>
|
||||
<p>速度由解析导数给出:</p>
|
||||
<div class="formula">
|
||||
<strong>v</strong>(<em>t</em>) = −<strong>A</strong> · 2π<em>f</em> · sin(2π<em>f</em> · <em>t</em> + <strong>φ</strong>)
|
||||
</div>
|
||||
<p>其中 <strong>A</strong> = (amp_x, amp_y, amp_z),<strong>f</strong> = (freq_x, freq_y, freq_z) 为不同方向的驱动频率,<strong>φ</strong> = (phi_x, phi_y, phi_z) 为相位(<strong>角度制</strong>,代码自动转换为弧度)。</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>3.3 本案例驱动参数</h3>
|
||||
<table>
|
||||
<tr><th>参数</th><th>值</th><th>含义</th></tr>
|
||||
<tr><td>amp_z</td><td>5.0</td><td>z 方向驱动振幅</td></tr>
|
||||
<tr><td>freq_z</td><td>1.0 Hz</td><td>驱动频率(周期 1 s)</td></tr>
|
||||
<tr><td>phi_z</td><td>90°</td><td>驱动相位 → z(0) = 5·cos(90°) = 0</td></tr>
|
||||
<tr><td>period</td><td>all</td><td>全程驱动,永不停止</td></tr>
|
||||
</table>
|
||||
<div class="formula">
|
||||
<em>z</em>(<em>t</em>) = 5.0 · cos(2π · 1.0 · <em>t</em> + 90°)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>3.4 有限周期驱动</h3>
|
||||
<p><code>period</code> 参数支持三种模式:</p>
|
||||
<ul>
|
||||
<li><strong>all</strong> — 全程驱动</li>
|
||||
<li><strong>数值</strong> — 驱动指定周期数后 <strong>静止</strong>(冻结在最终位置,速度归零)。例如 <code>period: 1</code> 表示驱动 1 个完整周期后停止。</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>3.5 驱动与固定约束的关系</h3>
|
||||
<p>对于受驱原子(<code>driver.txt</code> 中 <code>n</code> 指定的原子),其在 <code>coord.txt</code> 中的初始坐标和 <code>fix_x/fix_y/fix_z</code> 约束被 <strong>完全忽略</strong>。原子的位置和速度完全由驱动力公式决定。</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 4. Usage -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="usage">
|
||||
<h2>四、使用方法</h2>
|
||||
|
||||
<div class="card">
|
||||
<h3>4.1 完整运行(模拟 + 动画)</h3>
|
||||
<pre>cd examples/case06
|
||||
python run_dynamics.py</pre>
|
||||
<p>这步会依次执行:物理模拟 → 抽帧 → 打开 VisPy 3D 动画窗口。</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>4.2 仅查看已有结果</h3>
|
||||
<p>如果已经跑完模拟且生成了 <code>output/display.txt</code>,可以通过修改 <code>input.txt</code> 跳过计算,只开动画:</p>
|
||||
<pre>step_simulate: 0 # 跳过模拟
|
||||
step_sample: 0 # 跳过抽帧
|
||||
step_animation: 1 # 播放动画</pre>
|
||||
<p>然后运行:<code>python run_dynamics.py</code></p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>4.3 手动 3D 动画</h3>
|
||||
<p>也可以单独启动 VisPy 窗口:</p>
|
||||
<pre>python ../../draw.py output/</pre>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>4.4 强制重新计算</h3>
|
||||
<p>修改参数后需要重新运行模拟时,设置:</p>
|
||||
<pre>force_calc: 1 # 忽略缓存,强制重新计算</pre>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>4.5 动画交互</h3>
|
||||
<table>
|
||||
<tr><th>操作</th><th>效果</th></tr>
|
||||
<tr><td>鼠标拖动</td><td>旋转视角</td></tr>
|
||||
<tr><td>滚轮</td><td>缩放</td></tr>
|
||||
<tr><td>W / S 键</td><td>相机沿 Z 轴向前 / 向后移动(靠近/远离场景)</td></tr>
|
||||
<tr><td>A / D 键</td><td>视角向右 / 向左平移</td></tr>
|
||||
<tr><td>E / Q 键</td><td>视角上升 / 下降(屏幕方向)</td></tr>
|
||||
<tr><td>C / X 键</td><td>增大 / 减小步长</td></tr>
|
||||
<tr><td>V 键</td><td>切换透视 / 正交投影</td></tr>
|
||||
<tr><td>左上角 <strong>reset</strong> 按钮</td><td>复位视角到初始位置</td></tr>
|
||||
<tr><td>左上角 <strong>info</strong> 按钮</td><td>切换信息面板显示/隐藏</td></tr>
|
||||
<tr><td>左上角 <strong>axes</strong> 按钮</td><td>切换坐标轴显示/隐藏</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 5. Parameters -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="params">
|
||||
<h2>五、参数参考</h2>
|
||||
|
||||
<div class="card">
|
||||
<h3>5.1 input.txt 关键参数</h3>
|
||||
<table>
|
||||
<tr><th>参数</th><th>默认值</th><th>说明</th></tr>
|
||||
<tr><td>gravity_field</td><td>0</td><td>均匀重力场(已关闭)</td></tr>
|
||||
<tr><td>gravity_interaction</td><td>0</td><td>原子间万有引力(已关闭)</td></tr>
|
||||
<tr><td>elastic_force</td><td>1</td><td>弹簧键力(已开启)</td></tr>
|
||||
<tr><td>damping_force</td><td>0</td><td>阻尼(已关闭)</td></tr>
|
||||
<tr><td><strong>driving_force</strong></td><td><strong>1</strong></td><td>驱动力开关(1=开启,需 driver.txt)</td></tr>
|
||||
<tr><td>method</td><td>leapfrog</td><td>数值积分方法</td></tr>
|
||||
<tr><td>DT</td><td>0.01</td><td>积分步长 (s)</td></tr>
|
||||
<tr><td>T_total</td><td>100.0</td><td>总模拟时间 (s)</td></tr>
|
||||
<tr><td>NSTEP</td><td>50</td><td>抽帧步数间隔</td></tr>
|
||||
<tr><td>engine</td><td>python</td><td>计算引擎(python / c / cpp / fortran)</td></tr>
|
||||
<tr><td>use_marker</td><td>1</td><td>渲染模式(0=Sphere 网格, 1=Marker GPU 实例化)</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>5.2 流程控制参数</h3>
|
||||
<table>
|
||||
<tr><th>参数</th><th>0</th><th>1</th></tr>
|
||||
<tr><td>step_simulate</td><td>跳过模拟(加载已有轨迹)</td><td>运行物理模拟</td></tr>
|
||||
<tr><td>step_sample</td><td>跳过抽帧</td><td>从轨迹抽取显示帧</td></tr>
|
||||
<tr><td>step_plot</td><td>不生成图表</td><td>生成轨迹/能量图</td></tr>
|
||||
<tr><td><strong>step_plot_wave</strong></td><td>不生成波形图</td><td>生成波形能量动画 GIF</td></tr>
|
||||
<tr><td>step_animation</td><td>不启动动画</td><td>自动打开 VisPy 3D 窗口</td></tr>
|
||||
<tr><td>force_calc</td><td>自动检测缓存</td><td>强制重新计算</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 6. File Structure -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="files">
|
||||
<h2>六、文件结构</h2>
|
||||
|
||||
<pre>case06/
|
||||
├── input/
|
||||
│ ├── input.txt # 主配置文件(YAML 格式)
|
||||
│ ├── coord.txt # 原子坐标(120 个原子)
|
||||
│ ├── connection.txt # 弹簧连接关系(59 条键)
|
||||
│ ├── bond.txt # 弹簧参数(k=1.0, L₀=1.0)
|
||||
│ └── <strong>driver.txt</strong> # <span class="cm">驱动力定义(本案例新增)</span>
|
||||
├── output/
|
||||
│ ├── trajectory.txt # 全量轨迹数据(50000 步 × 120 原子)
|
||||
│ ├── display.txt # 抽帧后的动画数据(500 帧 × 120 原子)
|
||||
│ ├── dynamics.log # 计算日志
|
||||
│ ├── animation.log # 动画启动日志(闪退时排查用)
|
||||
│ └── wave_animation.gif # 波形能量动画(step_plot_wave=1 时生成)
|
||||
├── doc/
|
||||
│ └── index.html # <span class="cm">本文档</span>
|
||||
├── Readme.md # 案例简介
|
||||
└── run_dynamics.py # 案例运行入口</pre>
|
||||
</section>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 7. Troubleshooting -->
|
||||
<!-- ============================================================ -->
|
||||
<section id="troubleshoot">
|
||||
<h2>七、常见问题</h2>
|
||||
|
||||
<div class="card">
|
||||
<h3>7.1 动画窗口闪退</h3>
|
||||
<p>如果 VisPy 窗口一闪就消失,请检查:</p>
|
||||
<ul>
|
||||
<li><code>output/animation.log</code> 中是否有错误信息</li>
|
||||
<li><code>output/display.txt</code> 是否存在(需先跑 <code>step_sample: 1</code>)</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>7.2 原子不振动</h3>
|
||||
<p>可能原因:</p>
|
||||
<ul>
|
||||
<li><strong>NSTEP 过大</strong>:抽帧间隔大于驱动周期的一半时,动画会丢失振动细节。建议 NSTEP ≤ 1/(freq · DT · 10)</li>
|
||||
<li><strong>相位 φ 使采样点落在零值</strong>:试试 <code>phi_z: 0</code> 让原子在 t=0 处于振幅峰值</li>
|
||||
<li>确认 <code>driving_force: 1</code> 且 <code>driver.txt</code> 中 amp_z 不为 0</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>7.3 渲染性能慢</h3>
|
||||
<p>原子数多时动画卡顿:</p>
|
||||
<ul>
|
||||
<li>设置 <code>use_marker: 1</code>(使用 GPU 实例化渲染替代独立网格球体)</li>
|
||||
<li>增大 <code>NSTEP</code> 减少动画帧数</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<hr style="border:none;border-top:1px solid var(--border);margin:40px 0;">
|
||||
|
||||
<footer style="text-align:center;color:var(--muted);font-size:0.85rem;margin-bottom:40px;">
|
||||
Dynamics Simulation Framework · 生成于 2026-06-10
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,2 @@
|
||||
bond_name k rest_length
|
||||
k1 300.0 1.0
|
||||
@@ -0,0 +1,40 @@
|
||||
n1 n2 bond_name
|
||||
1 2 k1
|
||||
2 3 k1
|
||||
3 4 k1
|
||||
4 5 k1
|
||||
5 6 k1
|
||||
6 7 k1
|
||||
7 8 k1
|
||||
8 9 k1
|
||||
9 10 k1
|
||||
10 11 k1
|
||||
11 12 k1
|
||||
12 13 k1
|
||||
13 14 k1
|
||||
14 15 k1
|
||||
15 16 k1
|
||||
16 17 k1
|
||||
17 18 k1
|
||||
18 19 k1
|
||||
19 20 k1
|
||||
20 21 k1
|
||||
21 22 k1
|
||||
22 23 k1
|
||||
23 24 k1
|
||||
24 25 k1
|
||||
25 26 k1
|
||||
26 27 k1
|
||||
27 28 k1
|
||||
28 29 k1
|
||||
29 30 k1
|
||||
30 31 k1
|
||||
31 32 k1
|
||||
32 33 k1
|
||||
33 34 k1
|
||||
34 35 k1
|
||||
35 36 k1
|
||||
36 37 k1
|
||||
37 38 k1
|
||||
38 39 k1
|
||||
39 40 k1
|
||||
@@ -0,0 +1,41 @@
|
||||
n mass radius x y z vx vy vz fix_x fix_y fix_z
|
||||
1 1 0.1 0 0 0 0 0 0 0 1 1
|
||||
2 1 0.1 1 0 0 0 0 0 0 1 1
|
||||
3 1 0.1 2 0 0 0 0 0 0 1 1
|
||||
4 1 0.1 3 0 0 0 0 0 0 1 1
|
||||
5 1 0.1 4 0 0 0 0 0 0 1 1
|
||||
6 1 0.1 5 0 0 0 0 0 0 1 1
|
||||
7 1 0.1 6 0 0 0 0 0 0 1 1
|
||||
8 1 0.1 7 0 0 0 0 0 0 1 1
|
||||
9 1 0.1 8 0 0 0 0 0 0 1 1
|
||||
10 1 0.1 9 0 0 0 0 0 0 1 1
|
||||
11 1 0.1 10 0 0 0 0 0 0 1 1
|
||||
12 1 0.1 11 0 0 0 0 0 0 1 1
|
||||
13 1 0.1 12 0 0 0 0 0 0 1 1
|
||||
14 1 0.1 13 0 0 0 0 0 0 1 1
|
||||
15 1 0.1 14 0 0 0 0 0 0 1 1
|
||||
16 1 0.1 15 0 0 0 0 0 0 1 1
|
||||
17 1 0.1 16 0 0 0 0 0 0 1 1
|
||||
18 1 0.1 17 0 0 0 0 0 0 1 1
|
||||
19 1 0.1 18 0 0 0 0 0 0 1 1
|
||||
20 1 0.1 19 0 0 0 0 0 0 1 1
|
||||
21 1 0.1 20 0 0 0 0 0 0 1 1
|
||||
22 1 0.1 21 0 0 0 0 0 0 1 1
|
||||
23 1 0.1 22 0 0 0 0 0 0 1 1
|
||||
24 1 0.1 23 0 0 0 0 0 0 1 1
|
||||
25 1 0.1 24 0 0 0 0 0 0 1 1
|
||||
26 1 0.1 25 0 0 0 0 0 0 1 1
|
||||
27 1 0.1 26 0 0 0 0 0 0 1 1
|
||||
28 1 0.1 27 0 0 0 0 0 0 1 1
|
||||
29 1 0.1 28 0 0 0 0 0 0 1 1
|
||||
30 1 0.1 29 0 0 0 0 0 0 1 1
|
||||
31 1 0.1 30 0 0 0 0 0 0 1 1
|
||||
32 1 0.1 31 0 0 0 0 0 0 1 1
|
||||
33 1 0.1 32 0 0 0 0 0 0 1 1
|
||||
34 1 0.1 33 0 0 0 0 0 0 1 1
|
||||
35 1 0.1 34 0 0 0 0 0 0 1 1
|
||||
36 1 0.1 35 0 0 0 0 0 0 1 1
|
||||
37 1 0.1 36 0 0 0 0 0 0 1 1
|
||||
38 1 0.1 37 0 0 0 0 0 0 1 1
|
||||
39 1 0.1 38 0 0 0 0 0 0 1 1
|
||||
40 1 0.1 39 0 0 0 0 0 1 1 1
|
||||
@@ -0,0 +1,2 @@
|
||||
n amp_x amp_y amp_z freq_x freq_y freq_z phi_x phi_y phi_z period
|
||||
1 0.1 0 0 0.04 0 0 0 0 90 all
|
||||
@@ -0,0 +1,114 @@
|
||||
# 物理模拟参数配置
|
||||
# 格式:YAML
|
||||
# 用法:python run_dynamics.py
|
||||
|
||||
# ── 流程控制 ──────────────────────────────────
|
||||
# 每步用 0/1 单独开关,1=执行,0=跳过
|
||||
# 依赖关系:抽帧依赖模拟结果,绘图依赖模拟+抽帧
|
||||
step_simulate: 1 # 运行物理模拟 → output/display.txt(引擎直接抽帧)
|
||||
step_sample: 0 # (旧版)从 trajectory.txt 重新抽帧,默认0=不执行
|
||||
step_plot: 1 # 绘制轨迹/能量图 → output/trajectory_plots.png
|
||||
step_animation: 0 # 自动播放 VisPy 3D 动画窗口(需安装 vispy)
|
||||
step_plot_wave: 1 # 绘制波形能量动画
|
||||
force_calc: 1 # 强制重新计算:1=跳过缓存强算,0=自动使用已有输出
|
||||
plot_wave_save_gif: 0 # 输出波形 GIF(需 step_plot_wave=1)
|
||||
plot_wave_save_mp4: 0 # 输出波形 MP4(需 step_plot_wave=1)
|
||||
|
||||
# ── 文件保存 ──────────────────────────────────
|
||||
save_trajectory: 0 # 0=不保留完整轨迹文件, 1=保留 trajectory.txt(用于后续单独抽帧)
|
||||
|
||||
# ── 计算引擎 ──────────────────────────────────
|
||||
# 可选: python, c, cpp, fortran, java
|
||||
engine: c # 默认使用 python 引擎
|
||||
|
||||
# ── 盒子 ──────────────────────────────────────
|
||||
box_a: 300.0 # 立方体半边长,粒子被限制在 [-box_a, box_a]³ 内
|
||||
|
||||
# ── 初始构型 ──────────────────────────────────
|
||||
# 坐标文件格式:
|
||||
# 第一行:n mass radius x y z vx vy vz fix_x fix_y fix_z
|
||||
# 后续行:原子序号 质量 半径 x y z vx vy vz fix_x fix_y fix_z
|
||||
coord_file: input/coord.txt
|
||||
connection_file: input/connection.txt
|
||||
bond_file: input/bond.txt
|
||||
driver_file: input/driver.txt # 驱动力定义文件(driving_force=1 时生效)
|
||||
|
||||
# 绘图/动画展示的原子序号(对应 coord_file 第一列 n)
|
||||
plot_atom: 1
|
||||
|
||||
# ── 物理参数 ──────────────────────────────────
|
||||
# 三个方向分量分别对应 x, y, z
|
||||
G: [0.000, 0.000, 0.000] # 重力场分量 (m/s²)
|
||||
B: [0.005, 0.000, 0.005] # 阻尼分量
|
||||
|
||||
# ── 力开关(0=关闭, 1=开启)──────────────────
|
||||
gravity_field: 0 # 均匀重力场 (G)
|
||||
gravity_interaction: 0 # 原子间万有引力
|
||||
elastic_force: 1 # 弹簧键力
|
||||
damping_force: 0 # 阻尼 (B)
|
||||
driving_force: 1 # 驱动力(需 driver_file 定义)
|
||||
#
|
||||
gravity_strength: 1.0 # 万有引力强度(仅 gravity_interaction=1 时有效)
|
||||
|
||||
# ── 数值算法 ──────────────────────────────────
|
||||
# 可选:
|
||||
# explicit_euler 显式欧拉法
|
||||
# implicit_euler 隐式欧拉法
|
||||
# midpoint 中点法
|
||||
# leapfrog 蛙跳法
|
||||
method: leapfrog
|
||||
|
||||
# ── 步骤控制 ──────────────────────────────────
|
||||
# 以下参数控制哪些步骤被执行和保存
|
||||
|
||||
# 预热步数:模拟开始时跳过不保存的步数(用于稳定初始状态)
|
||||
warmup_steps: 0 # 默认 0(立即开始记录)
|
||||
|
||||
# 总模拟时间(秒),程序自动计算 NT = T_total / DT
|
||||
# 如果同时指定了 NT,以 NT 为准
|
||||
T_total: 10.0
|
||||
|
||||
# 抽帧间隔(每 NSTEP 步取一帧用于动画)
|
||||
NSTEP: 20
|
||||
|
||||
# ── 时间步长 ──────────────────────────────────
|
||||
DT: 0.001 # 时间步长 (s)
|
||||
|
||||
# 抽帧范围:只保存 [sample_start, sample_end) 区间内的帧
|
||||
sample_start: null # null 表示从头开始(帧索引从 0 起)
|
||||
sample_end: null # null 表示到末尾
|
||||
|
||||
|
||||
|
||||
# ── 渲染方式 ──────────────────────────────────
|
||||
# 3D 动画中原子渲染方式:
|
||||
# 0 = Sphere (网格球体,效果精细,原子数少时推荐)
|
||||
# 1 = Marker (GPU 实例化点,原子数多时性能更佳)
|
||||
use_marker: 1
|
||||
|
||||
# ── 显示参数 ──────────────────────────────────
|
||||
# 盒子透明度:单个数值(统一)或 6 个数的数组,按 [-x,+x,-y,+y,-z,+z] 顺序
|
||||
alpha: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
|
||||
|
||||
# 小球颜色
|
||||
# 小球半径从 coord_file 的 radius 列读取
|
||||
ball_color_r: 0.20 # R 分量 (0~1)
|
||||
ball_color_g: 0.60 # G 分量
|
||||
ball_color_b: 0.90 # B 分量
|
||||
|
||||
# 盒子面颜色
|
||||
box_color_r: 0.80
|
||||
box_color_g: 0.80
|
||||
box_color_b: 0.85
|
||||
|
||||
# ── 摄像机初始位置 ────────────────────────────
|
||||
camera_distance: 120.0 # 摄像机到场景中心的距离
|
||||
camera_elevation: 0.0 # 俯仰角(度),负值=俯视
|
||||
camera_azimuth: 0.0 # 方位角(度)
|
||||
camera_center_x: 60.0 # 摄像机注视点 x
|
||||
camera_center_y: 0.0 # 摄像机注视点 y
|
||||
camera_center_z: 0.0 # 摄像机注视点 z
|
||||
move_camera: 0 # 0=固定视角, 1=按 move_camera.txt 运动
|
||||
|
||||
# ── 视觉放大 ──────────────────────────────────
|
||||
display_amp: [1.0, 1.0, 10.0] # x/y/z 方向视觉位移放大倍数(不影响物理)
|
||||
@@ -0,0 +1,9 @@
|
||||
# move_camera.txt — 摄像机速度段驱动
|
||||
# 格式: start-end vx=f vy=f vz=f rx=d ry=d rz=d
|
||||
# vx/vy/vz: 平移速度(每帧移动单位)
|
||||
# rx/ry/rz: 旋转速度(每帧度数)
|
||||
# rx → elevation(俯仰), ry → azimuth(方位), rz → (预留)
|
||||
#
|
||||
# 示例:前60帧向右平移+绕x旋转,30-90帧向上平移+绕y绕z旋转
|
||||
all vx=0.02
|
||||
# 30-90 vy=0.02 ry=1 rz=1
|
||||
@@ -0,0 +1,54 @@
|
||||
"""
|
||||
Case runner for Dynamics case06 — 1D atomic chain (transverse wave).
|
||||
|
||||
This script keeps program and data separated:
|
||||
- program: ../../dynamics.py
|
||||
- input: ./input
|
||||
- output: ./output
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
CASE_DIR = Path(__file__).resolve().parent
|
||||
DYNAMICS_PATH = Path("..") / ".." / "dynamics.py"
|
||||
INPUT_DIR = Path("input")
|
||||
OUTPUT_DIR = Path("output")
|
||||
CONFIG_FILE = INPUT_DIR / "input.txt"
|
||||
|
||||
|
||||
def load_dynamics_module(module_path: Path):
|
||||
spec = importlib.util.spec_from_file_location("dynamics_module", module_path)
|
||||
if spec is None or spec.loader is None:
|
||||
raise ImportError(f"无法加载 dynamics.py: {module_path}")
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="运行 Dynamics 示例案例 case06")
|
||||
parser.add_argument("--no-plot", action="store_true", help="跳过 matplotlib 绘图")
|
||||
args = parser.parse_args()
|
||||
|
||||
dynamics_path = (CASE_DIR / DYNAMICS_PATH).resolve()
|
||||
input_dir = (CASE_DIR / INPUT_DIR).resolve()
|
||||
output_dir = (CASE_DIR / OUTPUT_DIR).resolve()
|
||||
config_path = (CASE_DIR / CONFIG_FILE).resolve()
|
||||
|
||||
module = load_dynamics_module(dynamics_path)
|
||||
module.run_case(
|
||||
config_path=config_path,
|
||||
runtime_base=CASE_DIR,
|
||||
input_dir=input_dir,
|
||||
output_dir=output_dir,
|
||||
no_plot=args.no_plot,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user