Bohrium
robot
新建

空间站广场

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

我的工作空间

任务
节点
文件
数据集
镜像
项目
数据库
公开
樊哲勇《分子动力学模拟》python实例 | 4.用简谐振子展示控温算法的效果
樊哲勇《分子动力学模拟》程序代码python实现
AI4S101
python
樊哲勇《分子动力学模拟》程序代码python实现AI4S101python
yuxiangc22
更新于 2024-07-04
推荐镜像 :Basic Image:bohrium-notebook:2023-03-26
推荐机型 :c2_m4_cpu
1
樊哲勇《分子动力学模拟》python实例 | 4.用简谐振子展示控温算法的效果
本章目标
一、控温算法
1.1 定义
1.2 常见的控温算法
二、控温算法代码实现
Berendsen 控温算法
Nose-Hoover 控温算法
Langevin Thermostat控温算法
Andersen Thermostat 控温算法
三、进行不同算法之间的对比
四、控温知识扩展
1. Velocity Rescaling Thermostat(速度重标定控温算法)
2. Parrinello-Rahman Thermostat(Parrinello-Rahman 控温算法)
3. Martyna-Tuckerman-Klein (MTK) Thermostat
4. Stochastic Velocity Rescaling (SVR) Thermostat(随机速度重标定控温算法)
扩展知识点

樊哲勇《分子动力学模拟》python实例 | 4.用简谐振子展示控温算法的效果

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

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

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

代码
文本

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

代码
文本

本章目标

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

一、控温算法

1.1 定义

分子动力学(MD)控温算法(thermostat)是指在MD模拟中用来控制系统温度的算法。由于MD模拟是通过数值积分牛顿运动方程来计算粒子的运动轨迹,这种方法默认的是微正则系综(NVE系综),即系统的能量和粒子数目是固定的。在实际研究中,我们通常希望在正则系综(NVT系综,温度固定)或等压等温系综(NPT系综,温度和压力固定)下进行模拟,因此需要引入控温算法来调节系统温度。

使用控温算法的原因:

  1. 研究温度依赖性现象:许多物理和化学现象都依赖于温度,例如相变、反应速率、扩散等。在研究这些现象时,需要精确控制系统温度。

  2. 模拟实际实验条件:实验室中的大多数实验都是在恒温条件下进行的,通过控温算法,可以更好地与实验结果进行对比和验证。

  3. 系统稳定性:在长时间模拟中,系统的温度可能会因为能量的积累或损失而发生变化,控温算法可以帮助维持系统在目标温度附近,确保模拟结果的可靠性。

1.2 常见的控温算法

Berendsen Thermostat: 通过将系统的温度逐渐调整到目标温度,调节系统的温度变化速率。优点是简单且收敛速度快,缺点是不能准确生成正则系综

Nose-Hoover Thermostat:通过引入虚拟热浴和额外自由度来控制系统温度,可以准确产生正则系综。缺点是可能在小系统或短时间内产生温度振荡

Langevin Thermostat:通过引入随机力和阻尼力来模拟与外界环境的热交换。优点是能够有效控制温度,并且在处理溶液和生物大分子时非常有用。

Andersen Thermostat:通过随机选择粒子进行速度重置,从而控制温度。优点是能够很好地热化系统,但对动力学过程的影响较大。

代码
文本

二、控温算法代码实现

代码
文本

Berendsen 控温算法

Berendsen 控温算法的核心思想是通过一个比例反馈机制来调整系统的动能,使系统的温度逐渐接近目标温度。具体来说,系统的温度 𝑇和目标温度 𝑇0的关系可以通过以下公式进行调整: 其中,𝜏是一个时间常数,决定了温度调节的速度。通过这个公式,我们可以得到新的温度 𝑇′: 为了实现温度的调节,我们需要调整系统中每个粒子的速度 𝑣𝑖。调整后的速度vi′可以通过以下公式计算: 其中,𝜆是一个缩放因子,用于调整粒子的速度: 这里,Δ𝑡是时间步长,𝑇是当前系统的温度,𝑇0是目标温度。

可知算法步骤

  1. 计算当前系统温度 𝑇:通过系统的动能计算当前温度。
  2. 计算缩放因子 𝜆:使用上面的公式计算速度调整因子。
  3. 调整粒子速度:将每个粒子的速度 𝑣𝑖乘以缩放因子 𝜆,得到新的速度 𝑣𝑖′
  4. 更新系统动能和温度:通过新的速度计算新的动能和温度,检查是否接近目标温度。
代码
文本
[1]
#Berendsen 控温算法
import numpy as np
import matplotlib.pyplot as plt

# 计算系统温度的函数
def compute_temperature(velocities, masses, k_B):
kinetic_energy = 0.5 * np.sum(masses * velocities**2)
temperature = (2 / (3 * k_B * len(masses))) * kinetic_energy
return temperature

# Berendsen控温算法函数
def berendsen_thermostat(velocities, masses, T0, tau, dt, steps, k_B):
temperatures = np.zeros(steps)
# 初始温度
T = compute_temperature(velocities, masses, k_B)
temperatures[0] = T
for step in range(1, steps):
# 计算缩放因子λ
lambda_factor = np.sqrt(1 + (dt / tau) * ((T0 / T) - 1))
# 调整粒子速度
velocities *= lambda_factor
# 更新系统动能和温度
T = compute_temperature(velocities, masses, k_B)
temperatures[step] = T
return temperatures

# 参数设置
initial_temperature = 300 # 初始温度
target_temperature = 500 # 目标温度
tau = 100.0 # 时间常数
dt = 1.0 # 时间步长
steps = 1000 # 模拟步数
num_particles = 100 # 粒子数目
k_B = 1.38e-23 # 玻尔兹曼常数

# 初始化粒子速度和质量
masses = np.ones(num_particles) # 设定所有粒子的质量为1
initial_velocities = np.random.normal(0, np.sqrt(initial_temperature * k_B), num_particles) # 初始速度

# 运行Berendsen控温算法
temperatures = berendsen_thermostat(initial_velocities, masses, target_temperature, tau, dt, steps, k_B)

# 绘制温度变化曲线
plt.figure(figsize=(10, 6))
plt.plot(temperatures, label='Temperature')
plt.axhline(y=target_temperature, color='r', linestyle='--', label='Target Temperature')
plt.xlabel('Time Steps')
plt.ylabel('Temperature (K)')
plt.title('Temperature Control using Berendsen Thermostat')
plt.legend()
plt.grid(True)
plt.show()
代码
文本

Nose-Hoover 控温算法

Nose-Hoover 控温算法基于Nose-Hoover链(Nose-Hoover chain),其基本思想是通过引入一个与系统耦合的虚拟热浴来控制系统的动能(温度)。该虚拟热浴通过一个附加的自由度(即热浴变量)来模拟系统与外界环境的能量交换。具体的公式见书P116-118。 优点

  1. 精确控制温度
    • Nose-Hoover 控温算法能够将系统的温度精确地保持在设定值上,而不会引入明显的温度波动。
  2. 保留动力学性质
    • 该算法不会破坏系统的动力学性质,可以准确地模拟出系统的时间相关行为和输运性质(如扩散系数)。
  3. 能量守恒
    • 系统在 Nose-Hoover 控温算法下仍然能保持总能量的守恒,只是在系统能量和热浴能量之间进行交换。

缺点

  1. 参数敏感性
    • 算法对参数(如耦合常数)的选择较为敏感,参数选择不当可能导致控温效果不佳或数值不稳定。
  2. 数值稳定性问题
    • 对于某些系统,Nose-Hoover 控温算法可能导致数值不稳定,尤其是当系统较大或者系统中存在剧烈的动态变化时。
  3. 初始态依赖性
    • 算法对初始状态较为敏感,初始温度和虚拟热库参数的设置需要仔细调节。
  4. 复杂性较高
    • 与简单的控温方法(如Berendsen Thermostat或Langevin Thermostat)相比,Nose-Hoover 控温算法实现和调试相对复杂。

算法步骤:

  1. 实施控温相关的时间演化算符 e*iLT∆t/2。
  2. 实施与速度-Verlet 积分算法对应的时间演化算符。
  3. 再次实施控温相关的时间演化算符 eiLT∆t/2。
代码
文本
[2]
# Nose-Hoover 控温算法
import math
from tqdm import tqdm
import numpy as np
import matplotlib.pyplot as plt

NUMBER_OF_STEPS = 1000000
SAMPLE_INTERVAL = 1

length = int(NUMBER_OF_STEPS / SAMPLE_INTERVAL)
x_list = np.zeros(length, dtype=float)
v_list = np.zeros(length, dtype=float)
inv_list = np.zeros(length, dtype=float)
vel_eta_list = np.zeros(length, dtype=float)


def nh(pos_eta, vel_eta, mas_eta, Ek2, kT, dN, dt2):
dt4 = dt2 * 0.5

G = Ek2 - dN * kT
vel_eta[0] = vel_eta[0] + dt4 * G

pos_eta[0] += dt2 * vel_eta[0] / mas_eta

# Compute the scale factor
factor = math.exp(-dt2 * vel_eta[0] / mas_eta)

# Update thermostat velocities from 0 to M - 2:
G = Ek2 * factor * factor - dN * kT
vel_eta[0] = vel_eta[0] + dt4 * G

return factor


# Main simulation loop
dN = 1.0
dt = 0.01
dt2 = dt * 0.5
kT = 1
x = 0
v = 1
mass = 1.0
k_spring = 1
f = -k_spring * x
pos_eta = [0.0]
vel_eta = [1]
mas_eta = 1

Ek2 = 0.0
factor = 0.0

for step in tqdm(range(NUMBER_OF_STEPS)):
inv = mass * v * v * 0.5 + k_spring * x * x * 0.5
inv += kT * dN * pos_eta[0]
Ek2 = v * v * mass
factor = nh(pos_eta, vel_eta, mas_eta, Ek2, kT, dN, dt2)
v *= factor

v += dt2 * (f / mass)
x += dt * v
f = -k_spring * x
v += dt2 * (f / mass)

if step % SAMPLE_INTERVAL == 0:
nn = int(step / SAMPLE_INTERVAL)
x_list[nn] = x
v_list[nn] = v
inv_list[nn] = inv
vel_eta_list[nn] = vel_eta[0]

Ek2 = v * v * mass
factor = nh(pos_eta, vel_eta, mas_eta, Ek2, kT, dN, dt2)
v *= factor

# %%
fig, axs = plt.subplots(2, 2)
axs[0, 0].scatter(x_list, v_list, s=1)
axs[0, 0].set_xlim(-4, 4)
axs[0, 0].set_ylim(-4, 4)
axs[0, 0].set_aspect(1)

choose = (vel_eta_list >= -0.01) & (vel_eta_list <= 0.01)
axs[0, 1].scatter(x_list[choose], v_list[choose], s=1)
axs[0, 1].set_xlim(-4, 4)
axs[0, 1].set_ylim(-4, 4)
axs[0, 1].set_aspect(1)

axs[1, 0].hist(v_list, density=True, bins=100)
axs[1, 0].set_xlim(-4, 4)
axs[1, 0].set_ylim(0, 0.5)
axs[1, 0].set_box_aspect(1)

axs[1, 1].hist(x_list, density=True, bins=100)
axs[1, 1].set_xlim(-4, 4)
axs[1, 1].set_ylim(0, 0.5)
axs[1, 1].set_box_aspect(1)
fig.set_size_inches(6, 6)

# %%
fig, axs = plt.subplots(1, 3)
axs[0].hist2d(
x_list, v_list, bins=51, range=[[-4, 4], [-4, 4]], cmap="Blues", density=True
)
axs[0].set_xlim(-4, 4)
axs[0].set_ylim(-4, 4)
axs[0].set_xlabel("x")
axs[0].set_ylabel("p")
axs[0].set_xticks([-4, -2, 0, 2, 4])
axs[0].set_yticks([-4, -2, 0, 2, 4])
axs[0].set_aspect(1)

position = np.linspace(-4, 4, 500)
boltz_factor = np.exp(-0.5 / kT * k_spring * position**2)
Z = np.trapz(boltz_factor, position)
boltz_factor /= Z
axs[1].plot(position, boltz_factor, color="k", linestyle="--")
axs[2].plot(position, boltz_factor, color="k", linestyle="--")

axs[1].hist(x_list, density=True, bins=21, alpha=0.8)
axs[1].set_xlim(-4, 4)
axs[1].set_ylim(0, 0.5)
axs[1].set_box_aspect(1)
axs[1].set_xlabel("x")
axs[1].set_ylabel("probability")
axs[1].set_xticks([-4, -2, 0, 2, 4])

axs[2].hist(v_list, density=True, bins=21, alpha=0.8)
axs[2].set_xlim(-4, 4)
axs[2].set_ylim(0, 0.5)
axs[2].set_box_aspect(1)
axs[2].set_xlabel("p")
axs[2].set_ylabel("probability")
axs[2].set_xticks([-4, -2, 0, 2, 4])

fig.set_size_inches(11, 3)
plt.savefig("md_ho_nh.pdf", bbox_inches="tight")
plt.show()

100%|██████████| 1000000/1000000 [00:04<00:00, 248326.64it/s]
代码
文本

为了克服NH控温算法的不足,Martyna、 Klein 和 Tuckerman 将NH算法中的一个控温变量扩展为一组控温变量,称为一条控温链 (chain)。所以,这种控温算法常称为NHC控温算法。在该算法中,第0个控温变量相当于NH控温算法中的那个控温变量,而第m(m ≥ 1)个控温变量的作用是控制第m − 1个控温变量的温度。详细公式见书P123-125

与传统的 Nose-Hoover 恒温器相比,NHC 方法具有以下优点:

更高的效率: NHC 方法可以更有效地控制系统的温度,特别是在模拟大型系统时。

更好的稳定性: NHC 方法比传统的 Nose-Hoover 恒温器更稳定,不易产生漂移。

更宽的温度范围: NHC 方法可以用于模拟更宽的温度范围内的系统。

代码
文本
[3]
#NHC代码
import math
from tqdm import tqdm
import numpy as np
import matplotlib.pyplot as plt

NUMBER_OF_STEPS = 5000000
SAMPLE_INTERVAL = 10

length = int(NUMBER_OF_STEPS / SAMPLE_INTERVAL)
x_list = np.zeros(length, dtype=float)
v_list = np.zeros(length, dtype=float)
inv_list = np.zeros(length, dtype=float)


def nhc(M, pos_eta, vel_eta, mas_eta, Ek2, kT, dN, dt2):
dt4 = dt2 * 0.5
dt8 = dt4 * 0.5

# Update velocity of the last (M - 1) thermostat:
G = vel_eta[M - 2] * vel_eta[M - 2] / mas_eta[M - 2] - kT
vel_eta[M - 1] += dt4 * G

# Update thermostat velocities from M - 2 to 0:
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)

# Update thermostat positions from M - 1 to 0:
for m in range(M - 1, -1, -1):
pos_eta[m] += dt2 * vel_eta[m] / mas_eta[m]

# Compute the scale factor
factor = math.exp(-dt2 * vel_eta[0] / mas_eta[0])

# Update thermostat velocities from 0 to M - 2:
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)

# Update velocity of the last (M - 1) thermostat:
G = vel_eta[M - 2] * vel_eta[M - 2] / mas_eta[M - 2] - kT
vel_eta[M - 1] += dt4 * G

return factor


# Main simulation loop
dN = 1.0
dt = 0.01
dt2 = dt * 0.5
kT = 1.0
x = 0
v = 1
mass = 1.0
k_spring = 1.0
f = -k_spring * x
M = 4
tau = dt * 100
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

Ek2 = 0.0
factor = 0.0


for step in tqdm(range(NUMBER_OF_STEPS)):
inv = mass * v * v * 0.5 + k_spring * x * x * 0.5
inv += kT * dN * pos_eta[0]

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]

if step % SAMPLE_INTERVAL == 0:
nn = int(step / SAMPLE_INTERVAL)
x_list[nn] = x
v_list[nn] = v
inv_list[nn] = inv

Ek2 = v * v * mass
factor = nhc(M, pos_eta, vel_eta, mas_eta, Ek2, kT, dN, dt2)
v *= factor

v += dt2 * (f / mass)
x += dt * v
f = -k_spring * x
v += dt2 * (f / mass)

Ek2 = v * v * mass
factor = nhc(M, pos_eta, vel_eta, mas_eta, Ek2, kT, dN, dt2)
v *= factor

# %%
fig, axs = plt.subplots(1, 3)
axs[0].hist2d(x_list, v_list, bins=21, range=[[-4, 4], [-4, 4]], cmap="Blues")
axs[0].set_xlim(-4, 4)
axs[0].set_ylim(-4, 4)
axs[0].set_xlabel("x")
axs[0].set_ylabel("p")
axs[0].set_xticks([-4, -2, 0, 2, 4])
axs[0].set_yticks([-4, -2, 0, 2, 4])
axs[0].set_aspect(1)

position = np.linspace(-4, 4, 500)
boltz_factor = np.exp(-0.5 / kT * k_spring * position**2)
Z = np.trapz(boltz_factor, position)
boltz_factor /= Z
axs[1].plot(position, boltz_factor, color="k", linestyle="--")
axs[2].plot(position, boltz_factor, color="k", linestyle="--")

axs[1].hist(x_list, density=True, bins=21, alpha=0.8)
axs[1].set_xlim(-4, 4)
axs[1].set_ylim(0, 0.5)
axs[1].set_box_aspect(1)
axs[1].set_xlabel("x")
axs[1].set_ylabel("probability")
axs[1].set_xticks([-4, -2, 0, 2, 4])

axs[2].hist(v_list, density=True, bins=21, alpha=0.8)
axs[2].set_xlim(-4, 4)
axs[2].set_ylim(0, 0.5)
axs[2].set_box_aspect(1)
axs[2].set_xlabel("p")
axs[2].set_ylabel("probability")
axs[2].set_xticks([-4, -2, 0, 2, 4])

fig.set_size_inches(11, 3)
plt.savefig("md_ho_nhc.pdf", bbox_inches="tight")
plt.show()

# %%

100%|██████████| 5000000/5000000 [01:15<00:00, 66305.69it/s]
代码
文本

Langevin Thermostat控温算法

郎之万控温算法(Langevin Thermostat)是一种用于分子动力学模拟中的控温方法,通过引入随机力和摩擦力来模拟与热浴(热库)的相互作用,从而使系统在一定的温度下进行演化。运动方程如下:

算法步骤

  1. 初始化粒子的位置和速度初始化粒子的位置和速度。设置模拟参数,如摩擦系数 𝛾、时间步长 Δ𝑡、目标温度 𝑇等。
  2. 计算每个粒子所受的保守力F,计算摩擦力 F_friction和随机力R(t)
  3. 使用数值积分方法(如Verlet算法或其改进版本)更新粒子的速度和位置。
  4. 重复模拟循环2-3.

优点:

  1. 控温效果好:郎之万控温算法能有效地控制系统的温度,使其在期望的温度附近波动,尤其适用于需要维持稳定温度的长时间模拟。
  2. 简单易实现:该算法相对简单,容易在已有的分子动力学程序中实现。
  3. 适用于小系统:在较小的系统中,郎之万控温算法的控温效果较好,因为摩擦和随机力可以有效地与系统中较少的

缺点:

  1. 引入额外的力:摩擦力和随机力的引入可能会影响系统的动力学行为,导致结果偏离真实的物理过程。
  2. 参数选择敏感:摩擦系数 ( \gamma ) 和随机力的强度需要合理选择,否则可能导致温度波动过大或过小,影响模拟的准确性。
  3. 影响速度自相关函数:由于引入了非保守力,系统的速度自相关函数可能受到影响,从而影响运输性质(如扩散系数)的计算结果。
代码
文本
[4]
#Langevin Thermostat控温算法
# %%
from tqdm import tqdm
import numpy as np
import matplotlib.pyplot as plt


class langevin:
def __init__(self) -> None:
self.dN = 1.0
self.dt = 0.01
self.dt2 = self.dt * 0.5
self.dt4 = self.dt2 * 0.5
self.kT = 1
self.x = 0
self.v = 1
self.mass = 1.0
self.k_spring = 1
self.f = -self.k_spring * self.x
self.Ek2 = 0.0

self.temperature_coupling = 100
self.c1 = np.exp(-0.5 / self.temperature_coupling)
self.c2 = np.sqrt((1 - self.c1**2) * self.kT)
self.c2m = self.c2 * np.sqrt(1 / self.mass)

def langevin(self):
self.v = self.c1 * self.v + self.c2m * np.random.normal()

def run(self, nsteps, sample_intervals):
self.length = int(nsteps / sample_intervals)
self.x_list = np.zeros(self.length, dtype=float)
self.v_list = np.zeros(self.length, dtype=float)

for step in tqdm(range(nsteps)):
# half step
self.langevin()
self.v += self.dt2 * (self.f / self.mass)
self.x += self.dt * self.v
# another half step
self.f = -self.k_spring * self.x
self.v += self.dt2 * (self.f / self.mass)
self.langevin()

if step % sample_intervals == 0:
nn = int(step / sample_intervals)
self.x_list[nn] = self.x
self.v_list[nn] = self.v


lan = langevin()
lan.run(5000000, 10)

# %%
fig, axs = plt.subplots(1, 3)
axs[0].hist2d(lan.x_list, lan.v_list, bins=21, range=[[-4, 4], [-4, 4]], cmap="Blues")
axs[0].set_xlim(-4, 4)
axs[0].set_ylim(-4, 4)
axs[0].set_xlabel("x")
axs[0].set_ylabel("p")
axs[0].set_xticks([-4, -2, 0, 2, 4])
axs[0].set_yticks([-4, -2, 0, 2, 4])
axs[0].set_aspect(1)

position = np.linspace(-4, 4, 500)
boltz_factor = np.exp(-0.5 / lan.kT * lan.k_spring * position**2)
Z = np.trapz(boltz_factor, position)
boltz_factor /= Z
axs[1].plot(position, boltz_factor, color="k", linestyle="--")
axs[2].plot(position, boltz_factor, color="k", linestyle="--")

axs[1].hist(lan.x_list, density=True, bins=21, alpha=0.8)
axs[1].set_xlim(-4, 4)
axs[1].set_ylim(0, 0.5)
axs[1].set_box_aspect(1)
axs[1].set_xlabel("x")
axs[1].set_ylabel("probability")
axs[1].set_xticks([-4, -2, 0, 2, 4])

axs[2].hist(lan.v_list, density=True, bins=21, alpha=0.8)
axs[2].set_xlim(-4, 4)
axs[2].set_ylim(0, 0.5)
axs[2].set_box_aspect(1)
axs[2].set_xlabel("p")
axs[2].set_ylabel("probability")
axs[2].set_xticks([-4, -2, 0, 2, 4])

fig.set_size_inches(11, 3)
plt.savefig("md_lan_nh.pdf", bbox_inches="tight")
plt.show()

100%|██████████| 5000000/5000000 [00:20<00:00, 246848.95it/s]
代码
文本

Andersen Thermostat 控温算法

Andersen Thermostat通过随机选择粒子并重置其速度来模拟与热浴(热库)的相互作用。其基本思想是通过随机碰撞来控制系统的温度,使其接近设定的目标温度。

计算思路

  1. 初始化

    • 初始化粒子的速度和位置。
    • 设置模拟参数,如时间步长、目标温度、碰撞频率等。
  2. 常规分子动力学步骤

    • 按照分子动力学的常规方法,计算每个粒子所受的保守力。
    • 使用数值积分方法(如Verlet算法)更新粒子的速度和位置。
  3. 随机碰撞步骤

    • 对于每个时间步长,以概率来决定每个粒子是否与热浴发生碰撞。
    • 如果发生碰撞,重置该粒子的速度,新的速度从Maxwell-Boltzmann分布中随机采样。

优点

  1. 控温效果好:能有效地将系统温度控制在目标温度附近。
  2. 简单易实现:随机重置粒子的速度非常简单,不需要复杂的计算。
  3. 对不同系统的适用性强:适用于各种类型的分子动力学模拟。

缺点

  1. 破坏动量守恒:随机重置粒子的速度会破坏系统的动量守恒。
  2. 对动力学行为的影响:频繁的速度重置会影响系统的动力学行为,可能不适用于某些需要精确动力学行为的模拟。
代码
文本
[5]
#Andersen Thermostat 控温算法
import numpy as np
import matplotlib.pyplot as plt
from tqdm import tqdm

class AndersenThermostat:
def __init__(self, num_particles=1, temperature=1, collision_freq=0.1, time_step=0.01, k_spring=1.0, mass=1.0):
self.num_particles = num_particles
self.temperature = temperature
self.collision_freq = collision_freq
self.time_step = time_step
self.k_spring = k_spring
self.mass = mass
# 物理常量
self.k_B = 1.0 # 使用无量纲化的玻尔兹曼常数
# 初始化位置和速度
self.positions = np.zeros(num_particles)
self.velocities = np.random.randn(num_particles) * np.sqrt(self.k_B * temperature / mass)
self.forces = -self.k_spring * self.positions
def apply_thermostat(self):
for i in range(self.num_particles):
if np.random.rand() < self.collision_freq * self.time_step:
self.velocities[i] = np.random.randn() * np.sqrt(self.k_B * self.temperature / self.mass)
def run(self, nsteps, sample_intervals):
self.length = int(nsteps / sample_intervals)
self.positions_list = np.zeros((self.length, self.num_particles), dtype=float)
self.velocities_list = np.zeros((self.length, self.num_particles), dtype=float)
self.temperature_list = np.zeros(self.length, dtype=float)

for step in tqdm(range(nsteps)):
# 更新位置
self.positions += self.velocities * self.time_step
# 更新力
self.forces = -self.k_spring * self.positions
# 更新速度
self.velocities += self.forces / self.mass * self.time_step
# 应用Andersen Thermostat
self.apply_thermostat()
# 采样
if step % sample_intervals == 0:
nn = int(step / sample_intervals)
self.positions_list[nn] = self.positions
self.velocities_list[nn] = self.velocities
# 计算当前温度
kinetic_energy = 0.5 * self.mass * np.sum(self.velocities**2)
self.temperature_list[nn] = kinetic_energy / (0.5 * self.num_particles * self.k_B)

# 使用示例
andersen = AndersenThermostat(num_particles=1, temperature=1, collision_freq=0.1, time_step=0.01, k_spring=1.0, mass=1.0)
andersen.run(nsteps=500000, sample_intervals=100)

# 可视化结果
fig, axs = plt.subplots(1, 3)

# 绘制位置-速度的二维直方图
axs[0].hist2d(andersen.positions_list.flatten(), andersen.velocities_list.flatten(), bins=21, range=[[-4, 4], [-4, 4]], cmap="Blues")
axs[0].set_xlim(-4, 4)
axs[0].set_ylim(-4, 4)
axs[0].set_xlabel("x")
axs[0].set_ylabel("p")
axs[0].set_xticks([-4, -2, 0, 2, 4])
axs[0].set_yticks([-4, -2, 0, 2, 4])
axs[0].set_aspect(1)

# 计算Boltzmann因子
position = np.linspace(-4, 4, 500)
boltz_factor = np.exp(-0.5 / andersen.k_B * andersen.k_spring * position**2)
Z = np.trapz(boltz_factor, position)
boltz_factor /= Z
axs[1].plot(position, boltz_factor, color="k", linestyle="--")
axs[2].plot(position, boltz_factor, color="k", linestyle="--")

# 绘制位置的直方图
axs[1].hist(andersen.positions_list.flatten(), density=True, bins=21, alpha=0.8)
axs[1].set_xlim(-4, 4)
axs[1].set_ylim(0, 0.5)
axs[1].set_box_aspect(1)
axs[1].set_xlabel("x")
axs[1].set_ylabel("probability")
axs[1].set_xticks([-4, -2, 0, 2, 4])

# 绘制速度的直方图
axs[2].hist(andersen.velocities_list.flatten(), density=True, bins=21, alpha=0.8)
axs[2].set_xlim(-4, 4)
axs[2].set_ylim(0, 0.5)
axs[2].set_box_aspect(1)
axs[2].set_xlabel("p")
axs[2].set_ylabel("probability")
axs[2].set_xticks([-4, -2, 0, 2, 4])

fig.set_size_inches(11, 3)
plt.savefig("md_andersen.pdf", bbox_inches="tight")
plt.show()

100%|██████████| 500000/500000 [00:04<00:00, 106488.41it/s]
代码
文本

三、进行不同算法之间的对比

控温算法的性质对比: alt

书中考虑具有8000个原子的硅晶体超胞,采用Tersoff势函数描述原子间相互作用。采用GPUMD程序,测试几个控温算法获得平衡的时间。具体细节见书P135 alt

代码
文本

四、控温知识扩展

在分子动力学模拟中,控温是确保系统热力学性质合理的重要部分。除了Berendsen控温算法、Nose-Hoover控温算法、Langevin Thermostat控温算法和Andersen Thermostat控温算法,还有一些其他控温方法和相关知识点对研究人员学习和应用分子动力学模拟非常重要。以下是一些扩展的控温知识:

1. Velocity Rescaling Thermostat(速度重标定控温算法)

速度重标定控温算法通过按比例缩放系统所有粒子的速度来调整温度,使系统的动能达到目标温度。这是一种简单但有效的控温方法,特别适用于初始阶段的温度调整。

公式

其中 ( T ) 为当前温度, ( T_0 ) 为目标温度。

优点

  • 简单易实现
  • 适用于初始阶段快速调整温度

缺点

  • 不保留系统的动力学性质
  • 温度波动较大

2. Parrinello-Rahman Thermostat(Parrinello-Rahman 控温算法)

Parrinello-Rahman Thermostat 通过引入一个与系统耦合的虚拟热库来控制温度,类似于Nose-Hoover Thermostat,但该方法可以与Parrinello-Rahman Barostat一起使用,进行等温等压(NPT)系综的模拟。

优点

  • 能同时控制温度和压力
  • 适用于需要模拟真实物理条件的系统

缺点

  • 实现复杂
  • 参数选择敏感

3. Martyna-Tuckerman-Klein (MTK) Thermostat

MTK Thermostat 是对Nose-Hoover Thermostat的一种改进,通过引入多个热库变量,提高了数值稳定性。该方法特别适用于长时间的动力学模拟。

优点

  • 控温精确
  • 数值稳定性好
  • 保留系统动力学性质

缺点

  • 实现复杂
  • 参数选择敏感

4. Stochastic Velocity Rescaling (SVR) Thermostat(随机速度重标定控温算法)

SVR Thermostat 结合了速度重标定和随机噪声,通过在速度重标定过程中引入随机扰动来控制温度。这种方法能更好地模拟真实热力学性质。

公式

优点

  • 控温精确
  • 保留系统动力学性质
  • 适用于长时间模拟

缺点

  • 算法实现相对复杂

扩展知识点

  1. 控温算法的选择 不同的控温算法适用于不同的模拟需求和系统特性。研究人员应根据具体的模拟目标、系统性质和计算资源选择合适的控温算法。例如:
  • 对初始温度调节要求较高的模拟,可以选择Berendsen或速度重标定控温算法。
  • 对动力学性质要求高的长时间模拟,可以选择Nose-Hoover或Langevin Thermostat。
  • 对需要模拟真实物理条件的NPT系综模拟,可以选择Parrinello-Rahman Thermostat。
  1. 温度波动的控制 在实际模拟中,系统的温度会有一定的波动。合理的温度波动范围取决于系统大小和具体模拟的性质。过大的温度波动可能表明控温算法不稳定或参数选择不当。

  2. 热库耦合常数的选择 热库耦合常数(如Nose-Hoover和Langevin Thermostat中的参数)决定了系统与热库的交换速率。合适的耦合常数能够平衡控温效果和系统动力学性质。

  3. 长时间模拟的数值稳定性 在长时间的模拟中,数值稳定性是一个重要问题。选择合适的时间步长和控温参数能够提高模拟的数值稳定性,避免温度漂移和系统发散。

代码
文本
樊哲勇《分子动力学模拟》程序代码python实现
AI4S101
python
樊哲勇《分子动力学模拟》程序代码python实现AI4S101python
点个赞吧
推荐阅读
公开
樊哲勇《分子动力学模拟》python实例 | 1.一个简单的分子动力学模拟程序
樊哲勇《分子动力学模拟》程序代码python实现AI4S101
樊哲勇《分子动力学模拟》程序代码python实现AI4S101
yuxiangc22
更新于 2024-06-10
1 赞1 转存文件
公开
樊哲勇《分子动力学模拟》python实例 | 3.Tersoff 势的编程实现
樊哲勇《分子动力学模拟》程序代码python实现AI4S101
樊哲勇《分子动力学模拟》程序代码python实现AI4S101
yuxiangc22
更新于 2024-06-26
1 转存文件