2"""Pressure Correlation function
4Computes various correlation functions of the pressure and pressure tensor
5that have been stored in a stat file. These can be used to compute
6shear and bulk viscosities.
11 -h, --help show this help
12 -f, --stat-file=... use specified stat file
13 -o, --output-file=... use specified output (.pcorr) file
14 -g, --green-kubo use Green-Kubo formulae (noisy!)
15 -e, --einstein use Einstein relation (best)
16 -s, --shear compute the shear viscosity (the off-diagonal
17 pressure tensor values must be present in the .stat
20The Green-Kubo formulae option will compute: V*<(P(t)-<P>)*(P(0)-<P>)>/kT ,
21which may be integrated to give a slowly-converging value for the viscosity.
23The Einstein relation option will compute: V*<(\int_0^t (P(t')-<P>)dt')^2>/2kT,
24which will grow approximately linearly in time. The long-time slope of this
25function will be the viscosity.
28 stat2visco -f ring5.stat -o ring5.pcorr -e -s
32__author__ = "Dan Gezelter (gezelter@nd.edu)"
33__version__ = "$Revision$"
36__copyright__ = "Copyright (c) 2004-present The University of Notre Dame. All Rights Reserved."
47def readStatFile(statFileName):
73 statFile = open(statFileName, 'r')
80 line = statFile.readline()
82 line = statFile.readline()
86 time.append(float(L[0]))
87 temperature.append(float(L[4]))
89 # OpenMD prints out pressure in units of atm.
91 pressure.append(float(L[5]))
92 volume.append(float(L[6]))
97 # OpenMD prints out the pressure tensor in units of amu*fs^-2*Ang^-1
99 Pxx.append(float(L[8]))
100 Pyy.append(float(L[12]))
101 Pzz.append(float(L[16]))
103 # symmetrize the off-diagonal terms in the pressure tensor
105 Pxy.append(0.5*(float(L[9]) + float(L[11])))
106 Pxz.append(0.5*(float(L[10]) + float(L[14])))
107 Pyz.append(0.5*(float(L[13]) + float(L[15])))
109 print("Not enough columns are present in the .stat file")
110 print("to calculate the shear viscosity...")
112 print("stat2visco expects to find all 9 elements of the")
113 print("pressure tensor in columns 9-17 of the .stat file")
115 print("You may need to set the statFileFormat string")
116 print("explicitly in your .omd file when running OpenMD.")
117 print("Consult the OpenMD documentation for more details.")
120 line = statFile.readline()
125def computeAverages():
132 print("computing Averages")
144 # converts amu*fs^-2*Ang^-1 -> atm
145 pressureConvert = 1.63882576e8
147 for i in range(len(time)):
148 tempSum = tempSum + temperature[i]
149 pressSum = pressSum + pressure[i]
150 volSum = volSum + volume[i]
151 # in units of amu Ang^2 fs^-1
152 pvTerm = pressure[i]*volume[i] / pressureConvert
153 pvSum = pvSum + pvTerm
154 temp2Sum = temp2Sum + math.pow(temperature[i], 2)
155 press2Sum = press2Sum + math.pow(pressure[i], 2)
156 vol2Sum = vol2Sum + math.pow(volume[i], 2)
157 pv2Sum = pv2Sum + math.pow(pvTerm, 2)
159 tempAve = tempSum / float(len(time))
160 pressAve = pressSum / float(len(time))
161 volAve = volSum / float(len(time))
162 pvAve = pvSum / float(len(time))
164 tempSdev = math.sqrt(temp2Sum / float(len(time)) - math.pow(tempAve, 2))
165 pressSdev = math.sqrt(press2Sum / float(len(time)) - math.pow(pressAve, 2))
166 if (vol2Sum / float(len(time)) < math.pow(volAve, 2)):
169 volSdev = math.sqrt(vol2Sum / float(len(time)) - math.pow(volAve, 2))
170 pvSdev = math.sqrt(pv2Sum / float(len(time)) - math.pow(pvAve, 2))
172 print(" Average pressure = %f +/- %f (atm)" % (pressAve, pressSdev))
173 print(" Average volume = %f +/- %f (Angst^3)" % (volAve, volSdev))
174 print("Average temperature = %f +/- %f (K)" % (tempAve, tempSdev))
175 print(" Average PV product = %f +/- %f (amu Angst^2 fs^-1)" % (pvAve, pvSdev))
177def computeCorrelations(outputFileName):
179 # converts amu*fs^-2*Ang^-1 -> atm
180 pressureConvert = 1.63882576e8
182 # Boltzmann's constant amu*Ang^2*fs^-2/K
185 # converts amu Ang^-1 fs^-1 -> g cm^-1 s^-1
186 viscoConvert = 0.16605387
188 preV = viscoConvert * volAve / (kB * tempAve)
189 preVi = viscoConvert / (volAve * kB * tempAve)
197 print("computing Green-Kubo-style Correlation Function")
198 # i corresponds to dt
199 for i in range(len(time)):
200 # j is the starting time for the correlation
206 for j in range( len(time) - i ):
207 pv1 = pressure[j]*volume[j]/pressureConvert - pvAve
208 pv2 = pressure[j+i]*volume[j+i]/pressureConvert - pvAve
211 ppXY = ppXY + Pxy[j+i]*Pxy[j]
212 ppXZ = ppXZ + Pxz[j+i]*Pxz[j]
213 ppYZ = ppYZ + Pyz[j+i]*Pyz[j]
215 gkPcorr.append(pp / float(len(time) - i))
217 gkXYcorr.append(ppXY / float(len(time)-i))
218 gkXZcorr.append(ppXZ / float(len(time)-i))
219 gkYZcorr.append(ppYZ / float(len(time)-i))
223 print("computing Einstein-style Correlation Function")
225 # Precompute sum variables to aid integration.
226 # The integral from t0 -> t0 + t can be easily obtained
227 # from the precomputed sum variables: sum[t0+t] - sum[t0-1]
229 pSum.append( (pressure[0] - pressAve) / pressureConvert)
230 for i in range(1, len(time)):
231 pSum.append(pSum[i-1] + (pressure[i]-pressAve)/pressureConvert )
240 for i in range(1, len(time)):
241 xySum.append(xySum[i-1] + Pxy[i])
242 xzSum.append(xzSum[i-1] + Pxz[i])
243 yzSum.append(yzSum[i-1] + Pyz[i])
247 dt = time[1] - time[0]
254 # i corresponds to the total duration of the integral
255 for i in range(len(time)):
261 # j corresponds to the starting point of the integral
262 for j in range(len(time) - i):
266 xyInt = dt*xySum[j+i]
267 xzInt = dt*xzSum[j+i]
268 yzInt = dt*yzSum[j+i]
270 pInt = dt*(pSum[j+i] - pSum[j-1])
272 xyInt = dt*(xySum[j+i] - xySum[j-1])
273 xzInt = dt*(xzSum[j+i] - xzSum[j-1])
274 yzInt = dt*(yzSum[j+i] - yzSum[j-1])
276 pIntSum = pIntSum + pInt*pInt
278 xyIntSum = xyIntSum + xyInt*xyInt
279 xzIntSum = xzIntSum + xzInt*xzInt
280 yzIntSum = yzIntSum + yzInt*yzInt
281 ePcorr.append(pIntSum / float(len(time)-i))
283 eXYcorr.append(xyIntSum / float(len(time)-i))
284 eXZcorr.append(xzIntSum / float(len(time)-i))
285 eYZcorr.append(yzIntSum / float(len(time)-i))
288 outputFile = open(outputFileName, 'w')
289 for i in range(len(time)):
292 outputFile.write("%f\t%13e\t%13e\t%13e\t%13e\n" % (time[i], preVi*gkPcorr[i], preV*gkXYcorr[i], preV*gkXZcorr[i], preV*gkYZcorr[i]))
294 outputFile.write("%f\t%13e\n" % (time[i], preVi*gkPcorr[i]))
298 outputFile.write("%f\t%13e\t%13e\t%13e\t%13e\n" % (time[i], 0.5*preV*ePcorr[i], 0.5*preV*eXYcorr[i], 0.5*preV*eXZcorr[i], 0.5*preV*eYZcorr[i]))
300 outputFile.write("%f\t%13e\n" % (time[i], 0.5*preV*ePcorr[i]))
307 global haveStatFileName
308 global haveOutputFileName
310 haveStatFileName = False
311 haveOutputFileName = False
317 opts, args = getopt.getopt(argv, "hgesf:o:", ["help", "green-kubo", "einstein", "shear", "stat-file=", "output-file="])
318 except getopt.GetoptError:
321 for opt, arg in opts:
322 if opt in ("-h", "--help"):
325 elif opt in ("-g", "--green-kubo"):
327 elif opt in ("-e", "--einstein"):
329 elif opt in ("-s", "--shear"):
331 elif opt in ("-f", "--stat-file"):
333 haveStatFileName = True
334 elif opt in ("-o", "--output-file"):
336 haveOutputFileName = True
337 if (not haveStatFileName):
339 print("No stat file was specified")
341 if (not haveOutputFileName):
343 print("No output file was specified")
346 readStatFile(statFileName);
348 computeCorrelations(outputFileName);
350if __name__ == "__main__":
351 if len(sys.argv) == 1: