注解
此笔记本可在此处下载: Molecular_Dynamics.ipynb
%load_ext autoreload
%autoreload 2
from IPython.display import Image
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from scipy import integrate, optimize, spatial
from matplotlib import animation, rc
import sympy as sp
import pandas as pd
from PMD import PMD, distances
sp.init_printing(use_latex = "mathjax")
rc('animation', html='html5')
%matplotlib nbagg
分子动力学
利用莫尔斯势进行原子模拟
https://en.wikipedia.org/wiki/Morse_potential
Image(url= "https://upload.wikimedia.org/wikipedia/commons/7/7a/Morse-potential.png", width=500, height=500)

PMD模块
这里提供PMD模块: PMD.py
潜力
De, a, re, r = sp.symbols("D_e a r_e r")
V = De * (1- sp.exp(-a * (r-re)))**2
V
\[D E \左(1-E ^-A \左(R-R E \右)\右)^ 2\]
力
F = -V.diff(r)
F
\[-2 D E A \左(1-E ^-A \左(R-R E \右)\右)E ^-A \左(R-R E \右)\]
作图
values = {De:1., a:2., re:1}
Vf = sp.lambdify(r, V.subs(values), "numpy")
Ff = sp.lambdify(r, F.subs(values), "numpy")
vr = np.linspace(.3 * values[re], 5 * values[re], 100)
fig = plt.figure()
ax = fig.add_subplot(2,1,1)
plt.plot(vr, Vf(vr))
plt.grid()
plt.ylabel("Potential Value, $V$")
ax = fig.add_subplot(2,1,2)
plt.plot(vr, Ff(vr))
plt.grid()
plt.xlabel("Interatomic Distance, $r$")
plt.ylabel("Force Value, $F$")
plt.show()
<IPython.core.display.Javascript object>
class MD(PMD):
"""
Molecular dynamics w. Morse potential.
"""
def __init__(self, De = 1., a = 1., re = 1., mu = 0., **kwargs):
self.De = De
self.a = a
self.re = re
self.mu = mu
super().__init__(**kwargs)
def derivative(self, X, t, cutoff_radius = 1.e-2):
De, a, re, mu = self.De, self.a, self.re, self.mu
n = len(m)
P = X[:2 * n ].reshape(n ,2)
V = X[ 2 * n:].reshape(n ,2)
M = m * m[:, np.newaxis]
D, R, U = distances(P)
np.fill_diagonal(R, np.inf)
if cutoff_radius > 0.: R = np.where(R > cutoff_radius, R, cutoff_radius)
#F =((G * M * R**-2)[:,:,np.newaxis] * U).sum(axis = 0)
F =((2. * De * a * ( 1. - np.exp(-a * (R - re)) ) *
np.exp(- a * (R - re)))[:,:,np.newaxis] * U).sum(axis = 0) - mu * (V**2).sum(axis=0)**1.5 * V
A = (F.T /m).T
X2 = X.copy()
X2[:2*n ] = V.flatten()
X2[ 2*n:] = A.flatten()
return X2
def potential(self, P):
De, a, re, mu = self.De, self.a, self.re, self.mu
D, R, U = distances(P)
return np.where(R != 0.,
De * a * ( 1 - np.exp(-a * (R - re)))**2,
0.).sum() / 2.
re = .5
nmx = 10
nmy = 10
nm = nmx * nmy
x0 = np.arange(nmx) * re * 1.2
y0 = np.arange(nmy) * re * 1.2
X0, Y0 = np.meshgrid(x0, y0)
P0 = np.array([X0.flatten(), Y0.flatten()]).T
P0 *= 1. + np.random.rand(*P0.shape) *.1
P0 -= P0.mean(axis = 0)
V0 = np.zeros_like(P0)
pcolors = "r"
tcolors = "b"
m = np.ones(nm)*1.e0
s = MD(m = m, P = P0, V = V0, mu = .05, re = re, a = 10, De = .5, nk = 1000)
dt = 1.e-1
nt = 100
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.set_aspect("equal")
margin = 1.
plt.xlim(P0[:,0].min() - margin, P0[:,0].max() + margin)
plt.ylim(P0[:,1].min() - margin, P0[:,1].max() + margin)
plt.grid()
#ax.axis("off")
points = []
msize = 10. * (s.m / s.m.max())**(1./ 6.)
for i in range(nm):
plc = len(pcolors)
pc = pcolors[i%plc]
tlc = len(tcolors)
tc = tcolors[i%tlc]
trail, = ax.plot([], [], "-"+tc)
point, = ax.plot([], [], "o"+pc, markersize = msize[i])
points.append(point)
points.append(trail)
def init():
for i in range(2 * nm):
points[i].set_data([], [])
return points
def animate(i):
s.solve(dt, nt)#, rtol = 1.e-8, atol = 1.e-8)
x, y = s.xy()
for i in range(nm):
points[2*i].set_data(x[i:i+1], y[i:i+1])
xt, yt = s.trail(i)
points[2*i+1].set_data(xt, yt)
return points
anim = animation.FuncAnimation(fig, animate, init_func=init, frames=400, interval=20, blit=True)
#plt.show()
plt.close()
anim
<IPython.core.display.Javascript object>
微观结构分析
P = s.positions
nodes = pd.DataFrame(P, columns = {"X", "Y"})
nodes.index.name = "Atom"
nodes.head()
Y | X | |
---|---|---|
Atom | ||
0 | -1.548040 | -2.484607 |
1 | -1.076637 | -2.350997 |
2 | -0.756620 | -2.726322 |
3 | -0.599794 | -2.253769 |
4 | -0.100450 | -2.163847 |
tri = spatial.Delaunay(P)
tri.simplices
elements = pd.DataFrame(tri.simplices.copy())
plt.figure()
ax = fig.add_subplot(1,1,1)
ax.set_aspect("equal")
plt.triplot(P[:,0], P[:,1], tri.simplices.copy())
plt.plot(P[:,0], P[:,1], 'o')
plt.show()
<IPython.core.display.Javascript object>