├── README.md ├── configura ├── MD_LJP.ipynb ├── MD_LJP.py └── Rap_2_LJP.in └── exmple_in_jupyter notebook ├── .ipynb_checkpoints └── MD_LJP-checkpoint.ipynb ├── MD_LJP.ipynb ├── Rap_2_LJP.in ├── coo └── coordinates.mp4 └── plot.jpg /README.md: -------------------------------------------------------------------------------- 1 | # MD_LJP 2 | An elementary MD simulation program written in python 3 | -------------------------------------------------------------------------------- /configura/MD_LJP.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "id": "aea0a6c1", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "# 代码1:..........................................................................................\n", 11 | "import pandas as pd\n", 12 | "import math\n", 13 | "import os\n", 14 | "import matplotlib.pyplot as plt\n", 15 | "plt.style.use('seaborn-whitegrid')\n", 16 | "import numpy as np\n", 17 | "from PIL import Image\n", 18 | "import glob\n", 19 | "import moviepy.editor as mp\n", 20 | "from datetime import datetime\n", 21 | "import time\n", 22 | "import os.path\n", 23 | "from os import path\n", 24 | "import shutil\n", 25 | "from IPython.display import display\n", 26 | " \n", 27 | "\n", 28 | "# 代码2:..........................................................................................\n", 29 | "class Mol():\n", 30 | " def __init__(self,r,rv,ra):\n", 31 | " \"\"\"\n", 32 | " 每一分子对象(mol)所具有的属性如下:\n", 33 | " r:原子坐标\n", 34 | " rv:原子速度\n", 35 | " ra:原子加速度向量\n", 36 | " \"\"\"\n", 37 | " #初始化以上属性的值\n", 38 | " self.r=np.asarray([0.0,0.0])\n", 39 | " self.rv=np.asarray([0.0,0.0])\n", 40 | " self.ra=np.asarray([0.0,0.0])\n", 41 | " \n", 42 | "# 体系属性类,主要用来求体系属性(测定量)的平均值和标准差 \n", 43 | "class Prop():\n", 44 | " def __init__(self, val, sum1, sum2 ):\n", 45 | " self.val=val #体系测定量的值\n", 46 | " self.sum1=sum1 #体系测定量的值的和\n", 47 | " self.sum2=sum2 #体系测定量的值的平方和\n", 48 | "\n", 49 | " \n", 50 | "# 代码3:..........................................................................................\n", 51 | "def Sqr(x):\n", 52 | " return (x * x)\n", 53 | "\n", 54 | "def Cube(x):\n", 55 | " return ((x) * (x) * (x))\n", 56 | "\n", 57 | "# 用于生成 (0,1) 范围内的均匀分布的随机数,见18.4\n", 58 | "def RandR():\n", 59 | " global randSeedP\n", 60 | " randSeedP=(randSeedP * IMUL + IADD) & MASK\n", 61 | " return (randSeedP*SCALE)\n", 62 | "\n", 63 | "# 用于在二维空间产生具有均匀分布的随机方向的单位向量\n", 64 | "def VRand(p):\n", 65 | " s: float\n", 66 | " s = 2. * math.pi * RandR()\n", 67 | " p[0] = math.cos(s)\n", 68 | " p[1] = math.sin(s)\n", 69 | " return p\n", 70 | "\n", 71 | "# 周期性边界(PBC)算法:\n", 72 | "# PBC算法第一部分:对体系内粒子坐标的约束\n", 73 | "def VWrapAll(v):\n", 74 | " #对元胞x方向的坐标约束\n", 75 | " if v[0]>=0.5*region[0]: \n", 76 | " v[0]-=region[0]\n", 77 | " elif v[0]<-0.5*region[0]:\n", 78 | " v[0] +=region[0]\n", 79 | " \n", 80 | " #对元胞y方向的坐标约束\n", 81 | " if v[1] >= 0.5 * region[1]:\n", 82 | " v[1] -= region[1]\n", 83 | " elif v[1] < -0.5 * region[1]:\n", 84 | " v[1] += region[1]\n", 85 | " \n", 86 | " \n", 87 | "# 代码5:.......................................................................................... \n", 88 | "def SetParams():\n", 89 | " global rCut #截断距离\n", 90 | " global region #区域\n", 91 | " global velMag #速度幅度\n", 92 | " \n", 93 | " #截断值为势阱底部时的原子间距离,即rmin=rCut=2^1/6 *sigma\n", 94 | " rCut=math.pow(2.,1./6. * sigma)\n", 95 | " region=np.multiply(1./math.sqrt(density),initUcell) \n", 96 | " nMol=len(mol)\n", 97 | " \n", 98 | " #速度的变化幅度取决于温度的高低\n", 99 | " velMag = math.sqrt(NDIM * (1. -1. /nMol) * temperature)\n", 100 | " \n", 101 | " \n", 102 | "# 代码7:..........................................................................................\n", 103 | "def InitCoords():\n", 104 | " c=np.asarray([0.0,0.0]) #初始坐标值\n", 105 | " gap=np.divide(region,initUcell) #单个粒子所在元胞的大小\n", 106 | " n=0 #给粒子计数\n", 107 | " \n", 108 | " #将400个原子分别放到元胞中(这些元胞向x,y方向扩胞成了region区域)\n", 109 | " for ny in range(0, int(initUcell[1])):\n", 110 | " for nx in range(0, int(initUcell[0])):\n", 111 | " c = np.asarray([nx+0.5, ny+0.5])\n", 112 | " c = np.multiply(c, gap)\n", 113 | " c = np.add(c, np.multiply(-0.5, region))\n", 114 | " mol[n].r = c\n", 115 | " n=n+1\n", 116 | " \n", 117 | " \n", 118 | "def InitVels():\n", 119 | " global vSum\n", 120 | " vSum=np.zeros(vSum.shape) #返回特定大小,以0填充新的数组:[0,0],这里是形状\n", 121 | " \n", 122 | " for n in range(nMol):\n", 123 | " VRand(mol[n].rv) #产生随机随机速度向量[x,y]\n", 124 | " mol[n].rv=np.multiply(mol[n].rv,velMag) #根据温度,生成新的速度\n", 125 | " vSum=np.add(vSum,mol[n].rv) #质心的速度,系统总速度各质点速度的总和\n", 126 | " \n", 127 | " #调整度方向,以确保质心是静止的,这里取400个粒子在,x,y方向的平均速度1/400*Vsum+每一个原子的速度\n", 128 | " for n in range (nMol):\n", 129 | " mol[n].rv=np.add(mol[n].rv,np.multiply((- 1.0 / nMol),vSum))\n", 130 | " \n", 131 | " \n", 132 | "def InitAccels():\n", 133 | " for n in range(nMol):\n", 134 | " mol[n].ra=np.zeros(mol[n].ra.shape)\n", 135 | " \n", 136 | "\n", 137 | "# 代码8:..........................................................................................\n", 138 | "def PropZero(v):\n", 139 | " v.sum1 = v.sum2 = 0.\n", 140 | " return v \n", 141 | " \n", 142 | "def PropAccum(v):\n", 143 | " v.sum1 += v.val\n", 144 | " v.sum2 += Sqr(v.val)\n", 145 | " return v \n", 146 | "\n", 147 | "def PropAvg(v, n):\n", 148 | " v.sum1 /= n\n", 149 | " v.sum2 = math.sqrt(max(v.sum2 / n - Sqr(v.sum1), 0.)) \n", 150 | " return v \n", 151 | "\n", 152 | "\n", 153 | "def AccumProps(icode):\n", 154 | " \n", 155 | " if icode == 0: # 0:初始化 \n", 156 | " PropZero(totEnergy)\n", 157 | " PropZero(kinEnergy)\n", 158 | " PropZero(pressure) \n", 159 | " if icode == 1: # 1:求和 \n", 160 | " PropAccum(totEnergy)\n", 161 | " PropAccum(kinEnergy)\n", 162 | " PropAccum(pressure) \n", 163 | " if icode == 2: # 2:求平均值和标准差\n", 164 | " PropAvg(totEnergy, stepAvg)\n", 165 | " PropAvg(kinEnergy, stepAvg)\n", 166 | " PropAvg(pressure, stepAvg) \n", 167 | " \n", 168 | " \n", 169 | "# 代码6:..........................................................................................\n", 170 | "def SetupJob(): \n", 171 | " global stepCount #步长计数\n", 172 | " \n", 173 | " stepCount = 0 #初始化步长计数变量的值\n", 174 | " InitCoords() #初始化坐标\n", 175 | " InitVels() #初始化速度\n", 176 | " InitAccels() #初始化加速度\n", 177 | " AccumProps(0) #初始化系统属性值(总能量,动能,压强)\n", 178 | " \n", 179 | "\n", 180 | "# 代码10:.........................................................................................\n", 181 | "def LeapfrogStep(part):\n", 182 | " if part == 1:\n", 183 | " for n in range (nMol):\n", 184 | " mol[n].rv=np.add(mol[n].rv,np.multiply(0.5 * deltaT,mol[n].ra))\n", 185 | " mol[n].r=np.add(mol[n].r,np.multiply(deltaT,mol[n].rv))\n", 186 | " else :\n", 187 | " for n in range(nMol):\n", 188 | " mol[n].rv=np.add(mol[n].rv,np.multiply(0.5 * deltaT,mol[n].ra))\n", 189 | "\n", 190 | " \n", 191 | "# 代码11:...................................................................................\n", 192 | "def ApplyBoundaryCond():\n", 193 | " for n in range(nMol):\n", 194 | " VWrapAll(mol[n].r)\n", 195 | " \n", 196 | "# 代码12:...................................................................................\n", 197 | "def ComputeForces():\n", 198 | " global virSum #用于计算压强的中间变量(fij*rij)和\n", 199 | " global uSum #LJ势能和\n", 200 | " fcVal=0 # 原子j对原子i施加的力\n", 201 | " rrCut=Sqr(rCut) # rCut:Rc,截断半径的平方\n", 202 | " \n", 203 | " #初始化分子加速度\n", 204 | " for n in range (nMol):\n", 205 | " mol[n].ra=np.zeros(mol[n].ra.shape)\n", 206 | " \n", 207 | " uSum=0. #初始化LJ势能和值\n", 208 | " virSum=0.\n", 209 | " n=0\n", 210 | " for j1 in range(nMol-1):\n", 211 | " for j2 in range(j1+1,nMol):\n", 212 | " \n", 213 | " # 使Delta Rij。(RJ1-RJ2的平方之和)\n", 214 | " dr=np.subtract(mol[j1].r,mol[j2].r) # dr包含Rj1和Rj2之间的x,y坐标差值\n", 215 | " VWrapAll(dr) #应用PBC约束原子在元胞内,更新了dr[0],dr[1]\n", 216 | " rr=(dr[0] * dr[0] + dr[1] * dr[1]) #两原子距离的平方,这里并未求两原子间距离的绝对值,没必要,因为与截断半径只是比大小,省去了平方根的计算\n", 217 | " r=np.sqrt(rr) #r两为原子间的距离 \n", 218 | " \n", 219 | " # 这里是使用原子距离的平方来 dr2 < Rc^2 来判断两原子键相互作用力,\n", 220 | " if(rr < rrCut):\n", 221 | " fcVal = 48 * epsilon * np.power(sigma, 12) / np.power(r, 13) - 24 * epsilon * np.power(sigma, 6) / np.power(r, 7)\n", 222 | " \n", 223 | " # 更新加速度\n", 224 | " mol[j1].ra = np.add(mol[j1].ra, np.multiply(fcVal, dr))\n", 225 | " mol[j2].ra = np.add(mol[j2].ra, np.multiply(-fcVal, dr))\n", 226 | " \n", 227 | " #LJ势能计算\n", 228 | " uSum += 4 * epsilon * np.power(sigma/r, 12)/r - np.power(sigma/r, 6) \n", 229 | " virSum += fcVal * rr\n", 230 | " \n", 231 | "# 代码13:...................................................................................\n", 232 | "def EvalProps():\n", 233 | " global vSum\n", 234 | " vvSum = 0. #系统速度平方的总和\n", 235 | " vSum = np.zeros(vSum.shape) #质心速度,为系统速度=各质点速度总和,初始化为[0,0]\n", 236 | " \n", 237 | " global kinEnergy #动能\n", 238 | " global totEenergy #总能量\n", 239 | " global pressure #压强\n", 240 | " \n", 241 | " #求得质心速度\n", 242 | " for n in range(nMol):\n", 243 | " vSum =np.add(vSum,mol[n].rv) \n", 244 | " vv = (mol[n].rv[0] * mol[n].rv[0] + mol[n].rv[1] * mol[n].rv[1]) #xv^2+yv^2\n", 245 | " vvSum += vv\n", 246 | " \n", 247 | " # 在二维分子体系中,热力学属性值的数值计算方法\n", 248 | " kinEnergy.val = (0.5 * vvSum) / nMol #单个原子动能,nMol代表原子数\n", 249 | " totEnergy.val = kinEnergy.val + (uSum / nMol) #总能量:单个原子的动能+单个原子的势能\n", 250 | " pressure.val = density * (vvSum + virSum) / (nMol * NDIM) #体系压强\n", 251 | " \n", 252 | "\n", 253 | "# 代码14:...................................................................................\n", 254 | "def PrintSummary():\n", 255 | "\n", 256 | " print(stepCount, \\\n", 257 | " \"{0:.4f}\".format(timeNow), \\\n", 258 | " \"{0:.4f}\".format(vSum[0] / nMol) ,\\\n", 259 | " \"{0:.4f}\".format(totEnergy.sum1),\\\n", 260 | " \"{0:.4f}\".format(totEnergy.sum2), \\\n", 261 | " \"{0:.4f}\".format(kinEnergy.sum1), \\\n", 262 | " \"{0:.4f}\".format(kinEnergy.sum2),\\\n", 263 | " \"{0:.4f}\".format(pressure.sum1),\\\n", 264 | " \"{0:.4f}\".format(pressure.sum2))\n", 265 | " \n", 266 | " return (stepCount, \\\n", 267 | " timeNow, \\\n", 268 | " (vSum[0] / nMol) ,\\\n", 269 | " totEnergy.sum1,\\\n", 270 | " totEnergy.sum2, \\\n", 271 | " kinEnergy.sum1, \\\n", 272 | " kinEnergy.sum2,\\\n", 273 | " pressure.sum1,\\\n", 274 | " pressure.sum2) \n", 275 | "\n", 276 | "# 代码9:------------------------------------------------------------------------------------------\n", 277 | "def SingleStep():\n", 278 | " \n", 279 | " global stepCount # 步长计数\n", 280 | " global timeNow # 模拟运行时间\n", 281 | "\n", 282 | " stepCount +=1 \n", 283 | " timeNow = stepCount * deltaT #模拟运行的时间=步数x步长\n", 284 | " LeapfrogStep(1) #求解运动方程积分\n", 285 | " ApplyBoundaryCond() #应用周期性边界条件\n", 286 | " ComputeForces() # 计算原间相互作用力\n", 287 | " LeapfrogStep(2) # 坐标和速度的积分\n", 288 | " EvalProps() #计算系统属性值(速度,,速度平方和,总能量,动能,压力)\n", 289 | " AccumProps(1) #系统属性值求和\n", 290 | " \n", 291 | " #每一百步统计系统的属性值(0,100,200,300,400,500),可以设置stepAvg的值进行自定义\n", 292 | " if (stepCount % stepAvg == 0):\n", 293 | " AccumProps(2) #求系统的属性值的平均值和标准差\n", 294 | " systemParams.append(PrintSummary()) #将结果加入到 systemParams列表中\n", 295 | " AccumProps(0) # 重置系统属性值用来下一次的统计\n", 296 | " \n", 297 | "\n", 298 | "# 代码15:...................................................................................\n", 299 | "def plotMolCoo(mol,workdir,n):\n", 300 | " import matplotlib.patches as mpatches\n", 301 | " import matplotlib.pyplot as plt\n", 302 | " \n", 303 | " Time=timeNow #模拟时长\n", 304 | " Sigma_v = \"{0:.4f}\".format(vSum[0] / nMol)\n", 305 | " E = \"{0:.4f}\".format(totEnergy.sum1)\n", 306 | " Sigma_E = \"{0:.4f}\".format(totEnergy.sum2)\n", 307 | " Ek = \"{0:.4f}\".format(kinEnergy.sum1)\n", 308 | " Sigma_Ek = \"{0:.4f}\".format(kinEnergy.sum2)\n", 309 | " P_1 = \"{0:.4f}\".format(pressure.sum1)\n", 310 | " P_2 = \"{0:.4f}\".format(pressure.sum2) \n", 311 | " \n", 312 | " %matplotlib inline \n", 313 | " TileName = (workdir+'coo/'+str(n)+'.png') #传入的n表示n步,这里用来给生成的图像命名\n", 314 | " x = [] #新建列表保存粒子x的坐标\n", 315 | " y = [] #新建列表保存粒子y的坐标\n", 316 | " \n", 317 | " # 遍历0-400号原子的坐标,加入到列表中去\n", 318 | " for n in range(len(mol)):\n", 319 | " x.append(mol[n].r[0])\n", 320 | " y.append(mol[n].r[1])\n", 321 | " \n", 322 | " # 标记400个原子中两个位置较为居中的两相邻原子mol[250]和mol[251],用于观察\n", 323 | " mark_1 = int(len(mol)/2 + len(mol)/8)\n", 324 | " mark_2 = int(len(mol)/2 + len(mol)/8 + 1)\n", 325 | " \n", 326 | " # 根据原子坐标绘制图形\n", 327 | " plt.plot(x, y, 'o', color='blue') #每个原子均为蓝色圆形\n", 328 | " plt.plot(x[mark_1], y[mark_1], 'o', color='red') #标记mark_1为红色\n", 329 | " plt.plot(x[mark_2], y[mark_2], 'o', color='cyan') #标记mark_2为青色\n", 330 | " \n", 331 | " # 绘制图标的标题\n", 332 | " plt.title('timestep:'+\"{0:.4f}\".format(timeNow)+'; '+\\\n", 333 | " '$\\Sigma v$:'+Sigma_v+'; '+\\\n", 334 | " 'E:'+E+'; '+\\\n", 335 | " '$\\sigma E$:'+Sigma_E+';\\n'+\\\n", 336 | " 'Ek:'+Ek+'; ' +\\\n", 337 | " '$\\sigma Ek$:'+Sigma_Ek+'; '+\\\n", 338 | " 'P.sum1:'+P_1+'; '+\\\n", 339 | " 'P.sum2:'+P_2+'; ', loc='left')\n", 340 | " \n", 341 | " plt.savefig(TileName, dpi=100) #保存为坐标图为.png图片\n", 342 | " \n", 343 | "\n", 344 | "# 代码16:...................................................................................\n", 345 | "def makeMov():\n", 346 | " \n", 347 | " # 将多张.png图像转为gif图的片段\n", 348 | " frames = []\n", 349 | " imgs = sorted(glob.glob('coo/*.png'), key=os.path.getmtime)\n", 350 | " for i in imgs:\n", 351 | " temp = Image.open(i)\n", 352 | " keep = temp.copy()\n", 353 | " frames.append(keep)\n", 354 | " temp.close()\n", 355 | " \n", 356 | " # 删除全部的.png图\n", 357 | " for i in imgs:\n", 358 | " os.remove(i) \n", 359 | "\n", 360 | " # 片段合并保存为GIF文件,永远循环播放\n", 361 | " frames[0].save('coo/coordinates.gif', format='GIF',\n", 362 | " append_images=frames[1:],\n", 363 | " save_all=True,\n", 364 | " duration=30, loop=0)\n", 365 | "\n", 366 | " # 将GIF图转换成MP4视频文件\n", 367 | " clip = mp.VideoFileClip(\"coo/coordinates.gif\")\n", 368 | " clip.write_videofile(\"coo/\"+\"coordinates\"+\".mp4\")\n", 369 | " \n", 370 | " # 删除gif图\n", 371 | " os.remove(\"coo/coordinates.gif\")\n", 372 | " \n", 373 | "\n", 374 | "# 代码17:...................................................................................\n", 375 | "def GraphOutput():\n", 376 | " \n", 377 | " ax = \\\n", 378 | " df_systemParams.plot(x=\"timestep\", y='$\\Sigma v$', kind=\"line\")\n", 379 | " df_systemParams.plot(x=\"timestep\", y='E', kind=\"line\", ax=ax, color=\"C1\")\n", 380 | " df_systemParams.plot(x=\"timestep\", y='$\\sigma E$', kind=\"line\", ax=ax, color=\"C2\")\n", 381 | " df_systemParams.plot(x=\"timestep\", y='Ek', kind=\"line\", ax=ax, color=\"C3\")\n", 382 | " df_systemParams.plot(x=\"timestep\", y='$\\sigma Ek$', kind=\"line\", ax=ax, color=\"C4\")\n", 383 | " df_systemParams.plot(x=\"timestep\", y='P_1', kind=\"line\", ax=ax, color=\"C9\")\n", 384 | " df_systemParams.plot(x=\"timestep\", y='P_2', kind=\"line\", ax=ax, color=\"C9\")\n", 385 | " \n", 386 | " plt.savefig('plot.jpg', dpi=300)\n", 387 | " \n", 388 | " \n", 389 | "# 代码3:************************************Main************************************************\n", 390 | "mov = 1 # 如果你想做一个视频的话,设置 mov=1\n", 391 | "workdir = str(os.getcwd()+'/') # 为所有png和视频设置一个工作目录\n", 392 | "\n", 393 | "if path.exists(str(workdir+'coo'))==False:\n", 394 | " os.makedirs(str(workdir+'coo'))\n", 395 | "else:\n", 396 | " shutil.rmtree(str(workdir+'coo'))\n", 397 | " os.makedirs(str(workdir+'coo'))\n", 398 | "\n", 399 | "# 加载输入参数文件\n", 400 | "df_params = pd.read_csv('Rap_2_LJP.in', sep='\\t', header=None, names=['parameter', 'value'])\n", 401 | "\n", 402 | "#初始该模拟系统热力学属性值\n", 403 | "NDIM = 2 #二维度设置\n", 404 | "vSum = np.asarray([0.0, 0.0]) #速度之和\n", 405 | "kinEnergy =Prop(0.0, 0.0, 0.0) #动能\n", 406 | "totEnergy =Prop(0.0, 0.0, 0.0) #势能\n", 407 | "pressure =Prop(0.0, 0.0, 0.0) #压强\n", 408 | "\n", 409 | "systemParams = [] #初始化系统参数列表\n", 410 | "\n", 411 | "#用于产生随机数算法函数的变量\n", 412 | "IADD = 453806245\n", 413 | "IMUL = 314159269\n", 414 | "MASK = 2147483647\n", 415 | "SCALE = 0.4656612873e-9\n", 416 | "randSeedP = 17\n", 417 | "\n", 418 | "#初始化参数:把Rap_2_LJP.文件中的参数值传递给MD模拟所需要的相关变量\n", 419 | "deltaT = float(df_params.values[0][1]) #模拟步长\n", 420 | "density = float(df_params.values[1][1]) #体系密度\n", 421 | "\n", 422 | "\n", 423 | "initUcell = np.asarray([0.0, 0.0]) #初始化元胞,具体大小由输入文件密度决定\n", 424 | "initUcell[0] = int(df_params.values[2][1]) #元胞X方向长度=20\n", 425 | "initUcell[1] = int(df_params.values[3][1]) #元胞X方向长度=20\n", 426 | " \n", 427 | "stepAvg = int(df_params.values[4][1]) #抽样平均数\n", 428 | "stepEquil = float(df_params.values[5][1]) #平衡步长\n", 429 | "stepLimit = float(df_params.values[6][1]) #限制的步数\n", 430 | "temperature = float(df_params.values[7][1]) #体系温度\n", 431 | "\n", 432 | "#定义了一个Mol类对象的数组,大小为20*20=400. mol[0]~mol[399],共400个氩原子分子\n", 433 | "mol = [Mol(np.asarray([0.0, 0.0]), \\\n", 434 | " np.asarray([0.0, 0.0]), \\\n", 435 | " np.asarray([0.0, 0.0])) for i in range(int(initUcell[0]*initUcell[1]))]\n", 436 | "\n", 437 | "global nMol #定义分子的数量变量\n", 438 | "nMol = len(mol) #为mol数组的长度为400\n", 439 | "\n", 440 | "# 氩-氩相互作用的LJ势参数:\n", 441 | "epsilon = 1\n", 442 | "sigma = 1\n", 443 | "\n", 444 | "# 执行体系初始化相关功能函数\n", 445 | "SetParams() #设置主程序内部模拟所需参数\n", 446 | "SetupJob() #初始化粒子的坐标,速度,加速\n", 447 | "moreCycles = 1 #MD循环控制开关变量1:run; 0:stop\n", 448 | "\n", 449 | "n = 0 #记录步数,用来给每一步输出的坐标图命名 \n", 450 | "while moreCycles: #MD循环\n", 451 | " SingleStep() #求解每一步的运动方程\n", 452 | " if mov==1:\n", 453 | " plotMolCoo(mol, workdir, n) #制作单个步长的粒子坐标图\n", 454 | " n += 1\n", 455 | " if stepCount >= stepLimit:\n", 456 | " moreCycles = 0\n", 457 | " \n", 458 | "#输出模拟过程中生成的参数\n", 459 | "columns = ['timestep','timeNow', '$\\Sigma v$', 'E', '$\\sigma E$', 'Ek', '$\\sigma Ek$', 'P_1', 'P_2']\n", 460 | "df_systemParams = pd.DataFrame(systemParams, columns=columns) \n", 461 | "\n", 462 | "#绘制表格\n", 463 | "display(df_systemParams) \n", 464 | "if mov==1: \n", 465 | " makeMov() # 制作视频\n", 466 | "GraphOutput() #输出体系测定量随模拟时间变化的图像" 467 | ] 468 | } 469 | ], 470 | "metadata": { 471 | "kernelspec": { 472 | "display_name": "Python 3 (ipykernel)", 473 | "language": "python", 474 | "name": "python3" 475 | }, 476 | "language_info": { 477 | "codemirror_mode": { 478 | "name": "ipython", 479 | "version": 3 480 | }, 481 | "file_extension": ".py", 482 | "mimetype": "text/x-python", 483 | "name": "python", 484 | "nbconvert_exporter": "python", 485 | "pygments_lexer": "ipython3", 486 | "version": "3.9.6" 487 | }, 488 | "toc": { 489 | "base_numbering": 1, 490 | "nav_menu": {}, 491 | "number_sections": true, 492 | "sideBar": true, 493 | "skip_h1_title": false, 494 | "title_cell": "Table of Contents", 495 | "title_sidebar": "Contents", 496 | "toc_cell": false, 497 | "toc_position": {}, 498 | "toc_section_display": true, 499 | "toc_window_display": false 500 | } 501 | }, 502 | "nbformat": 4, 503 | "nbformat_minor": 5 504 | } 505 | -------------------------------------------------------------------------------- /configura/MD_LJP.py: -------------------------------------------------------------------------------- 1 | # 代码1:.......................................................................................... 2 | import pandas as pd 3 | import math 4 | import os 5 | import matplotlib.pyplot as plt 6 | plt.style.use('seaborn-whitegrid') 7 | import numpy as np 8 | from PIL import Image 9 | import glob 10 | import moviepy.editor as mp 11 | from datetime import datetime 12 | import time 13 | import os.path 14 | from os import path 15 | import shutil 16 | 17 | 18 | # 代码2:.......................................................................................... 19 | class Mol(): 20 | def __init__(self,r,rv,ra): 21 | """ 22 | 每一分子对象(mol)所具有的属性如下: 23 | r:原子坐标 24 | rv:原子速度 25 | ra:原子加速度向量 26 | """ 27 | #初始化以上属性的值 28 | self.r=np.asarray([0.0,0.0]) 29 | self.rv=np.asarray([0.0,0.0]) 30 | self.ra=np.asarray([0.0,0.0]) 31 | 32 | # 体系属性类,主要用来求体系属性(测定量)的平均值和标准差 33 | class Prop(): 34 | def __init__(self, val, sum1, sum2 ): 35 | self.val=val #体系测定量的值 36 | self.sum1=sum1 #体系测定量的值的和 37 | self.sum2=sum2 #体系测定量的值的平方和 38 | 39 | 40 | # 代码3:.......................................................................................... 41 | def Sqr(x): 42 | return (x * x) 43 | 44 | def Cube(x): 45 | return ((x) * (x) * (x)) 46 | 47 | # 用于生成 (0,1) 范围内的均匀分布的随机数,见18.4 48 | def RandR(): 49 | global randSeedP 50 | randSeedP=(randSeedP * IMUL + IADD) & MASK 51 | return (randSeedP*SCALE) 52 | 53 | # 用于在二维空间产生具有均匀分布的随机方向的单位向量 54 | def VRand(p): 55 | s: float 56 | s = 2. * math.pi * RandR() 57 | p[0] = math.cos(s) 58 | p[1] = math.sin(s) 59 | return p 60 | 61 | # 周期性边界(PBC)算法: 62 | # PBC算法第一部分:对体系内粒子坐标的约束 63 | def VWrapAll(v): 64 | #对元胞x方向的坐标约束 65 | if v[0]>=0.5*region[0]: 66 | v[0]-=region[0] 67 | elif v[0]<-0.5*region[0]: 68 | v[0] +=region[0] 69 | 70 | #对元胞y方向的坐标约束 71 | if v[1] >= 0.5 * region[1]: 72 | v[1] -= region[1] 73 | elif v[1] < -0.5 * region[1]: 74 | v[1] += region[1] 75 | 76 | 77 | # 代码5:.......................................................................................... 78 | def SetParams(): 79 | global rCut #截断距离 80 | global region #区域 81 | global velMag #速度幅度 82 | 83 | #截断值为势阱底部时的原子间距离,即rmin=rCut=2^1/6 *sigma 84 | rCut=math.pow(2.,1./6. * sigma) 85 | region=np.multiply(1./math.sqrt(density),initUcell) 86 | nMol=len(mol) 87 | 88 | #速度的变化幅度取决于温度的高低 89 | velMag = math.sqrt(NDIM * (1. -1. /nMol) * temperature) 90 | 91 | 92 | # 代码7:.......................................................................................... 93 | def InitCoords(): 94 | c=np.asarray([0.0,0.0]) #初始坐标值 95 | gap=np.divide(region,initUcell) #单个粒子所在元胞的大小 96 | n=0 #给粒子计数 97 | 98 | #将400个原子分别放到元胞中(这些元胞向x,y方向扩胞成了region区域) 99 | for ny in range(0, int(initUcell[1])): 100 | for nx in range(0, int(initUcell[0])): 101 | c = np.asarray([nx+0.5, ny+0.5]) 102 | c = np.multiply(c, gap) 103 | c = np.add(c, np.multiply(-0.5, region)) 104 | mol[n].r = c 105 | n=n+1 106 | 107 | 108 | def InitVels(): 109 | global vSum 110 | vSum=np.zeros(vSum.shape) #返回特定大小,以0填充新的数组:[0,0],这里是形状 111 | 112 | for n in range(nMol): 113 | VRand(mol[n].rv) #产生随机随机速度向量[x,y] 114 | mol[n].rv=np.multiply(mol[n].rv,velMag) #根据温度,生成新的速度 115 | vSum=np.add(vSum,mol[n].rv) #质心的速度,系统总速度各质点速度的总和 116 | 117 | #调整度方向,以确保质心是静止的,这里取400个粒子在,x,y方向的平均速度1/400*Vsum+每一个原子的速度 118 | for n in range (nMol): 119 | mol[n].rv=np.add(mol[n].rv,np.multiply((- 1.0 / nMol),vSum)) 120 | 121 | 122 | def InitAccels(): 123 | for n in range(nMol): 124 | mol[n].ra=np.zeros(mol[n].ra.shape) 125 | 126 | 127 | # 代码8:.......................................................................................... 128 | def PropZero(v): 129 | v.sum1 = v.sum2 = 0. 130 | return v 131 | 132 | def PropAccum(v): 133 | v.sum1 += v.val 134 | v.sum2 += Sqr(v.val) 135 | return v 136 | 137 | def PropAvg(v, n): 138 | v.sum1 /= n 139 | v.sum2 = math.sqrt(max(v.sum2 / n - Sqr(v.sum1), 0.)) 140 | return v 141 | 142 | 143 | def AccumProps(icode): 144 | 145 | if icode == 0: # 0:初始化 146 | PropZero(totEnergy) 147 | PropZero(kinEnergy) 148 | PropZero(pressure) 149 | if icode == 1: # 1:求和 150 | PropAccum(totEnergy) 151 | PropAccum(kinEnergy) 152 | PropAccum(pressure) 153 | if icode == 2: # 2:求平均值和标准差 154 | PropAvg(totEnergy, stepAvg) 155 | PropAvg(kinEnergy, stepAvg) 156 | PropAvg(pressure, stepAvg) 157 | 158 | 159 | # 代码6:.......................................................................................... 160 | def SetupJob(): 161 | global stepCount #步长计数 162 | 163 | stepCount = 0 #初始化步长计数变量的值 164 | InitCoords() #初始化坐标 165 | InitVels() #初始化速度 166 | InitAccels() #初始化加速度 167 | AccumProps(0) #初始化系统属性值(总能量,动能,压强) 168 | 169 | 170 | # 代码10:......................................................................................... 171 | def LeapfrogStep(part): 172 | if part == 1: 173 | for n in range (nMol): 174 | mol[n].rv=np.add(mol[n].rv,np.multiply(0.5 * deltaT,mol[n].ra)) 175 | mol[n].r=np.add(mol[n].r,np.multiply(deltaT,mol[n].rv)) 176 | else : 177 | for n in range(nMol): 178 | mol[n].rv=np.add(mol[n].rv,np.multiply(0.5 * deltaT,mol[n].ra)) 179 | 180 | 181 | # 代码11:................................................................................... 182 | def ApplyBoundaryCond(): 183 | for n in range(nMol): 184 | VWrapAll(mol[n].r) 185 | 186 | # 代码12:................................................................................... 187 | def ComputeForces(): 188 | global virSum #用于计算压强的中间变量(fij*rij)和 189 | global uSum #LJ势能和 190 | fcVal=0 # 原子j对原子i施加的力 191 | rrCut=Sqr(rCut) # rCut:Rc,截断半径的平方 192 | 193 | #初始化分子加速度 194 | for n in range (nMol): 195 | mol[n].ra=np.zeros(mol[n].ra.shape) 196 | 197 | uSum=0. #初始化LJ势能和值 198 | virSum=0. 199 | n=0 200 | for j1 in range(nMol-1): 201 | for j2 in range(j1+1,nMol): 202 | 203 | # 使Delta Rij。(RJ1-RJ2的平方之和) 204 | dr=np.subtract(mol[j1].r,mol[j2].r) # dr包含Rj1和Rj2之间的x,y坐标差值 205 | VWrapAll(dr) #应用PBC约束原子在元胞内,更新了dr[0],dr[1] 206 | rr=(dr[0] * dr[0] + dr[1] * dr[1]) #两原子距离的平方,这里并未求两原子间距离的绝对值,没必要,因为与截断半径只是比大小,省去了平方根的计算 207 | r=np.sqrt(rr) #r两为原子间的距离 208 | 209 | # 这里是使用原子距离的平方来 dr2 < Rc^2 来判断两原子键相互作用力, 210 | if(rr < rrCut): 211 | fcVal = 48 * epsilon * np.power(sigma, 12) / np.power(r, 13) - 24 * epsilon * np.power(sigma, 6) / np.power(r, 7) 212 | 213 | # 更新加速度 214 | mol[j1].ra = np.add(mol[j1].ra, np.multiply(fcVal, dr)) 215 | mol[j2].ra = np.add(mol[j2].ra, np.multiply(-fcVal, dr)) 216 | 217 | #LJ势能计算 218 | uSum += 4 * epsilon * np.power(sigma/r, 12)/r - np.power(sigma/r, 6) 219 | virSum += fcVal * rr 220 | 221 | # 代码13:................................................................................... 222 | def EvalProps(): 223 | global vSum 224 | vvSum = 0. #系统速度平方的总和 225 | vSum = np.zeros(vSum.shape) #质心速度,为系统速度=各质点速度总和,初始化为[0,0] 226 | 227 | global kinEnergy #动能 228 | global totEenergy #总能量 229 | global pressure #压强 230 | 231 | #求得质心速度 232 | for n in range(nMol): 233 | vSum =np.add(vSum,mol[n].rv) 234 | vv = (mol[n].rv[0] * mol[n].rv[0] + mol[n].rv[1] * mol[n].rv[1]) #xv^2+yv^2 235 | vvSum += vv 236 | 237 | # 在二维分子体系中,热力学属性值的数值计算方法 238 | kinEnergy.val = (0.5 * vvSum) / nMol #单个原子动能,nMol代表原子数 239 | totEnergy.val = kinEnergy.val + (uSum / nMol) #总能量:单个原子的动能+单个原子的势能 240 | pressure.val = density * (vvSum + virSum) / (nMol * NDIM) #体系压强 241 | 242 | 243 | # 代码14:................................................................................... 244 | def PrintSummary(): 245 | 246 | print(stepCount, \ 247 | "{0:.4f}".format(timeNow), \ 248 | "{0:.4f}".format(vSum[0] / nMol) ,\ 249 | "{0:.4f}".format(totEnergy.sum1),\ 250 | "{0:.4f}".format(totEnergy.sum2), \ 251 | "{0:.4f}".format(kinEnergy.sum1), \ 252 | "{0:.4f}".format(kinEnergy.sum2),\ 253 | "{0:.4f}".format(pressure.sum1),\ 254 | "{0:.4f}".format(pressure.sum2)) 255 | 256 | return (stepCount, \ 257 | timeNow, \ 258 | (vSum[0] / nMol) ,\ 259 | totEnergy.sum1,\ 260 | totEnergy.sum2, \ 261 | kinEnergy.sum1, \ 262 | kinEnergy.sum2,\ 263 | pressure.sum1,\ 264 | pressure.sum2) 265 | 266 | # 代码9:------------------------------------------------------------------------------------------ 267 | def SingleStep(): 268 | 269 | global stepCount # 步长计数 270 | global timeNow # 模拟运行时间 271 | 272 | stepCount +=1 273 | timeNow = stepCount * deltaT #模拟运行的时间=步数x步长 274 | LeapfrogStep(1) #求解运动方程积分 275 | ApplyBoundaryCond() #应用周期性边界条件 276 | ComputeForces() # 计算原间相互作用力 277 | LeapfrogStep(2) # 坐标和速度的积分 278 | EvalProps() #计算系统属性值(速度,,速度平方和,总能量,动能,压力) 279 | AccumProps(1) #系统属性值求和 280 | 281 | #每一百步统计系统的属性值(0,100,200,300,400,500),可以设置stepAvg的值进行自定义 282 | if (stepCount % stepAvg == 0): 283 | AccumProps(2) #求系统的属性值的平均值和标准差 284 | systemParams.append(PrintSummary()) #将结果加入到 systemParams列表中 285 | AccumProps(0) # 重置系统属性值用来下一次的统计 286 | 287 | 288 | # 代码15:................................................................................... 289 | def plotMolCoo(mol,workdir,n): 290 | import matplotlib.patches as mpatches 291 | import matplotlib.pyplot as plt 292 | 293 | Time=timeNow #模拟时长 294 | Sigma_v = "{0:.4f}".format(vSum[0] / nMol) 295 | E = "{0:.4f}".format(totEnergy.sum1) 296 | Sigma_E = "{0:.4f}".format(totEnergy.sum2) 297 | Ek = "{0:.4f}".format(kinEnergy.sum1) 298 | Sigma_Ek = "{0:.4f}".format(kinEnergy.sum2) 299 | P_1 = "{0:.4f}".format(pressure.sum1) 300 | P_2 = "{0:.4f}".format(pressure.sum2) 301 | 302 | 303 | #%matplotlib inline 304 | TileName = (workdir+'coo/'+str(n)+'.png') #传入的n表示n步,这里用来给生成的图像命名 305 | x = [] #新建列表保存粒子x的坐标 306 | y = [] #新建列表保存粒子y的坐标 307 | 308 | # 遍历0-400号原子的坐标,加入到列表中去 309 | for n in range(len(mol)): 310 | x.append(mol[n].r[0]) 311 | y.append(mol[n].r[1]) 312 | 313 | # 标记400个原子中两个位置较为居中的两相邻原子mol[250]和mol[251],用于观察 314 | mark_1 = int(len(mol)/2 + len(mol)/8) 315 | mark_2 = int(len(mol)/2 + len(mol)/8 + 1) 316 | 317 | # 根据原子坐标绘制图形 318 | plt.plot(x, y, 'o', color='blue') #每个原子均为蓝色圆形 319 | plt.plot(x[mark_1], y[mark_1], 'o', color='red') #标记mark_1为红色 320 | plt.plot(x[mark_2], y[mark_2], 'o', color='cyan') #标记mark_2为青色 321 | 322 | # 绘制图标的标题 323 | plt.title('timestep:'+"{0:.4f}".format(timeNow)+'; '+\ 324 | '$\Sigma v$:'+Sigma_v+'; '+\ 325 | 'E:'+E+'; '+\ 326 | '$\sigma E$:'+Sigma_E+';\n'+\ 327 | 'Ek:'+Ek+'; ' +\ 328 | '$\sigma Ek$:'+Sigma_Ek+'; '+\ 329 | 'P.sum1:'+P_1+'; '+\ 330 | 'P.sum2:'+P_2+'; ', loc='left') 331 | 332 | plt.savefig(TileName, dpi=100) #保存为坐标图为.png图片 333 | 334 | 335 | # 代码16:................................................................................... 336 | def makeMov(): 337 | 338 | # 将多张.png图像转为gif图的片段 339 | frames = [] 340 | imgs = sorted(glob.glob('coo/*.png'), key=os.path.getmtime) 341 | for i in imgs: 342 | temp = Image.open(i) 343 | keep = temp.copy() 344 | frames.append(keep) 345 | temp.close() 346 | 347 | # 删除全部的.png图 348 | for i in imgs: 349 | os.remove(i) 350 | 351 | # 片段合并保存为GIF文件,永远循环播放 352 | frames[0].save('coo/coordinates.gif', format='GIF', 353 | append_images=frames[1:], 354 | save_all=True, 355 | duration=30, loop=0) 356 | 357 | # 将GIF图转换成MP4视频文件 358 | clip = mp.VideoFileClip("coo/coordinates.gif") 359 | clip.write_videofile("coo/"+"coordinates"+".mp4") 360 | 361 | # 删除gif图 362 | os.remove("coo/coordinates.gif") 363 | 364 | 365 | # 代码17:................................................................................... 366 | def GraphOutput(): 367 | 368 | ax = \ 369 | df_systemParams.plot(x="timestep", y='$\Sigma v$', kind="line") 370 | df_systemParams.plot(x="timestep", y='E', kind="line", ax=ax, color="C1") 371 | df_systemParams.plot(x="timestep", y='$\sigma E$', kind="line", ax=ax, color="C2") 372 | df_systemParams.plot(x="timestep", y='Ek', kind="line", ax=ax, color="C3") 373 | df_systemParams.plot(x="timestep", y='$\sigma Ek$', kind="line", ax=ax, color="C4") 374 | df_systemParams.plot(x="timestep", y='P_1', kind="line", ax=ax, color="C9") 375 | df_systemParams.plot(x="timestep", y='P_2', kind="line", ax=ax, color="C9") 376 | 377 | plt.savefig('plot.jpg', dpi=300) 378 | 379 | 380 | # 代码3:************************************Main************************************************ 381 | mov = 1 # 如果你想做一个视频的话,设置 mov=1 382 | workdir = str(os.getcwd()+'/') # 为所有png和视频设置一个工作目录 383 | 384 | if path.exists(str(workdir+'coo'))==False: 385 | os.makedirs(str(workdir+'coo')) 386 | else: 387 | shutil.rmtree(str(workdir+'coo')) 388 | os.makedirs(str(workdir+'coo')) 389 | 390 | # 加载输入参数文件 391 | df_params = pd.read_csv('Rap_2_LJP.in', sep='\t', header=None, names=['parameter', 'value']) 392 | 393 | #初始该模拟系统热力学属性值 394 | NDIM = 2 #二维度设置 395 | vSum = np.asarray([0.0, 0.0]) #速度之和 396 | kinEnergy =Prop(0.0, 0.0, 0.0) #动能 397 | totEnergy =Prop(0.0, 0.0, 0.0) #势能 398 | pressure =Prop(0.0, 0.0, 0.0) #压强 399 | 400 | systemParams = [] #初始化系统参数列表 401 | 402 | #用于产生随机数算法函数的变量 403 | IADD = 453806245 404 | IMUL = 314159269 405 | MASK = 2147483647 406 | SCALE = 0.4656612873e-9 407 | randSeedP = 17 408 | 409 | #初始化参数:把Rap_2_LJP.文件中的参数值传递给MD模拟所需要的相关变量 410 | deltaT = float(df_params.values[0][1]) #模拟步长 411 | density = float(df_params.values[1][1]) #体系密度 412 | 413 | 414 | initUcell = np.asarray([0.0, 0.0]) #初始化元胞,具体大小由输入文件密度决定 415 | initUcell[0] = int(df_params.values[2][1]) #元胞X方向长度=20 416 | initUcell[1] = int(df_params.values[3][1]) #元胞X方向长度=20 417 | 418 | stepAvg = int(df_params.values[4][1]) #抽样平均数 419 | stepEquil = float(df_params.values[5][1]) #平衡步长 420 | stepLimit = float(df_params.values[6][1]) #限制的步数 421 | temperature = float(df_params.values[7][1]) #体系温度 422 | 423 | #定义了一个Mol类对象的数组,大小为20*20=400. mol[0]~mol[399],共400个氩原子分子 424 | mol = [Mol(np.asarray([0.0, 0.0]), \ 425 | np.asarray([0.0, 0.0]), \ 426 | np.asarray([0.0, 0.0])) for i in range(int(initUcell[0]*initUcell[1]))] 427 | 428 | global nMol #定义分子的数量变量 429 | nMol = len(mol) #为mol数组的长度为400 430 | 431 | # 氩-氩相互作用的LJ势参数: 432 | epsilon = 1 433 | sigma = 1 434 | 435 | # 执行体系初始化相关功能函数 436 | SetParams() #设置主程序内部模拟所需参数 437 | SetupJob() #初始化粒子的坐标,速度,加速 438 | moreCycles = 1 #MD循环控制开关变量1:run; 0:stop 439 | 440 | n = 0 #记录步数,用来给每一步输出的坐标图命名 441 | while moreCycles: #MD循环 442 | SingleStep() #求解每一步的运动方程 443 | if mov==1: 444 | plotMolCoo(mol, workdir, n) #制作单个步长的粒子坐标图 445 | n += 1 446 | if stepCount >= stepLimit: 447 | moreCycles = 0 448 | 449 | #输出模拟过程中生成的参数 450 | columns = ['timestep','timeNow', '$\Sigma v$', 'E', '$\sigma E$', 'Ek', '$\sigma Ek$', 'P_1', 'P_2'] 451 | df_systemParams = pd.DataFrame(systemParams, columns=columns) 452 | print(df_systemParams) 453 | if mov==1: 454 | makeMov() # 制作视频 455 | GraphOutput() #输出体系测定量随模拟时间变化的图像 456 | -------------------------------------------------------------------------------- /configura/Rap_2_LJP.in: -------------------------------------------------------------------------------- 1 | deltaT 0.005 2 | density 0.8 3 | initUcell_x 20 4 | initUcell_y 20 5 | stepAvg 100 6 | stepEquil 0 7 | stepLimit 500 8 | temperature 1. 9 | -------------------------------------------------------------------------------- /exmple_in_jupyter notebook/.ipynb_checkpoints/MD_LJP-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "id": "33f7674e", 7 | "metadata": { 8 | "ExecuteTime": { 9 | "end_time": "2021-09-27T09:50:56.152591Z", 10 | "start_time": "2021-09-27T09:50:42.955752Z" 11 | }, 12 | "scrolled": false 13 | }, 14 | "outputs": [], 15 | "source": [ 16 | "# 代码1:..........................................................................................\n", 17 | "import pandas as pd\n", 18 | "import math\n", 19 | "import os\n", 20 | "import matplotlib.pyplot as plt\n", 21 | "plt.style.use('seaborn-whitegrid')\n", 22 | "import numpy as np\n", 23 | "from PIL import Image\n", 24 | "import glob\n", 25 | "import moviepy.editor as mp\n", 26 | "from datetime import datetime\n", 27 | "import time\n", 28 | "import os.path\n", 29 | "from os import path\n", 30 | "import shutil\n", 31 | "%matplotlib inline \n", 32 | "\n", 33 | "# 代码2:..........................................................................................\n", 34 | "class Mol():\n", 35 | " def __init__(self,r,rv,ra):\n", 36 | " \"\"\"\n", 37 | " 每一分子对象(mol)所具有的属性如下:\n", 38 | " r:原子坐标\n", 39 | " rv:原子速度\n", 40 | " ra:原子加速度向量\n", 41 | " \"\"\"\n", 42 | " #初始化以上属性的值\n", 43 | " self.r=np.asarray([0.0,0.0])\n", 44 | " self.rv=np.asarray([0.0,0.0])\n", 45 | " self.ra=np.asarray([0.0,0.0])\n", 46 | " \n", 47 | "# 体系属性类,主要用来求体系属性(测定量)的平均值和标准差 \n", 48 | "class Prop():\n", 49 | " def __init__(self, val, sum1, sum2 ):\n", 50 | " self.val=val #体系测定量的值\n", 51 | " self.sum1=sum1 #体系测定量的值的和\n", 52 | " self.sum2=sum2 #体系测定量的值的平方和\n", 53 | "\n", 54 | " \n", 55 | "# 代码3:..........................................................................................\n", 56 | "def Sqr(x):\n", 57 | " return (x * x)\n", 58 | "\n", 59 | "def Cube(x):\n", 60 | " return ((x) * (x) * (x))\n", 61 | "\n", 62 | "# 用于生成 (0,1) 范围内的均匀分布的随机数,见18.4\n", 63 | "def RandR():\n", 64 | " global randSeedP\n", 65 | " randSeedP=(randSeedP * IMUL + IADD) & MASK\n", 66 | " return (randSeedP*SCALE)\n", 67 | "\n", 68 | "# 用于在二维空间产生具有均匀分布的随机方向的单位向量\n", 69 | "def VRand(p):\n", 70 | " s: float\n", 71 | " s = 2. * math.pi * RandR()\n", 72 | " p[0] = math.cos(s)\n", 73 | " p[1] = math.sin(s)\n", 74 | " return p\n", 75 | "\n", 76 | "# 周期性边界(PBC)算法:\n", 77 | "# PBC算法第一部分:对体系内粒子坐标的约束\n", 78 | "def VWrapAll(v):\n", 79 | " #对元胞x方向的坐标约束\n", 80 | " if v[0]>=0.5*region[0]: \n", 81 | " v[0]-=region[0]\n", 82 | " elif v[0]<-0.5*region[0]:\n", 83 | " v[0] +=region[0]\n", 84 | " \n", 85 | " #对元胞y方向的坐标约束\n", 86 | " if v[1] >= 0.5 * region[1]:\n", 87 | " v[1] -= region[1]\n", 88 | " elif v[1] < -0.5 * region[1]:\n", 89 | " v[1] += region[1]\n", 90 | " \n", 91 | " \n", 92 | "# 代码5:.......................................................................................... \n", 93 | "def SetParams():\n", 94 | " global rCut #截断距离\n", 95 | " global region #区域\n", 96 | " global velMag #速度幅度\n", 97 | " \n", 98 | " #截断值为势阱底部时的原子间距离,即rmin=rCut=2^1/6 *sigma\n", 99 | " rCut=math.pow(2.,1./6. * sigma)\n", 100 | " region=np.multiply(1./math.sqrt(density),initUcell) \n", 101 | " nMol=len(mol)\n", 102 | " \n", 103 | " #速度的变化幅度取决于温度的高低\n", 104 | " velMag = math.sqrt(NDIM * (1. -1. /nMol) * temperature)\n", 105 | " \n", 106 | " \n", 107 | "# 代码7:..........................................................................................\n", 108 | "def InitCoords():\n", 109 | " c=np.asarray([0.0,0.0]) #初始坐标值\n", 110 | " gap=np.divide(region,initUcell) #单个粒子所在元胞的大小\n", 111 | " n=0 #给粒子计数\n", 112 | " \n", 113 | " #将400个原子分别放到元胞中(这些元胞向x,y方向扩胞成了region区域)\n", 114 | " for ny in range(0, int(initUcell[1])):\n", 115 | " for nx in range(0, int(initUcell[0])):\n", 116 | " c = np.asarray([nx+0.5, ny+0.5])\n", 117 | " c = np.multiply(c, gap)\n", 118 | " c = np.add(c, np.multiply(-0.5, region))\n", 119 | " mol[n].r = c\n", 120 | " n=n+1\n", 121 | " \n", 122 | " \n", 123 | "def InitVels():\n", 124 | " global vSum\n", 125 | " vSum=np.zeros(vSum.shape) #返回特定大小,以0填充新的数组:[0,0],这里是形状\n", 126 | " \n", 127 | " for n in range(nMol):\n", 128 | " VRand(mol[n].rv) #产生随机随机速度向量[x,y]\n", 129 | " mol[n].rv=np.multiply(mol[n].rv,velMag) #根据温度,生成新的速度\n", 130 | " vSum=np.add(vSum,mol[n].rv) #质心的速度,系统总速度各质点速度的总和\n", 131 | " \n", 132 | " #调整度方向,以确保质心是静止的,这里取400个粒子在,x,y方向的平均速度1/400*Vsum+每一个原子的速度\n", 133 | " for n in range (nMol):\n", 134 | " mol[n].rv=np.add(mol[n].rv,np.multiply((- 1.0 / nMol),vSum))\n", 135 | " \n", 136 | " \n", 137 | "def InitAccels():\n", 138 | " for n in range(nMol):\n", 139 | " mol[n].ra=np.zeros(mol[n].ra.shape)\n", 140 | " \n", 141 | "\n", 142 | "# 代码8:..........................................................................................\n", 143 | "def PropZero(v):\n", 144 | " v.sum1 = v.sum2 = 0.\n", 145 | " return v \n", 146 | " \n", 147 | "def PropAccum(v):\n", 148 | " v.sum1 += v.val\n", 149 | " v.sum2 += Sqr(v.val)\n", 150 | " return v \n", 151 | "\n", 152 | "def PropAvg(v, n):\n", 153 | " v.sum1 /= n\n", 154 | " v.sum2 = math.sqrt(max(v.sum2 / n - Sqr(v.sum1), 0.)) \n", 155 | " return v \n", 156 | "\n", 157 | "\n", 158 | "def AccumProps(icode):\n", 159 | " \n", 160 | " if icode == 0: # 0:初始化 \n", 161 | " PropZero(totEnergy)\n", 162 | " PropZero(kinEnergy)\n", 163 | " PropZero(pressure) \n", 164 | " if icode == 1: # 1:求和 \n", 165 | " PropAccum(totEnergy)\n", 166 | " PropAccum(kinEnergy)\n", 167 | " PropAccum(pressure) \n", 168 | " if icode == 2: # 2:求平均值和标准差\n", 169 | " PropAvg(totEnergy, stepAvg)\n", 170 | " PropAvg(kinEnergy, stepAvg)\n", 171 | " PropAvg(pressure, stepAvg) \n", 172 | " \n", 173 | " \n", 174 | "# 代码6:..........................................................................................\n", 175 | "def SetupJob(): \n", 176 | " global stepCount #步长计数\n", 177 | " \n", 178 | " stepCount = 0 #初始化步长计数变量的值\n", 179 | " InitCoords() #初始化坐标\n", 180 | " InitVels() #初始化速度\n", 181 | " InitAccels() #初始化加速度\n", 182 | " AccumProps(0) #初始化系统属性值(总能量,动能,压强)\n", 183 | " \n", 184 | "\n", 185 | "# 代码10:.........................................................................................\n", 186 | "def LeapfrogStep(part):\n", 187 | " if part == 1:\n", 188 | " for n in range (nMol):\n", 189 | " mol[n].rv=np.add(mol[n].rv,np.multiply(0.5 * deltaT,mol[n].ra))\n", 190 | " mol[n].r=np.add(mol[n].r,np.multiply(deltaT,mol[n].rv))\n", 191 | " else :\n", 192 | " for n in range(nMol):\n", 193 | " mol[n].rv=np.add(mol[n].rv,np.multiply(0.5 * deltaT,mol[n].ra))\n", 194 | "\n", 195 | " \n", 196 | "# 代码11:...................................................................................\n", 197 | "def ApplyBoundaryCond():\n", 198 | " for n in range(nMol):\n", 199 | " VWrapAll(mol[n].r)\n", 200 | " \n", 201 | "# 代码12:...................................................................................\n", 202 | "def ComputeForces():\n", 203 | " global virSum #用于计算压强的中间变量(fij*rij)和\n", 204 | " global uSum #LJ势能和\n", 205 | " fcVal=0 # 原子j对原子i施加的力\n", 206 | " rrCut=Sqr(rCut) # rCut:Rc,截断半径的平方\n", 207 | " \n", 208 | " #初始化分子加速度\n", 209 | " for n in range (nMol):\n", 210 | " mol[n].ra=np.zeros(mol[n].ra.shape)\n", 211 | " \n", 212 | " uSum=0. #初始化LJ势能和值\n", 213 | " virSum=0.\n", 214 | " n=0\n", 215 | " for j1 in range(nMol-1):\n", 216 | " for j2 in range(j1+1,nMol):\n", 217 | " \n", 218 | " # 使Delta Rij。(RJ1-RJ2的平方之和)\n", 219 | " dr=np.subtract(mol[j1].r,mol[j2].r) # dr包含Rj1和Rj2之间的x,y坐标差值\n", 220 | " VWrapAll(dr) #应用PBC约束原子在元胞内,更新了dr[0],dr[1]\n", 221 | " rr=(dr[0] * dr[0] + dr[1] * dr[1]) #两原子距离的平方,这里并未求两原子间距离的绝对值,没必要,因为与截断半径只是比大小,省去了平方根的计算\n", 222 | " r=np.sqrt(rr) #r两为原子间的距离 \n", 223 | " \n", 224 | " # 这里是使用原子距离的平方来 dr2 < Rc^2 来判断两原子键相互作用力,\n", 225 | " if(rr < rrCut):\n", 226 | " fcVal = 48 * epsilon * np.power(sigma, 12) / np.power(r, 13) - 24 * epsilon * np.power(sigma, 6) / np.power(r, 7)\n", 227 | " \n", 228 | " # 更新加速度\n", 229 | " mol[j1].ra = np.add(mol[j1].ra, np.multiply(fcVal, dr))\n", 230 | " mol[j2].ra = np.add(mol[j2].ra, np.multiply(-fcVal, dr))\n", 231 | " \n", 232 | " #LJ势能计算\n", 233 | " uSum += 4 * epsilon * np.power(sigma/r, 12)/r - np.power(sigma/r, 6) \n", 234 | " virSum += fcVal * rr\n", 235 | " \n", 236 | "# 代码13:...................................................................................\n", 237 | "def EvalProps():\n", 238 | " global vSum\n", 239 | " vvSum = 0. #系统速度平方的总和\n", 240 | " vSum = np.zeros(vSum.shape) #质心速度,为系统速度=各质点速度总和,初始化为[0,0]\n", 241 | " \n", 242 | " global kinEnergy #动能\n", 243 | " global totEenergy #总能量\n", 244 | " global pressure #压强\n", 245 | " \n", 246 | " #求得质心速度\n", 247 | " for n in range(nMol):\n", 248 | " vSum =np.add(vSum,mol[n].rv) \n", 249 | " vv = (mol[n].rv[0] * mol[n].rv[0] + mol[n].rv[1] * mol[n].rv[1]) #xv^2+yv^2\n", 250 | " vvSum += vv\n", 251 | " \n", 252 | " # 在二维分子体系中,热力学属性值的数值计算方法\n", 253 | " kinEnergy.val = (0.5 * vvSum) / nMol #单个原子动能,nMol代表原子数\n", 254 | " totEnergy.val = kinEnergy.val + (uSum / nMol) #总能量:单个原子的动能+单个原子的势能\n", 255 | " pressure.val = density * (vvSum + virSum) / (nMol * NDIM) #体系压强\n", 256 | " \n", 257 | "\n", 258 | "# 代码14:...................................................................................\n", 259 | "def PrintSummary():\n", 260 | "\n", 261 | " print(stepCount, \\\n", 262 | " \"{0:.4f}\".format(timeNow), \\\n", 263 | " \"{0:.4f}\".format(vSum[0] / nMol) ,\\\n", 264 | " \"{0:.4f}\".format(totEnergy.sum1),\\\n", 265 | " \"{0:.4f}\".format(totEnergy.sum2), \\\n", 266 | " \"{0:.4f}\".format(kinEnergy.sum1), \\\n", 267 | " \"{0:.4f}\".format(kinEnergy.sum2),\\\n", 268 | " \"{0:.4f}\".format(pressure.sum1),\\\n", 269 | " \"{0:.4f}\".format(pressure.sum2))\n", 270 | " \n", 271 | " return (stepCount, \\\n", 272 | " timeNow, \\\n", 273 | " (vSum[0] / nMol) ,\\\n", 274 | " totEnergy.sum1,\\\n", 275 | " totEnergy.sum2, \\\n", 276 | " kinEnergy.sum1, \\\n", 277 | " kinEnergy.sum2,\\\n", 278 | " pressure.sum1,\\\n", 279 | " pressure.sum2) \n", 280 | "\n", 281 | "# 代码9:------------------------------------------------------------------------------------------\n", 282 | "def SingleStep():\n", 283 | " \n", 284 | " global stepCount # 步长计数\n", 285 | " global timeNow # 模拟运行时间\n", 286 | "\n", 287 | " stepCount +=1 \n", 288 | " timeNow = stepCount * deltaT #模拟运行的时间=步数x步长\n", 289 | " LeapfrogStep(1) #求解运动方程积分\n", 290 | " ApplyBoundaryCond() #应用周期性边界条件\n", 291 | " ComputeForces() # 计算原间相互作用力\n", 292 | " LeapfrogStep(2) # 坐标和速度的积分\n", 293 | " EvalProps() #计算系统属性值(速度,,速度平方和,总能量,动能,压力)\n", 294 | " AccumProps(1) #系统属性值求和\n", 295 | " \n", 296 | " #每一百步统计系统的属性值(0,100,200,300,400,500),可以设置stepAvg的值进行自定义\n", 297 | " if (stepCount % stepAvg == 0):\n", 298 | " AccumProps(2) #求系统的属性值的平均值和标准差\n", 299 | " systemParams.append(PrintSummary()) #将结果加入到 systemParams列表中\n", 300 | " AccumProps(0) # 重置系统属性值用来下一次的统计\n", 301 | " \n", 302 | "\n", 303 | "# 代码15:...................................................................................\n", 304 | "def plotMolCoo(mol,workdir,n):\n", 305 | " import matplotlib.patches as mpatches\n", 306 | " import matplotlib.pyplot as plt\n", 307 | " \n", 308 | " Time=timeNow #模拟时长\n", 309 | " Sigma_v = \"{0:.4f}\".format(vSum[0] / nMol)\n", 310 | " E = \"{0:.4f}\".format(totEnergy.sum1)\n", 311 | " Sigma_E = \"{0:.4f}\".format(totEnergy.sum2)\n", 312 | " Ek = \"{0:.4f}\".format(kinEnergy.sum1)\n", 313 | " Sigma_Ek = \"{0:.4f}\".format(kinEnergy.sum2)\n", 314 | " P_1 = \"{0:.4f}\".format(pressure.sum1)\n", 315 | " P_2 = \"{0:.4f}\".format(pressure.sum2) \n", 316 | " \n", 317 | " \n", 318 | " TileName = (workdir+'coo/'+str(n)+'.png') #传入的n表示n步,这里用来给生成的图像命名\n", 319 | " x = [] #新建列表保存粒子x的坐标\n", 320 | " y = [] #新建列表保存粒子y的坐标\n", 321 | " \n", 322 | " # 遍历0-400号原子的坐标,加入到列表中去\n", 323 | " for n in range(len(mol)):\n", 324 | " x.append(mol[n].r[0])\n", 325 | " y.append(mol[n].r[1])\n", 326 | " \n", 327 | " # 标记400个原子中两个位置较为居中的两相邻原子mol[250]和mol[251],用于观察\n", 328 | " mark_1 = int(len(mol)/2 + len(mol)/8)\n", 329 | " mark_2 = int(len(mol)/2 + len(mol)/8 + 1)\n", 330 | " \n", 331 | " # 根据原子坐标绘制图形\n", 332 | " plt.plot(x, y, 'o', color='blue') #每个原子均为蓝色圆形\n", 333 | " plt.plot(x[mark_1], y[mark_1], 'o', color='red') #标记mark_1为红色\n", 334 | " plt.plot(x[mark_2], y[mark_2], 'o', color='cyan') #标记mark_2为青色\n", 335 | " \n", 336 | " # 绘制图标的标题\n", 337 | " plt.title('timestep:'+\"{0:.4f}\".format(timeNow)+'; '+\\\n", 338 | " '$\\Sigma v$:'+Sigma_v+'; '+\\\n", 339 | " 'E:'+E+'; '+\\\n", 340 | " '$\\sigma E$:'+Sigma_E+';\\n'+\\\n", 341 | " 'Ek:'+Ek+'; ' +\\\n", 342 | " '$\\sigma Ek$:'+Sigma_Ek+'; '+\\\n", 343 | " 'P.sum1:'+P_1+'; '+\\\n", 344 | " 'P.sum2:'+P_2+'; ', loc='left')\n", 345 | " \n", 346 | " plt.savefig(TileName, dpi=100) #保存为坐标图为.png图片\n", 347 | " \n", 348 | "\n", 349 | "# 代码16:...................................................................................\n", 350 | "def makeMov():\n", 351 | " \n", 352 | " # 将多张.png图像转为gif图的片段\n", 353 | " frames = []\n", 354 | " imgs = sorted(glob.glob('coo/*.png'), key=os.path.getmtime)\n", 355 | " for i in imgs:\n", 356 | " temp = Image.open(i)\n", 357 | " keep = temp.copy()\n", 358 | " frames.append(keep)\n", 359 | " temp.close()\n", 360 | " \n", 361 | " # 删除全部的.png图\n", 362 | " for i in imgs:\n", 363 | " os.remove(i) \n", 364 | "\n", 365 | " # 片段合并保存为GIF文件,永远循环播放\n", 366 | " frames[0].save('coo/coordinates.gif', format='GIF',\n", 367 | " append_images=frames[1:],\n", 368 | " save_all=True,\n", 369 | " duration=30, loop=0)\n", 370 | "\n", 371 | " # 将GIF图转换成MP4视频文件\n", 372 | " clip = mp.VideoFileClip(\"coo/coordinates.gif\")\n", 373 | " clip.write_videofile(\"coo/\"+\"coordinates\"+\".mp4\")\n", 374 | " \n", 375 | " # 删除gif图\n", 376 | " os.remove(\"coo/coordinates.gif\")\n", 377 | " \n", 378 | "\n", 379 | "# 代码17:...................................................................................\n", 380 | "def GraphOutput():\n", 381 | " \n", 382 | " ax = \\\n", 383 | " df_systemParams.plot(x=\"timestep\", y='$\\Sigma v$', kind=\"line\")\n", 384 | " df_systemParams.plot(x=\"timestep\", y='E', kind=\"line\", ax=ax, color=\"C1\")\n", 385 | " df_systemParams.plot(x=\"timestep\", y='$\\sigma E$', kind=\"line\", ax=ax, color=\"C2\")\n", 386 | " df_systemParams.plot(x=\"timestep\", y='Ek', kind=\"line\", ax=ax, color=\"C3\")\n", 387 | " df_systemParams.plot(x=\"timestep\", y='$\\sigma Ek$', kind=\"line\", ax=ax, color=\"C4\")\n", 388 | " df_systemParams.plot(x=\"timestep\", y='P_1', kind=\"line\", ax=ax, color=\"C9\")\n", 389 | " df_systemParams.plot(x=\"timestep\", y='P_2', kind=\"line\", ax=ax, color=\"C9\")\n", 390 | " \n", 391 | " plt.savefig('plot.jpg', dpi=300)\n", 392 | " \n", 393 | " \n", 394 | "# 代码3:************************************Main************************************************\n", 395 | "mov = 1 # 如果你想做一个视频的话,设置 mov=1\n", 396 | "workdir = str(os.getcwd()+'/') # 为所有png和视频设置一个工作目录\n", 397 | "\n", 398 | "if path.exists(str(workdir+'coo'))==False:\n", 399 | " os.makedirs(str(workdir+'coo'))\n", 400 | "else:\n", 401 | " shutil.rmtree(str(workdir+'coo'))\n", 402 | " os.makedirs(str(workdir+'coo'))\n", 403 | "\n", 404 | "# 加载输入参数文件\n", 405 | "df_params = pd.read_csv('Rap_2_LJP.in', sep='\\t', header=None, names=['parameter', 'value'])\n", 406 | "\n", 407 | "#初始该模拟系统热力学属性值\n", 408 | "NDIM = 2 #二维度设置\n", 409 | "vSum = np.asarray([0.0, 0.0]) #速度之和\n", 410 | "kinEnergy =Prop(0.0, 0.0, 0.0) #动能\n", 411 | "totEnergy =Prop(0.0, 0.0, 0.0) #势能\n", 412 | "pressure =Prop(0.0, 0.0, 0.0) #压强\n", 413 | "\n", 414 | "systemParams = [] #初始化系统参数列表\n", 415 | "\n", 416 | "#用于产生随机数算法函数的变量\n", 417 | "IADD = 453806245\n", 418 | "IMUL = 314159269\n", 419 | "MASK = 2147483647\n", 420 | "SCALE = 0.4656612873e-9\n", 421 | "randSeedP = 17\n", 422 | "\n", 423 | "#初始化参数:把Rap_2_LJP.文件中的参数值传递给MD模拟所需要的相关变量\n", 424 | "deltaT = float(df_params.values[0][1]) #模拟步长\n", 425 | "density = float(df_params.values[1][1]) #体系密度\n", 426 | "\n", 427 | "\n", 428 | "initUcell = np.asarray([0.0, 0.0]) #初始化元胞,具体大小由输入文件密度决定\n", 429 | "initUcell[0] = int(df_params.values[2][1]) #元胞X方向长度=20\n", 430 | "initUcell[1] = int(df_params.values[3][1]) #元胞X方向长度=20\n", 431 | " \n", 432 | "stepAvg = int(df_params.values[4][1]) #抽样平均数\n", 433 | "stepEquil = float(df_params.values[5][1]) #平衡步长\n", 434 | "stepLimit = float(df_params.values[6][1]) #限制的步数\n", 435 | "temperature = float(df_params.values[7][1]) #体系温度\n", 436 | "\n", 437 | "#定义了一个Mol类对象的数组,大小为20*20=400. mol[0]~mol[399],共400个氩原子分子\n", 438 | "mol = [Mol(np.asarray([0.0, 0.0]), \\\n", 439 | " np.asarray([0.0, 0.0]), \\\n", 440 | " np.asarray([0.0, 0.0])) for i in range(int(initUcell[0]*initUcell[1]))]\n", 441 | "\n", 442 | "global nMol #定义分子的数量变量\n", 443 | "nMol = len(mol) #为mol数组的长度为400\n", 444 | "\n", 445 | "# 氩-氩相互作用的LJ势参数:\n", 446 | "epsilon = 1\n", 447 | "sigma = 1\n", 448 | "\n", 449 | "# 执行体系初始化相关功能函数\n", 450 | "SetParams() #设置主程序内部模拟所需参数\n", 451 | "SetupJob() #初始化粒子的坐标,速度,加速\n", 452 | "moreCycles = 1 #MD循环控制开关变量1:run; 0:stop\n", 453 | "\n", 454 | "n = 0 #记录步数,用来给每一步输出的坐标图命名 \n", 455 | "while moreCycles: #MD循环\n", 456 | " SingleStep() #求解每一步的运动方程\n", 457 | " if mov==1:\n", 458 | " plotMolCoo(mol, workdir, n) #制作单个步长的粒子坐标图\n", 459 | " n += 1\n", 460 | " if stepCount >= stepLimit:\n", 461 | " moreCycles = 0\n", 462 | " \n", 463 | "#输出模拟过程中生成的参数\n", 464 | "columns = ['timestep','timeNow', '$\\Sigma v$', 'E', '$\\sigma E$', 'Ek', '$\\sigma Ek$', 'P_1', 'P_2']\n", 465 | "df_systemParams = pd.DataFrame(systemParams, columns=columns) \n", 466 | "df_systemParamssy.\n", 467 | "if mov==1: \n", 468 | " makeMov() # 制作视频\n", 469 | "GraphOutput() #输出体系测定量随模拟时间变化的图像" 470 | ] 471 | } 472 | ], 473 | "metadata": { 474 | "celltoolbar": "编辑元数据", 475 | "kernelspec": { 476 | "display_name": "Python 3 (ipykernel)", 477 | "language": "python", 478 | "name": "python3" 479 | }, 480 | "language_info": { 481 | "codemirror_mode": { 482 | "name": "ipython", 483 | "version": 3 484 | }, 485 | "file_extension": ".py", 486 | "mimetype": "text/x-python", 487 | "name": "python", 488 | "nbconvert_exporter": "python", 489 | "pygments_lexer": "ipython3", 490 | "version": "3.9.6" 491 | }, 492 | "toc": { 493 | "base_numbering": 1, 494 | "nav_menu": {}, 495 | "number_sections": true, 496 | "sideBar": true, 497 | "skip_h1_title": false, 498 | "title_cell": "Table of Contents", 499 | "title_sidebar": "Contents", 500 | "toc_cell": false, 501 | "toc_position": {}, 502 | "toc_section_display": true, 503 | "toc_window_display": false 504 | } 505 | }, 506 | "nbformat": 4, 507 | "nbformat_minor": 5 508 | } 509 | -------------------------------------------------------------------------------- /exmple_in_jupyter notebook/MD_LJP.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 8, 6 | "id": "33f7674e", 7 | "metadata": { 8 | "ExecuteTime": { 9 | "end_time": "2021-09-29T06:04:28.618922Z", 10 | "start_time": "2021-09-29T05:56:19.226429Z" 11 | }, 12 | "scrolled": true 13 | }, 14 | "outputs": [ 15 | { 16 | "name": "stdout", 17 | "output_type": "stream", 18 | "text": [ 19 | "100 0.5000 -0.0000 2.2080 0.1555 0.6488 0.0920 4.6033 0.8406\n", 20 | "200 1.0000 -0.0000 2.1828 0.0220 0.6425 0.0124 4.5977 0.0897\n", 21 | "300 1.5000 0.0000 2.1793 0.0251 0.6352 0.0192 4.6146 0.1336\n", 22 | "400 2.0000 0.0000 2.1583 0.0219 0.6410 0.0173 4.5456 0.1210\n", 23 | "500 2.5000 0.0000 2.1602 0.0281 0.6447 0.0148 4.5389 0.1260\n" 24 | ] 25 | }, 26 | { 27 | "data": { 28 | "text/html": [ 29 | "
\n", 47 | " | timestep | \n", 48 | "timeNow | \n", 49 | "$\\Sigma v$ | \n", 50 | "E | \n", 51 | "$\\sigma E$ | \n", 52 | "Ek | \n", 53 | "$\\sigma Ek$ | \n", 54 | "P_1 | \n", 55 | "P_2 | \n", 56 | "
---|---|---|---|---|---|---|---|---|---|
0 | \n", 61 | "100 | \n", 62 | "0.5 | \n", 63 | "-1.776357e-17 | \n", 64 | "2.207995 | \n", 65 | "0.155526 | \n", 66 | "0.648773 | \n", 67 | "0.092044 | \n", 68 | "4.603341 | \n", 69 | "0.840562 | \n", 70 | "
1 | \n", 73 | "200 | \n", 74 | "1.0 | \n", 75 | "-2.942091e-17 | \n", 76 | "2.182844 | \n", 77 | "0.022006 | \n", 78 | "0.642484 | \n", 79 | "0.012409 | \n", 80 | "4.597668 | \n", 81 | "0.089659 | \n", 82 | "
2 | \n", 85 | "300 | \n", 86 | "1.5 | \n", 87 | "1.221245e-17 | \n", 88 | "2.179275 | \n", 89 | "0.025134 | \n", 90 | "0.635185 | \n", 91 | "0.019170 | \n", 92 | "4.614588 | \n", 93 | "0.133551 | \n", 94 | "
3 | \n", 97 | "400 | \n", 98 | "2.0 | \n", 99 | "1.706968e-17 | \n", 100 | "2.158308 | \n", 101 | "0.021944 | \n", 102 | "0.641005 | \n", 103 | "0.017318 | \n", 104 | "4.545601 | \n", 105 | "0.120993 | \n", 106 | "
4 | \n", 109 | "500 | \n", 110 | "2.5 | \n", 111 | "1.457168e-17 | \n", 112 | "2.160234 | \n", 113 | "0.028112 | \n", 114 | "0.644672 | \n", 115 | "0.014838 | \n", 116 | "4.538944 | \n", 117 | "0.126002 | \n", 118 | "