Bohrium
robot
新建

空间站广场

论文
Notebooks
比赛
课程
Apps
我的主页
我的Notebooks
我的论文库
我的足迹

我的工作空间

任务
节点
文件
数据集
镜像
项目
数据库
公开
樊哲勇《分子动力学模拟》python实例 | 5.压力控制算法mtkk的编程实现
樊哲勇《分子动力学模拟》程序代码python实现
python
AI4S101
樊哲勇《分子动力学模拟》程序代码python实现pythonAI4S101
yuxiangc22
mosey
更新于 2024-07-13
推荐镜像 :Basic Image:bohrium-notebook:2023-03-26
推荐机型 :c2_m4_cpu
樊哲勇《分子动力学模拟》python实例 |5.压力控制算法mtkk的编程实现
本章目标
一、压力控制算法
1.1定义
1.2 常用的压力控制算法
二、控温算法代码实现
Berendsen 控温算法
SCR算法
MTTK控压算法
三、不同算法之间的对比
四、控压知识扩展全自由度控压。
各向异性控压
选择合适的控压算法

樊哲勇《分子动力学模拟》python实例 |5.压力控制算法mtkk的编程实现

樊哲勇老师最近出版的书籍《分子动力学模拟》中,使用C++语言进行分子模拟程序的实现。未了更好地理解分子动力学模拟,AI4S1O1-材料小队学习志愿者决定针对樊老师书籍中的内容,进行python语言的程序实现以及注释说明。

本节内容对应樊老师书中的第四章

樊哲勇《分子动力学模拟》python实例 | 概述

代码
文本

©️ Copyright 2023 @ Authors
作者:ChenYuxiang LiDenan(AI4S1O1-材料小队学习志愿者) 📨
日期:2024-7-6
共享协议:本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
快速开始:点击上方的 开始连接 按钮,选择 bohrium-notebook:2023-03-26 镜像及 c2_m4_cpu 节点配置即可开始运行。

代码
文本

本章目标

  1. 了解分子动力学模拟中的压力控制常用算法
  2. 进行python编码实现
  3. 进行不同算法之间的对比
  4. 控压知识扩展
代码
文本

一、压力控制算法

1.1定义

压力控制算法,也称为压力耦合算法或恒压算法,是在分子动力学(MD)模拟中用来调节系统压力的方法。这些算法通过调节系统的体积或者施加外部压力,使得系统在模拟过程中保持在预设的压力状态下。

在MD模拟中,压力可以通过以下几种方式进行控制:

  1. 体积调节(Volume Adjustment):通过改变模拟盒的体积来调节系统的压力。
  2. 应力张量(Stress Tensor):通过施加外部应力,调节系统内部的力平衡。 常用的压力控制算法

1.2 常用的压力控制算法

Berendsen 控压算法:该算法通过逐步调整系统的体积,使得系统压力逐渐趋向目标压力。简单,高效,适合初步平衡不能保证正确的热力学统计,越接近目标压力调节力度减弱

SCR(stochastic cell rescaling) 控压算法:在模拟过程中随机地对模拟盒的体积进行重新缩放,从而调整系统的压力。快速平衡,保持了动力学一致,易于实现;随机性引入了不稳定性

MTTK(Martyna-Tuckerman-Tobias-Klein)控压算法:算法基于扩展系综方法,通过引入额外的动态变量(如体积的变化率和应力张量)来调节系统的压力。精确控制压力,适用于复杂系统计算复杂度高,趋于平衡的过程表现较上两个差

PRB(Parrinello-Rahman Barostat)恒压算法:算法引入一个变换矩阵(通常表示为 ℎ)来描述模拟盒的形状和大小变化,通过将模拟盒的形状和体积作为动态变量,使系统在恒定外界压力下进行演化。能处理各向异性应变,精确热力学统计,适用于复杂系统;实现复杂,计算开销大,参数调节困难

Nose-Hoover 链恒压算法:算法通过引入虚拟变量(称为热浴变量和体积变量),使系统能够在恒温恒压(NPT)系综下演化,适用于高精度模拟和复杂系统。缺点是实现复杂,调节参数困难。

因为篇幅有限,本章节主要示范Berendsen 控压算法,*SCR控压算法,MTTK控压算法

代码
文本

二、控温算法代码实现

代码
文本

Berendsen 控温算法

Berendsen 控压算法通过将系统体积按指数方式调节,使得系统的压力逐渐逼近目标压力。具体来说,算法根据当前压力和目标压力之间的差异,调整系统的体积。

考虑各向同性时,体系的压强变化率正比于实际压强 p 与目标压强p0 的差值: 当体系的实际压强小于目标压强时, dp/dt 为正,体系压强有增加的趋势;当体系的 实际压强大于目标压强时, dp/dt 为负,体系压强有减小的趋势。参数 τp 具有时间的量纲, 它反映了压强变化的快慢,可被称为控压算法的弛豫时间。引入等温压缩率 可进一步的表达,如同对体积做如下标度变换: 相当于改变坐标: 由于每一步变化不大,坐标变换等同如下: 同时如果盒子为立方体,盒子边长L改变: 推广到一般的情况,体系的盒子矩阵 hαβ 和原子坐标 ri 都按照一个形变矩阵 µαβ 变换: 其中, 是等温压缩率张量。这代表最一般的 6 自由度控压。

代码
文本

SCR算法

SCR 算法的核心思想是在模拟过程中随机地对模拟盒的体积进行重新缩放,从而调整系统的压力。与传统的压力控制算法相比,SCR 采用了一种随机过程来控制压力,这种随机性有助于系统更快地达到平衡。与 Berendsen 控压算法相比, SRC 控压算法给形变矩阵增加了一个随机项 其中, 是均值为零、方差为一的正态分布的随机数, 是一个与盒子自由度耦合 有关的因子。当采用各向同性控压时,该因子为 3,其他情况下为 1。

代码
文本

MTTK控压算法

其算法公式较为复杂,请参考樊老师的书籍第七章P142

下面的代码实现了一个分子动力学模拟,通过Nosé-Hoover链(NHC)热浴控制粒子和盒子的温度,并计算粒子的位置、速度、势能和压力变化。具体的计算思路如下:

  1. 初始化参数和变量

    • 初始化系统常数、盒子参数、粒子参数和NHC热浴参数。
    • 定义时间步长 dt 和半时间步长 dt2
    • 初始化粒子位置 x 和速度 v,并根据初始位置和盒子长度计算力 f
  2. 定义辅助函数

    • sinh_factor(x2):计算双曲正弦函数的近似值。
    • find_force(x, h):根据粒子的位置和盒子长度计算粒子所受的力。
    • find_potential(x, h):计算粒子在给定位置处的势能。
    • find_pressure(ek2, x, h):根据粒子的动能、位置和盒子长度计算压力。
    • nhc(...):实现Nosé-Hoover链热浴的动力学计算,包括更新热浴的速度、位置和计算缩放因子。
  3. 时间演化循环

    • 进行多步时间演化模拟,每步更新系统的状态(位置、速度、盒子长度等)。
    • 每隔一定步数输出系统的状态数据到文件 data.txt,包括粒子的位置、盒子长度、总能量和速度。
  4. 时间演化步骤

    • 在每个时间步内,分别执行多种演化操作:
      • 更新盒子的动量。
      • 更新粒子的速度。
      • 更新盒子的动量。
      • 更新粒子的速度和位置。
      • 更新盒子长度。
      • 更新力。
      • 更新粒子的速度。
      • 更新盒子的动量。
  5. 能量守恒检查

    • 每个采样间隔计算系统的总能量,并输出到文件中,用于检查能量是否守恒。
代码
文本
代码
文本
[ ]
#MTTK算法python实现
import math

# 常数
TWOPI = 2 * math.pi
NUMBER_OF_STEPS = 10000000 # 示例值,模拟步数
SAMPLE_INTERVAL = 1000 # 示例值,数据采样间隔

# 计算双曲正弦函数的一种近似形式
def sinh_factor(x2):
c2 = 1.0 / (2.0 * 3.0)
c4 = c2 / (4.0 * 5.0)
c6 = c4 / (6.0 * 7.0)
c8 = c6 / (8.0 * 9.0)
return 1.0 + x2 * (c2 + x2 * (c4 + x2 * (c6 + x2 * c8)))

# 根据粒子的位置 x 和盒子的长度 h 计算粒子所受的力
def find_force(x, h):
tmp = TWOPI / h
return -math.sin(x * tmp) / tmp

# 计算粒子在位置 x 处的势能
def find_potential(x, h):
tmp = TWOPI / h
return (1.0 - math.cos(x * tmp)) / (tmp * tmp)

# 根据粒子动能 ek2、位置 x 和盒子长度 h 计算压力
def find_pressure(ek2, x, h):
tmp = TWOPI / h
potential = (1.0 - math.cos(x * tmp)) / (tmp * tmp)
return (ek2 - 2.0 * potential) / h

# 实现 Nosé-Hoover 链(NHC)热浴的动力学计算
def nhc(M, pos_eta, vel_eta, mas_eta, Ek2, kT, dN, dt2):
dt4 = dt2 * 0.5
dt8 = dt4 * 0.5

# 更新最后一个热浴的速度
G = vel_eta[M - 2] * vel_eta[M - 2] / mas_eta[M - 2] - kT
vel_eta[M - 1] += dt4 * G

# 从倒数第二个热浴开始更新速度
for m in range(M - 2, -1, -1):
tmp = math.exp(-dt8 * vel_eta[m + 1] / mas_eta[m + 1])
G = vel_eta[m - 1] * vel_eta[m - 1] / mas_eta[m - 1] - kT
if m == 0:
G = Ek2 - dN * kT
vel_eta[m] = tmp * (tmp * vel_eta[m] + dt4 * G)

# 从最后一个热浴开始更新位置
for m in range(M - 1, -1, -1):
pos_eta[m] += dt2 * vel_eta[m] / mas_eta[m]

# 计算缩放因子
factor = math.exp(-dt2 * vel_eta[0] / mas_eta[0])

# 从第一个热浴开始更新速度
for m in range(M - 1):
tmp = math.exp(-dt8 * vel_eta[m + 1] / mas_eta[m + 1])
G = vel_eta[m - 1] * vel_eta[m - 1] / mas_eta[m - 1] - kT
if m == 0:
G = Ek2 * factor * factor - dN * kT
vel_eta[m] = tmp * (tmp * vel_eta[m] + dt4 * G)

# 更新最后一个热浴的速度
G = vel_eta[M - 2] * vel_eta[M - 2] / mas_eta[M - 2] - kT
vel_eta[M - 1] += dt4 * G

return factor

def main():
# 盒子参数
h = 1.0 # 盒子长度
pg = 0.0 # 盒子动量
Wg = 18.0 # 盒子质量
dN_box = 1.0 # 盒子的自由度
# 粒子参数
dN = 1.0 # 粒子的自由度
dt = 0.005 # 时间步长
dt2 = dt * 0.5 # 半时间步长
kT = 1.0 # 目标温度
p0 = 1.0 # 目标压力
x = 0.2 # 位置
v = 0.0 # 速度
mass = 1.0 # 质量
f = find_force(x, h) # 力

# NHC 热浴参数(粒子)
M = 4
tau = 1
pos_eta = [0.0] * M
vel_eta = [0.0] * M
mas_eta = [0.0] * M
vel_eta[0] = vel_eta[2] = +1.0
vel_eta[1] = vel_eta[3] = -1.0
for i in range(M):
pos_eta[i] = 0.0
mas_eta[i] = kT * tau * tau
if i == 0:
mas_eta[i] = dN * kT * tau * tau

# NHC 热浴参数(盒子)
M_baro = 4
tau_baro = 1
pos_eta_baro = [0.0] * M_baro
vel_eta_baro = [0.0] * M_baro
mas_eta_baro = [0.0] * M_baro
vel_eta_baro[0] = vel_eta_baro[2] = +1.0
vel_eta_baro[1] = vel_eta_baro[3] = -1.0
for i in range(M_baro):
pos_eta_baro[i] = 0.0
mas_eta_baro[i] = kT * tau_baro * tau_baro
if i == 0:
mas_eta_baro[i] = dN_box * kT * tau_baro * tau_baro

# 时间演化
with open("data.txt", "w") as fid:
for step in range(NUMBER_OF_STEPS):
# 输出数据
if step % SAMPLE_INTERVAL == 0:
inv = mass * v * v * 0.5 + find_potential(x, h) # 粒子
inv += 0.5 * pg * pg / Wg + p0 * h # 盒子
inv += kT * dN * pos_eta[0] # NHC-粒子
for m in range(1, M):
inv += kT * pos_eta[m]
for m in range(M):
inv += 0.5 * vel_eta[m] * vel_eta[m] / mas_eta[m]
inv += kT * dN_box * pos_eta_baro[0] # NHC-盒子
for m in range(1, M_baro):
inv += kT * pos_eta_baro[m]
for m in range(M_baro):
inv += 0.5 * vel_eta_baro[m] * vel_eta_baro[m] / mas_eta_baro[m]
fid.write(f"{x:25.15f}{h:25.15f}{inv:25.15f}{v:25.15f}\n")
# 更新步骤中的时间演化
Ek2 = 0.0
factor = 0.0

# 更新盒子的动量
# 计算盒子的动能 Ek2
Ek2 = pg * pg / Wg
# 使用NHC算法更新盒子的动量,并计算缩放因子 factor
factor = nhc(M_baro, pos_eta_baro, vel_eta_baro, mas_eta_baro, Ek2, kT, dN_box, dt2)
# 通过缩放因子更新盒子的动量 pg
pg *= factor

# 更新粒子的速度
# 计算粒子的动能 Ek2
Ek2 = v * v * mass
# 使用NHC算法更新粒子的速度,并计算缩放因子 factor
factor = nhc(M, pos_eta, vel_eta, mas_eta, Ek2, kT, dN, dt2)
# 通过缩放因子更新粒子的速度 v
v *= factor

# 更新盒子的动量
# 计算粒子的动能 Ek2
Ek2 = v * v * mass
# 根据盒子长度 h、压力差和粒子动能 Ek2 更新盒子的动量 pg
pg += dt2 * (h * (find_pressure(Ek2, x, h) - p0) + Ek2)

# 更新粒子的速度和位置
# 计算时间步长 dt2 对动量的影响 x1
x1 = -pg / Wg * dt2
# 计算指数 tmp 用于更新速度 v 和位置 x
tmp = math.exp(x1)
# 使用双曲正弦因子更新粒子的速度 v
v = v * tmp * tmp + (dt2 / mass) * f * tmp * sinh_factor(x1 * x1)

# 更新粒子的速度和位置
# 计算时间步长 dt 对动量的影响 x1
x1 = pg / Wg * dt2
# 计算指数 tmp 用于更新位置 x
tmp = math.exp(x1)
# 使用双曲正弦因子更新粒子的位置 x
x = x * tmp * tmp + dt * v * tmp * sinh_factor(x1 * x1)
# 确保粒子的位置 x 在盒子长度 h 内
if x > h:
x -= h
if x < 0:
x += h

# 更新盒子长度
# 根据盒子的动量 pg 更新盒子长度 h
h *= math.exp(pg / Wg * dt)

# 更新力
# 根据粒子的位置 x 和盒子长度 h 计算力 f
f = find_force(x, h)

# 再次更新粒子的速度
# 计算时间步长 dt2 对动量的影响 x1
x1 = -pg / Wg * dt2
# 计算指数 tmp 用于更新速度 v
tmp = math.exp(x1)
# 使用双曲正弦因子更新粒子的速度 v
v = v * tmp * tmp + (dt2 / mass) * f * tmp * sinh_factor(x1 * x1)

# 再次更新盒子的动量
# 计算粒子的动能 Ek2
Ek2 = v * v * mass
# 根据盒子长度 h、压力差和粒子动能 Ek2 再次更新盒子的动量 pg
pg += dt2 * (h * (find_pressure(Ek2, x, h) - p0) + Ek2)

# 再次更新粒子的速度
# 计算粒子的动能 Ek2
Ek2 = v * v * mass
# 使用NHC算法更新粒子的速度,并计算缩放因子 factor
factor = nhc(M, pos_eta, vel_eta, mas_eta, Ek2, kT, dN, dt2)
# 通过缩放因子更新粒子的速度 v
v *= factor

# 再次更新盒子的动量
# 计算盒子的动能 Ek2
Ek2 = pg * pg / Wg
# 使用NHC算法更新盒子的动量,并计算缩放因子 factor
factor = nhc(M_baro, pos_eta_baro, vel_eta_baro, mas_eta_baro, Ek2, kT, dN_box, dt2)
# 通过缩放因子更新盒子的动量 pg
pg *= factor

if __name__ == "__main__":
main()

代码
文本

三、不同算法之间的对比

使用了樊哲勇老师等人编写的GPUMD软件,可以实现不同算法之间的对比。具体的输入脚本,请参考:

`potential   Si_Tersoff_1989.txt
velocity    300
#ensemble    npt_scr 300 300 100 0 50 1000
#ensemble    npt_ber 300 300 100 0 50 1000
ensemble    npt_mttk temp 300 300 iso 0 0
time_step   1

dump_thermo 1

run         10000`

运行结果可视化后如下:

alt alt 在 Berendsen 控 压算法中,压强和体积都以指数函数的方式趋于平衡值,达到平衡后便几乎没有涨落。 SCR控压算法在趋于平衡的过程与 Berendsen 控压算法有类似的表现,但在体系达到平衡后压强和体积都有合理的涨落,遵循 NpT 系综的统计分布。在 MTTK 控压算法中,压强和体积在体系趋于平衡的过程中都有较大的振荡。虽然 MTTK 和 SCR 算法给出的压强和盒子长度涨落的局部细节不一样,但是它们确实都给出正确的 NpT 系综。

代码
文本

四、控压知识扩展全自由度控压。

各向异性控压

上述方法是各向同性控压,也可以进行三轴独立控压和全自由度控压。 使用GPUMD软件实现这一过程: #三轴独立控压 potential Si_Tersoff_1989.txt velocity 300

#ensemble    npt_ber 300 300 100 10 0 0 50 50 50 1000
ensemble    npt_scr 300 300 100 10 0 0 50 50 50 1000
#ensemble    npt_mttk temp 300 300 x 10 10 y 0 0 z 0 0
time_step   1
dump_thermo 2
run         20000

#全自由度控压
potential   Si_Tersoff_1989.txt
velocity    300

#ensemble    npt_ber 300 300 100 0 0 0 0 0 10 50 50 50 50 50 50 1000
ensemble    npt_scr 300 300 100 0 0 0 0 0 10 50 50 50 50 50 50 1000
#ensemble    npt_mttk temp 300 300 x 0 0 y 0 0 z 0 0 yz 0 0 xz 0 0 xy 10 10
time_step   1
dump_thermo 2
dump_exyz   20000
run         20000

结果如下: alt alt

选择合适的控压算法

具体算法选择建议

  1. Berendsen Barostat:适用于快速达到平衡、计算效率高、适用于一般的分子动力学模拟,不需要严格的统计特性。
  2. Parrinello-Rahman Barostat:适用于需要精确控制压力和处理各向异性系统的模拟,特别是在应力和应变关系的研究中。
  3. MTTK控压算法:适用于高精度和长时间模拟,适合复杂生物分子和材料系统,能够提供高稳定性和准确性。
  4. Stochastic Cell Rescaling (SCR):适用于一般的分子动力学模拟,实现简单,但不适用于高精度模拟。
  5. Andersen Barostat:适用于需要较好压力控制的中等精度模拟,实现复杂,计算效率较低。

实际操作建议

  1. 测试和调试:在选择控压算法时,可以先进行短时间的测试模拟,观察系统在不同算法下的平衡速度和压力波动情况。
  2. 结合使用:在某些情况下,可以结合使用不同的控压算法。例如,可以先使用Berendsen Barostat快速达到平衡,然后切换到MTTK控压算法进行精确的长时间模拟。
  3. 参考文献:查阅相关领域的文献,了解在类似研究中常用的控压算法,以便选择适合的算法。
代码
文本
樊哲勇《分子动力学模拟》程序代码python实现
python
AI4S101
樊哲勇《分子动力学模拟》程序代码python实现pythonAI4S101
点个赞吧
推荐阅读
公开
樊哲勇《分子动力学模拟》python实例 | 3.Tersoff 势的编程实现
樊哲勇《分子动力学模拟》程序代码python实现AI4S101
樊哲勇《分子动力学模拟》程序代码python实现AI4S101
yuxiangc22
更新于 2024-06-26
1 转存文件
公开
樊哲勇《分子动力学模拟》python实例 | 1.一个简单的分子动力学模拟程序
樊哲勇《分子动力学模拟》程序代码python实现AI4S101
樊哲勇《分子动力学模拟》程序代码python实现AI4S101
yuxiangc22
更新于 2024-06-10
1 赞1 转存文件