计算化学公社

标题: 谈谈RDF [打印本页]

作者
Author:
丁越    时间: 2022-5-18 18:53
标题: 谈谈RDF
本帖最后由 丁越 于 2022-6-14 13:23 编辑

谈谈RDF


*****************************************************
2022.6.14注: 重新改写了脚本
*****************************************************

RDF(radial distribution function)径向分布函数(或称对相关函数),其含义是每个球层位置的被计算组的原子的数密度与其平均数密度的比值,描述密度如何因距离参考粒子的距离而变化。其中被计算组的平均数密度为被计算组粒子的个数除以盒子的体积。给出的g(r)~r图中横坐标是距参考粒子的距离,纵坐标指相对于盒子里被计算的粒子的平均密度的比值。计算RDF时需要定义盒子的周期性。

根据RDF的含义,我们将RDF公式定义如下:

(, 下载次数 Times of downloads: 103)

其中,rho_ab(r)的含义为距参考粒子r处的球层内计算组粒子的数密度,分母项是计算组粒子的平均数密度。我们将这一公式进一步扩展,

(, 下载次数 Times of downloads: 86)

(, 下载次数 Times of downloads: 80)

便得到了如何由轨迹文件求得RDF,上面公式来源于该篇文献(J. Chem. Inf. Model. 2011, 51, 2007–2023)。上式中,a为参考组粒子,b为计算组粒子,V是盒子的体积。式中第一项求和符号循环所有的参考组粒子,第二个求和符号循环所有的计算组粒子。在t时刻,距参考粒子a_i半径为r,厚度为dr的球壳内粒子b的平均数密度是通过遍历所有b粒子的δ(dr)函数然后取平均求得(b粒子如果在dr厚度球层内统计数目加1,否则为0)。如果要对整个轨迹求平均的话代码中需要嵌套循环所有帧。接着再给最外层套上循环所有参考粒子a,然后再除以a粒子数目Na求取平均,这样就到了了距a半径为r处发现b粒子的平均数密度,最后再除以b粒子的平均数密度(N_b/V)便得到了g(r)的值。(PS:公式中δ函数是统计数目的,但是写代码时得除以球层体积来得到球层中b的数密度,我不清楚公式中为什么不写上除以球层体积?)。弄明白RDF计算的基本原理后,利用VMD求解RDF的TCL语言代码如下所示:

  1. #This script is used to calculate the pair radial distribution function.
  2. #NOTE: PBC conditions must be correctly setted in VMD otherwise the results will be meaningless.

  3. #**********PARAMETERS***********
  4. set refatm "element O"
  5. set calcatm "element O"
  6. set dr 0.1
  7. set maxr 5
  8. set begframe 0
  9. set endframe -1
  10. set stride 1
  11. set fileid [open rdf.dat w]
  12. #*******************************
  13. #                PART 1-calculate RDF
  14. #*******************************
  15. set nframe [molinfo top get numframes]
  16. if { $endframe == -1 } {set endframe [expr $nframe-1]}
  17. set totframe [expr int(double($endframe-$begframe)/$stride)+1]
  18. set refsel [atomselect top "$refatm"]
  19. set Nref [$refsel num]
  20. set calcsel [atomselect top "$calcatm"]
  21. set Ncalc [$calcsel num]
  22. set nbin [expr int(double($maxr)/$dr)]
  23. set rtmp 0
  24. set pi 3.1415926

  25. set l [molinfo top get a]
  26. set w [molinfo top get b]
  27. set h [molinfo top get c]
  28. set V [expr $l*$w*$h]
  29. set rho_calc [expr double($Ncalc)/$V]

  30. for {set i 1} {$i<=$nbin} {incr i} {
  31.         set N($i) 0
  32. }

  33. for {set i $begframe} {$i<=$endframe} {incr i $stride} {
  34.         puts -nonewline [format "      Now is calculating %i_th frames.....\r" $i]
  35.         for {set j 1} {$j<$nbin} {incr j} {
  36.                 foreach k [$refsel get index] {
  37.                         set sel1 [atomselect top "$calcatm && pbwithin $rtmp of index $k"]
  38.                         set sel2 [atomselect top "$calcatm && pbwithin [expr $rtmp+$dr] of index $k"]
  39.                         $sel1 frame $i
  40.                         $sel2 frame $i
  41.                         $sel1 update
  42.                         $sel2 update
  43.                         set N($j) [expr [$sel2 num]-[$sel1 num]+$N($j)]
  44.                 }
  45.                 set Vtmp [expr 4.0/3.0*$pi*(3.0*($rtmp)**2 * $dr + 3.0*($dr)**2 * $rtmp + ($dr)**3)]
  46.                 set rmid [expr ($j-0.5)*$dr]
  47.                 set avgN($j) [expr double($N($j))/$Nref]
  48.                 set (gtmp$rmid,frame$i) [expr double($avgN($j))/($rho_calc*$Vtmp)]
  49.                 set rtmp [expr $j*$dr]
  50.         }
  51.         set rtmp 0
  52.         for {set h 1} {$h<$nbin} {incr h} {
  53.                 set N($h) 0
  54.                 set avgN($h) 0
  55.         }
  56. }

  57. for {set i 1} {$i<$nbin} {incr i} {
  58.         set rmid [expr ($i-0.5)*$dr]
  59.         set g($rmid) 0
  60. }

  61. for {set i 1} {$i<$nbin} {incr i} {
  62.         set rmid [expr ($i-0.5)*$dr]
  63.         for {set j $begframe} {$j<=$endframe} {incr j $stride} {
  64.                 set g($rmid) [expr $g($rmid)+$(gtmp$rmid,frame$j)]
  65.         }
  66.         puts $fileid "$rmid \t [expr double($g($rmid))/$totframe]"
  67. }
  68. close $fileid

  69. #******************************
  70. #                PART 2-integral rdf
  71. #******************************
  72. set fileid2 [open int_rdf.dat w]
  73. set fileid3 [open rdf.dat r]
  74. #******************************
  75. set iline 0

  76. while { [gets $fileid3 lval] > 0 } {
  77.         set iline [expr $iline+1]
  78.         set lval1 [lindex $lval 0]
  79.         set lval2 [lindex $lval 1]
  80.         set tmp1($iline) $lval1
  81.         set tmp2($iline) $lval2        
  82. }

  83. set tmp1(0) 0
  84. set tmp2(0) 0
  85. set intval 0
  86. foreach i [lsort -increasing -int [array names tmp1]] {
  87.         if { $i < [lindex [lsort -decreasing -int [array names tmp1]] 1] } {
  88.                 set valtmp1 [expr 0.5*($tmp1($i)+$tmp1([expr $i+1]))]
  89.                 set valtmp2 [expr 0.5*($tmp2($i)+$tmp2([expr $i+1]))]
  90.                 set intvaltmp [expr 4*$pi*($valtmp1)**2*$dr*$valtmp2*$rho_calc]
  91.                 set intval [expr $intvaltmp+$intval]
  92.                 puts $fileid2 "$valtmp1 \t $intval"
  93.         }
  94. }
  95. close $fileid2
  96. close $fileid3
复制代码


代码中34~55行是求解RDF的关键步骤,此处设定了三个循环,第一个for循环循环r从0到rmax的径向距离,第二个foreach循环我们遍历所有的参考组粒子a_i。第三个最内层for循环我们循环所有帧,然后累加在r_i处,以a_i为参考粒子,dr厚度球层内粒子的数目。统计球层粒子的数目我们使用了pbwithin原子选择语法,先用pbwithin得到r_i半径内粒子的数目,然后再得到r_i+dr半径内粒子数目,二者做差就是dr球层内粒子的数目。下面是一个单层Fe原子的测试样本,我们顺便对比了一下和VMD自带的RDF插件统计结果的差异:
(, 下载次数 Times of downloads: 79)
(, 下载次数 Times of downloads: 66)
图. Fe-Fe的RDF。蓝色线的为脚本计算结果。黑色线为VMD的RDF插件计算结果。

由上图中可以看出每个Fe原子存在着三种不同配位形式的Fe原子,即相邻距离不等的Fe原子(图中相邻Fe原子间距分别为2.58,3.65,4.47),因而RDF图中出现了三种峰。

最后再讨论一下RDF中统计的最远径向距离rmax的问题,即取值半径rmax不能超过盒子最小边长的一半。下图中蓝色圈是r=lattice/2,红色圈大小超过了盒子最小边长的一半,此时半径内包含了镜像粒子(如红色圆圈中两个互为镜像的粒子)。所以当r<lattice/2时,在任意ri处统计的粒子均是属于盒子内的粒子本身而不含有其镜像粒子。而当r>lattice/2时,在g(ra)处统计的计算组粒子数目中额外计入了一个和rb处粒子互为镜像的粒子,显然这样的统计是没有意义的。不知道我理解的对不对,欢迎大家的讨论!
(, 下载次数 Times of downloads: 56)










作者
Author:
丁越    时间: 2022-5-19 16:17
更正了一下脚本代码中的错误。
作者
Author:
王国庆    时间: 2022-12-3 16:56
麻烦请教下  该脚本支持非正交体系的计算吗?
作者
Author:
丁越    时间: 2022-12-3 20:11
王国庆 发表于 2022-12-3 16:56
麻烦请教下  该脚本支持非正交体系的计算吗?

不支持,你可以改写一下。

另外脚本里面应该加上截断半径,否则循环所有粒子计算量很大,我当时写的时侯没考虑到这点。。
作者
Author:
lei234    时间: 2023-5-31 11:43
请问下,怎么设置截断半径和那个bin width呢?感谢!!
作者
Author:
LU_    时间: 2023-12-30 01:56
您好,关于您在文章末尾提到截断半径=lattice/2,是因为多计入了一个镜像粒子导致式子没有意义,由于我也是刚学,我感觉您说的这种情况只会在盒子的边界出现,我的理解是因为盒子具有周期性,所以当从r>lattice/2开始其实会发生周期性重复,就是说其实之前这个距离的情况已经考虑过了,比如r1=lattice+1的rdf算出来应该与r2 =1的情况一致,也就是r = |r-lattice| ,在这种情况下只有r<lattice/2才有意义,当然我也是猜的,请您批评指正。[url=]图片 Image[/url]
作者
Author:
丁越    时间: 2023-12-31 09:25
LU_ 发表于 2023-12-30 01:56
您好,关于您在文章末尾提到截断半径=lattice/2,是因为多计入了一个镜像粒子导致式子没有意义,由于我也是 ...

这个问题你可以参考一下Andrew R.Leach 的“Molecular modeling, principles and applications”书中第324页,里面对minimum image convention有详细的描述。
(, 下载次数 Times of downloads: 45)





作者
Author:
LU_    时间: 2023-12-31 09:43
丁越 发表于 2023-12-31 09:25
这个问题你可以参考一下Andrew R.Leach 的“Molecular modeling, principles and applications”书中第32 ...

好的好的,非常感谢
作者
Author:
ZhangChuanzheng    时间: 2024-3-15 13:12
我有一个不同的看法,我认为应该将镜像粒子计入,出发点在于模型盒子里面的粒子也都会受到相邻周期性盒子内粒子的对其的作用力,如果互为镜像的两个粒子与参考粒子的距离相同,则这两个粒子在对参考粒子的受力大小上面没有区别,RDF描述的就是相互作用关系,因此计入镜像粒子不算是额外的,此外,如果一个参考粒子位于模拟盒子的边界(假设是XY1面),此时在计算时,假设有一个粒子位于XY2面,则该粒子就应该是距离参考粒子的距离为Z的球壳上,然而其有一个位于距离参考粒子极小的球壳内的镜像粒子,那么此时我们应该将该粒子计入参考粒子的哪个球壳内呢?我认为应该两个都计入,因为如果只存在一个的话,参考粒子的位置就大概率不在此处。也就是说在计算时,粒子本身和镜像粒子都是客观存在的。所以如果互为镜像的两个粒子与参考粒子距离相同,那也是参考粒子在那个半径球壳内客观存在的。
我不知道我这个理解是否正确,如有错误,欢迎大家的批评指正,谢谢
作者
Author:
yjb    时间: 2025-3-31 22:26
老师,您好。我在研究烷烃体系随温度变化的结晶行为分子动力学模拟,用gromacs自带的rdf,做了C16H34分子的不同温度下rdf。现在不明白 RDF图r<0.5mm,尖峰重叠问题。
作者
Author:
hdhxx123    时间: 2025-3-31 23:04
好物,要是在本科毕业的时候看到,毕设能写得更完善。




欢迎光临 计算化学公社 (http://bbs.keinsci.com/) Powered by Discuz! X3.3