技术背景

在前面的两篇博客中,我们分别介绍了Ewald算法求解静电势能基于格点拉格朗日插值法的PME算法。在多种计算优化算法(Ewald求和、快速傅里叶变换、格点拉格朗日插值、截断近似)的加持下,使得我们不需要在实空间进行大量的迭代,也可以得到一个近似收敛的静电势能结果。相关的PME计算公式为:

\[\begin{align*}
E&=E^S+E^L-E^{self}\\
&=\sum_{i,j\in \{Neigh\}}\frac{q_iq_j}{4\pi\epsilon_0|\mathbf{r}_j-\mathbf{r}_i|}Erfc\left(\frac{|\mathbf{r}_j-\mathbf{r}_i|}{\sqrt{2}\sigma}\right)\\
&+\frac{V}{2k_xk_yk_z\epsilon_0}\sum_{|\mathbf{k}|>0}\frac{e^{-\frac{\sigma^2 k^2}{2}}}{k^2}|F_{\mathbf{k}}(Q)(m_x,m_y,m_z)|^2\\
&-\frac{1}{4\pi\epsilon_0}\frac{1}{\sqrt{2\pi}\sigma}\sum_{i=0}^{N-1}q_i^2
\end{align*}
\]

以下做一个Python版本的简单测试。

测试思路

为了对比PME算法的收敛性与实空间迭代的收敛性,我们先取一个一维的简单周期性点电荷体系,一方面通过对实空间盒子进行扩张,以得到一个收敛的趋势。另一方面通过PME算法直接截断计算静电势。然后对比两者的结果,按预期来说,PME的结果应该在大量的实空间迭代之后被近似到,也就是\(V_{PME}=V_{real}(N)\)。当然,因为不同的插值算法也有可能也会导致计算结果的差异性,所以这里使用了两种插值阶数来进行测试。

代码示例

import numpy as np
from scipy.special import erfc
from tqdm import trange
import matplotlib.pyplot as plt
np.random.seed(4) num_charges=1000
crd = np.random.random(num_charges) * 10
q = np.random.random(num_charges)
q -= np.sum(q) / q.shape[0]
pbc_box = np.array([10.], np.float64) def energy(crd, q, pbc_box, levels=0, epsilon=1):
qij = np.einsum('i,j->ij', q, q)
if levels == 0:
dis = np.abs(crd[:, None] - crd[None])
energy = np.triu(qij / (dis+1e-08) / 4 / np.pi / epsilon, k=1).sum()
else:
# left box
crd1 = crd - levels * pbc_box
dis = np.abs(crd[:, None] - crd1[None])
energy = np.triu(qij / (dis+1e-08) / 4 / np.pi / epsilon, k=0).sum()
# right box
crd2 = crd + levels * pbc_box
dis = np.abs(crd[:, None] - crd2[None])
energy += np.triu(qij / (dis+1e-08) / 4 / np.pi / epsilon, k=0).sum()
return energy def pme4(crd, q, pbc_box, epsilon=1):
sigma = (pbc_box[0] ** 2 / crd.shape[0]) ** (1/6) / np.sqrt(2*np.pi)
qij = np.einsum('i,j->ij', q, q)
dis = np.abs(crd[:, None] - crd[None])
dis = np.where(dis<pbc_box-dis, dis, pbc_box-dis)
coe = erfc(dis / np.sqrt(2) / sigma)
real_energy = np.sum(coe * np.triu(qij / (dis+1e-08) / 4 / np.pi / epsilon, k=1))
self_energy = np.sum(q ** 2) / np.sqrt(2 * np.pi) / sigma / 4 / np.pi / epsilon
Q = np.zeros(10, dtype=np.float64)
for idx in range(crd.shape[0]):
x_floor = np.floor(crd[idx])
x_shift = np.array([-1.5, -0.5, 0.5, 1.5], np.float32)
x_idx = (np.floor(x_floor + x_shift) % 10).astype(np.int32)
x = x_shift
Q[x_idx[0]] += q[idx]*(-8*x[0]**3+12*x[0]**2+2*x[0]-3)/48
Q[x_idx[1]] += q[idx]*(8*x[1]**3-4*x[1]**2-18*x[1]+9)/16
Q[x_idx[2]] += q[idx]*(-8*x[2]**3-4*x[2]**2+18*x[2]+9)/16
Q[x_idx[3]] += q[idx]*(8*x[3]**3+12*x[3]**2-2*x[3]-3)/48
Q_ifft = np.fft.ifft(Q)
sk = np.abs(Q_ifft) ** 2 * Q.shape[0]
k = np.arange(Q.shape[0]) * 2 * np.pi / Q.shape[0]
res_energy = np.sum(np.exp(-0.5*sigma**2*k[1:]**2)*sk[1:]/k[1:]**2)/2/epsilon/(2*np.pi/pbc_box[0])
return real_energy - self_energy + res_energy def pme6(crd, q, pbc_box, epsilon=1):
sigma = (pbc_box[0] ** 2 / crd.shape[0]) ** (1/6) / np.sqrt(2*np.pi)
qij = np.einsum('i,j->ij', q, q)
dis = np.abs(crd[:, None] - crd[None])
dis = np.where(dis<pbc_box-dis, dis, pbc_box-dis)
coe = erfc(dis / np.sqrt(2) / sigma)
real_energy = np.sum(coe * np.triu(qij / (dis+1e-08) / 4 / np.pi / epsilon, k=1))
self_energy = np.sum(q ** 2) / np.sqrt(2 * np.pi) / sigma / 4 / np.pi / epsilon
Q = np.zeros(10, dtype=np.float64)
for idx in range(crd.shape[0]):
x_floor = np.floor(crd[idx])
x_shift = np.array([-2.5, -1.5, -0.5, 0.5, 1.5, 2.5], np.float32)
x_idx = (np.floor(x_floor + x_shift) % 10).astype(np.int32)
x = x_shift
Q[x_idx[0]] += -q[idx]*(x[0]**5-2.5*x[0]**4-1.5*x[0]**3+3.75*x[0]**2+0.3125*x[0]-0.78125)/120
Q[x_idx[1]] += q[idx]*(x[1]**5-1.5*x[1]**4-6.5*x[1]**3+9.75*x[1]**2+1.5625*x[1]-2.34375)/24
Q[x_idx[2]] += -q[idx]*(x[2]**5-0.5*x[2]**4-8.5*x[2]**3+4.25*x[2]**2+14.0625*x[2]-7.03125)/12
Q[x_idx[3]] += q[idx]*(x[2]**5+0.5*x[2]**4-8.5*x[2]**3-4.25*x[2]**2+14.0625*x[2]+7.03125)/12
Q[x_idx[4]] += -q[idx]*(x[1]**5+1.5*x[1]**4-6.5*x[1]**3-9.75*x[1]**2+1.5625*x[1]+2.34375)/24
Q[x_idx[5]] += q[idx]*(x[0]**5+2.5*x[0]**4-1.5*x[0]**3-3.75*x[0]**2+0.3125*x[0]+0.78125)/120
Q_ifft = np.fft.ifft(Q)
sk = np.abs(Q_ifft) ** 2 * Q.shape[0]
k = np.arange(Q.shape[0]) * 2 * np.pi / Q.shape[0]
res_energy = np.sum(np.exp(-0.5*sigma**2*k[1:]**2)*sk[1:]/k[1:]**2)/2/epsilon/(2*np.pi/pbc_box[0])
return real_energy - self_energy + res_energy N = 100000
e = np.zeros(N)
for i in trange(N):
e[i] = energy(crd, q, pbc_box, levels=i)
e = np.cumsum(e)
print (e[0], e[-1]) e2 = pme4(crd, q, pbc_box)
print (e2) e3 = pme6(crd, q, pbc_box)
print (e3) x = list(range(N))
plt.figure()
plt.xlabel('Box Layers')
plt.ylabel("Energy")
plt.plot(x, e, label='Normal')
plt.plot(x, np.ones_like(x) * e2, label='PME4')
plt.plot(x, np.ones_like(x) * e3, label='PME6')
plt.legend()
plt.savefig('energy.png')

运行输出为:

-6016.973545020364 -6008.267263384039
-6010.335037181866
-6009.780676419067

这个输出结果表示,不加任何额外的Box时,计算得到的电势能为-6016,在左右各加了10万个Box之后,得到的静电势能结果变为-6008。而PME计算使用4阶拉格朗日插值时一步就可以得到-6010,如果使用6阶的插值,一步就可以得到-6009。总体的不同Box Level下的静电势计算结果对比为:

这个结果表示,如果我们使用6阶插值的PME算法,单步的计算就可以得到实空间迭代10000个Box的近似结果。

总结概要

基于前面几篇博客关于PME算法的理论推导,本文给出了一个简单版本的Python代码实现,并且对比了PME算法相比于实空间迭代算法的优越性。从结果上来看,一维的静电势能计算中,PME单步得到的计算结果非常接近于实空间迭代1万个Box的近似结果。

版权声明

本文首发链接为:https://www.cnblogs.com/dechinphy/p/pme-python.html

作者ID:DechinPhy

更多原著文章:https://www.cnblogs.com/dechinphy/

请博主喝咖啡:https://www.cnblogs.com/dechinphy/gallery/image/379634.html

PME算法简单Python实现的更多相关文章

  1. 机器学习算法与Python实践之(四)支持向量机(SVM)实现

    机器学习算法与Python实践之(四)支持向量机(SVM)实现 机器学习算法与Python实践之(四)支持向量机(SVM)实现 zouxy09@qq.com http://blog.csdn.net/ ...

  2. 机器学习算法与Python实践之(三)支持向量机(SVM)进阶

    机器学习算法与Python实践之(三)支持向量机(SVM)进阶 机器学习算法与Python实践之(三)支持向量机(SVM)进阶 zouxy09@qq.com http://blog.csdn.net/ ...

  3. 机器学习算法与Python实践之(二)支持向量机(SVM)初级

    机器学习算法与Python实践之(二)支持向量机(SVM)初级 机器学习算法与Python实践之(二)支持向量机(SVM)初级 zouxy09@qq.com http://blog.csdn.net/ ...

  4. 常用排序算法的python实现和性能分析

    常用排序算法的python实现和性能分析 一年一度的换工作高峰又到了,HR大概每天都塞几份简历过来,基本上一天安排两个面试的话,当天就只能加班干活了.趁着面试别人的机会,自己也把一些基础算法和一些面试 ...

  5. 分类算法——k最近邻算法(Python实现)(文末附工程源代码)

    kNN算法原理 k最近邻(k-Nearest Neighbor)算法是比较简单的机器学习算法.它采用测量不同特征值之间的距离方法进行分类,思想很简单:如果一个样本在特征空间中的k个最近邻(最相似)的样 ...

  6. 机器学习算法与Python实践之(五)k均值聚类(k-means)

    机器学习算法与Python实践这个系列主要是参考<机器学习实战>这本书.因为自己想学习Python,然后也想对一些机器学习算法加深下了解,所以就想通过Python来实现几个比较常用的机器学 ...

  7. 对《禁忌搜索(Tabu Search)算法及python实现》的修改

    这个算法是在听北大人工智能mooc的时候,老师讲的一种局部搜索算法,可是举得例子不太明白.搜索网页后,发现<禁忌搜索(Tabu Search)算法及python实现>(https://bl ...

  8. DES的加密与解密算法(Python实现)

    DES的加密与解密算法(Python实现) 密码学实验:实现了DES的简单的加密和解密算法,DES算法的相关资料网上很多,这里不再赘述,仅仅贴出源代码给大家分享,源码中包含很多汉字注释,相信大家都是可 ...

  9. 机器学习算法与Python实践之(七)逻辑回归(Logistic Regression)

    http://blog.csdn.net/zouxy09/article/details/20319673 机器学习算法与Python实践之(七)逻辑回归(Logistic Regression) z ...

  10. 字符串匹配算法之 kmp算法 (python版)

    字符串匹配算法之 kmp算法 (python版) 1.什么是KMP算法 KMP是三位大牛:D.E.Knuth.J.H.MorriT和V.R.Pratt同时发现的.其中第一位就是<计算机程序设计艺 ...

随机推荐

  1. VideoGeneration

    Stable Video Diffusion: Scaling Latent Video Diffusion Models to Large Datasets 主要贡献:设计了一套数据清洗策略来清洗大 ...

  2. Linux下如何在程序中获取某个命令执行的结果?【附源码】

    在工作中遇到一个问题,就是想获取某个函数执行之后打印的字符串信息. 这个功能应用场景挺多的, 特地整理了一下相关知识点分享给大家. 1. 使用临时文件 1) 使用shell的重定向 将命令输出重定向到 ...

  3. JDK有用的新特性-Java Record

    目录 Java Record Record使用 Instance Methods 静态方法 Static Method Record 的构造方法 step1: 紧凑和定制构造方法 Record 与 与 ...

  4. 使用.NET源生成器(SG)生成项目的版本号信息

    之前写过一篇 源生成器生成自动注入的代码 主要是通过SyntaxProvider查找标注特性实现 其实除了SyntaxProvider之外还有几个很重要的Provider,比如:MetadataRef ...

  5. ROS 知识

    安装 Ref: ROS安装过程中如何解决 rosdep update 命令出现错误 https://jiayaoo3o.github.io/2020/06/23/%E8%AE%B0%E5%BD%95% ...

  6. 日志与追踪的完美融合:OpenTelemetry MDC 实践指南

    前言 在前面两篇实战文章中: OpenTelemetry 实战:从零实现分布式链路追踪 OpenTelemetry 实战:从零实现应用指标监控 覆盖了可观测中的指标追踪和 metrics 监控,下面理 ...

  7. [JS设计模式]:鸭子类型与多态

    鸭子类型 编程语言按照数据类型大体可以分为两类,一类是静态类型语言,另一类是动态类型语言. 动态类型语言对变量类型的宽容给实际编码带来了很大的灵活性.由于无需进行类型检测,我们可以尝试调用任何对象的任 ...

  8. MoCov1: 无监督视觉表征学习的动量对比《Momentum Contrast for Unsupervised Visual Representation Learning》(MoCo、动量对比、动态字典、队列维护、对比损失InfoNCE)

    现在是2024年6月11日,21:49,刚找好要看的论文,师兄推荐的. 先占个坑,明天看,我累了(我没脑子了). 现在是6月12日,15:49,干正事了(又被别人影响了情绪,这不好,希望你改掉,好的, ...

  9. ArgoWorkflow教程(四)---Workflow & 日志归档

    上一篇我们分析了argo-workflow 中的 artifact,包括 artifact-repository 配置以及 Workflow 中如何使用 artifact.本篇主要分析流水线 GC 以 ...

  10. Angular Material 18+ 高级教程 – Custom Themes for Material Design 2 (自定义主题 Material 2)

    v18 更新重要说明 从 Angular Material v18 开始,默认使用的是 Material 3 Design (简称 M3),本篇教的是旧版本的 Material 2 Design (简 ...