FPU单链模拟
这个文章,主要是给予单链一个初始位移分布,模拟单链演变过程,获得每个时刻,各个原子的速度位移
模型
32个等质量原子,两端固定,原子之间用弹簧连接,弹簧不再是线性的(即 \(F=k\Delta x\))
给予所有原子一个初始分布,不考虑重力,因此原子可以左右移动
模式
每一个原子是一个谐振子,整个系统的解,通过波动方程求解,是已知的(本博客中有求解方法,详见最下方 相关文章
)
波动方程求解2-分离变量法 中最后一节,每一个 \(n\) 对应一个解,每个 \(n\) 对应的解(方程)就是不同的模式
算法
初始分布求解
在实际求解中,知道了势函数(即 \(F=k\Delta x\))可以写出 \(V\) 矩阵(\(n \times n\)),详见 石墨烯振动模式 —— 构建一维链模型
\[V= \left[ \begin{matrix} -2 & 1 & … & 0 & 0 & 0 & … & 0 & 0\\ 1 & -2 & … & 0 & 0 & 0 & … & 0 & 0\\ ... & ... & ... & ... & ... & ... & ... & ... & ... \\ 0 & 0 & ... & -2 & 1 & 0 & ... & 0 & 0 \\ 0 & 0 & ... & 0 & -2 & 1 & ... & 0 & 0 \\ 0 & 0 & ... & 0 & 1 & -2 & ... & 0 & 0 \\ ... & ... & ... & ... & ... & ... & ... & ... & ... \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & -2 & 1 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & -2 \\ \end{matrix} \right]\]
求解该矩阵,可以得到本征向量(\(n \times n\))和本征值(\(n \times 1\)),每个本征模式对应的,本征向量 即为 \(t=0\) 时,该模式对应的原子位置分布。
但是实际计算中,要深入理解一下,因为本征方程求解,不同算法是不一样的,比如
- 用
python
的scipy
求解时,每一列
是一个本征模式对应的本征向量,也就是bzxl[: n]
,而且注意,本征向量和本征值对应,但是本征值并没有排序
。而我们平时说的第一个本征模式,指的是绝对值最小
的那个本征值)
如果遇到求解出来的本征向量,对应的初始分布周期太多,或者说,一个上一个下,太乱,大概率时因为把最后一个本征向量当成第一个了
1 | import numpy as np |
动力学模拟
其实就是知道了初始分布,而且知道了弹簧胡克定律,也就知道了在这个分布下,每个原子受力情况,
1 |
|
通过 \(F=ma\)可以得到加速度,进而得到下一时刻位移、速度,不断进行这一步,就得到了各个时刻原子位移和速度
1 |
|
但是注意,如果直接这样算,算个几十万上百万步,由于精度限制,会导致偏差很大,画出来一个原子的运动轨迹时,很明显
所以使用 verlet
算法,消去了三次项,精度在四次
泰勒展开
\[ \vec{\vec{x}}(t+\Delta t) = \vec{x}(t) + v(t) + \frac{\vec{a}(t)\Delta t^2}{4} + \frac{\vec{b}(t)\Delta t^3}{6} + O(\Delta t^4) \] \[ \vec{x}(t - \Delta t) = \vec{x}(t) - v(t) + \frac{\vec{a}(t)\Delta t^2}{4} - \frac{\vec{b}(t)\Delta t^3}{6} + O(\Delta t^4) \]
相加
\[ \vec{x}(t + \Delta t) = 2\vec{x}(t) - \vec{x}(t - \Delta t) + \vec{a}(t) \Delta t^2 + O(\Delta t^4) \]
很明显,三次项约掉了!精度提高了
1 | # 好处是,三阶导数那里约掉了,比直接用牛顿方程,精度高 |
但是必须两个时刻的位移才能得到下一时刻的,目前第一时刻是用本征向量(绝对值最小的那个),第二时刻,其实还是用 f=ma
但是之后就要用 verlet
算法计算速度和位移了
注意用
t0
t1
计算t2
的位移,受力用t1
的位移来计算,否则计算的时间步多了以后,会有大问题
循环
计算时,n个原子用矩阵计算,这样会快一些,因为矩阵乘法本身就自带并行加速了,每一步的循环之间与上一时刻有关,不容易并行,这里就不并行了,
i5第9代CPU
,计算百万步,也就是十几秒的时间
如果原子过多,其实没必要每一步都保存,可以间隔一定步数,保存一次,减小最后文件的体积,也减少计算过程中内存的占用(因为速度 vst、位移 xst 都在内存里)
1 |
|
最后得到的是不同时刻的每个原子的位移 xst
和速度分布 vst
(矩阵形状 \([(steps+2) \times n]\))
完整代码
注意的是,把时间间隔变小一点,也就是演化的慢一些了,这样可以减小误差,这里用 \(\Delta t=0.01\),为了方便质量用单位\(m=10\),胡克定律的弹簧系数也是 \(k=1\),计算 \(steps=1000000\),也就是1万个时间单位
提前创建文件夹,没有写在python里,是在 linux 运行的,写个sh脚本方便
1 | mkdir cache; |
第三方库
1 | pip3 install numpy scipy |
完整程序(包含beta模型,只是换了个受力就可以)
1 | import numpy as np |
\(\beta\) 模型代码不变,把
model = constant_model_alpha
改成model = constant_model_beta
就行
本文作者:yuhldr
本文地址: https://yuhldr.github.io/posts/28023.html
版权声明:转载请注明出处!