@@ -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 ( 135 deg , #1e293b 0 % , #334155 100 % ) ;
color : #fff ;
padding : 56 px 24 px 48 px ;
text-align : center ;
}
. hero h1 { font-size : 2 rem ; font-weight : 700 ; letter-spacing : -0.02 em ; }
. hero . subtitle {
margin-top : 10 px ;
font-size : 1.05 rem ;
opacity : 0.8 ;
}
. hero . badge {
display : inline-block ;
margin-top : 14 px ;
padding : 4 px 14 px ;
border-radius : 999 px ;
background : rgba ( 255 , 255 , 255 , 0.12 ) ;
font-size : 0.82 rem ;
}
/* ── Layout ── */
. container { max-width : 820 px ; margin : 0 auto ; padding : 32 px 20 px ; }
section { margin-bottom : 44 px ; }
h2 {
font-size : 1.35 rem ;
font-weight : 600 ;
margin-bottom : 16 px ;
padding-bottom : 8 px ;
border-bottom : 2 px solid var ( - - accent ) ;
display : inline-block ;
}
h3 {
font-size : 1.05 rem ;
font-weight : 600 ;
margin : 20 px 0 10 px ;
}
p , li { margin-bottom : 10 px ; }
ul , ol { padding-left : 22 px ; }
strong { color : var ( - - accent ) ; }
/* ── Cards ── */
. card {
background : var ( - - card ) ;
border-radius : 12 px ;
padding : 20 px 24 px ;
margin-bottom : 16 px ;
border : 1 px solid var ( - - border ) ;
box-shadow : 0 1 px 3 px rgba ( 0 , 0 , 0 , 0.04 ) ;
}
/* ── Formula / Code blocks ── */
. formula {
background : var ( - - card ) ;
border-left : 4 px solid var ( - - accent ) ;
padding : 14 px 20 px ;
margin : 14 px 0 ;
font-family : "Times New Roman" , "STIX" , serif ;
font-size : 1.05 rem ;
overflow-x : auto ;
border-radius : 0 8 px 8 px 0 ;
}
code {
background : var ( - - accent - light ) ;
padding : 2 px 7 px ;
border-radius : 4 px ;
font-family : "JetBrains Mono" , "Fira Code" , monospace ;
font-size : 0.88 em ;
}
pre {
background : var ( - - code - bg ) ;
color : var ( - - code - text ) ;
padding : 16 px 20 px ;
border-radius : 10 px ;
overflow-x : auto ;
font-size : 0.85 rem ;
line-height : 1.5 ;
margin : 14 px 0 ;
}
pre . cm { color : #94a3b8 ; font-style : italic ; } /* comment */
/* ── Table ── */
table {
width : 100 % ;
border-collapse : collapse ;
margin : 14 px 0 ;
font-size : 0.92 rem ;
}
th , td {
padding : 8 px 12 px ;
text-align : left ;
border-bottom : 1 px 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 : 6 px ; }
. 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 : 8 px ; align-items : center ; justify-content : center ; margin : 16 px 0 ; }
. flow-step {
background : var ( - - accent - light ) ;
border : 1 px solid var ( - - accent ) ;
border-radius : 8 px ;
padding : 8 px 16 px ;
font-size : 0.88 rem ;
font-weight : 500 ;
}
. flow-arrow { color : var ( - - muted ) ; font-size : 1.2 rem ; }
@ media ( max-width : 600px ) {
. hero h1 { font-size : 1.5 rem ; }
. flow { flex-direction : column ; }
. flow-arrow { transform : rotate ( 90 deg ) ; }
}
< / 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 >