OpenMD 3.0
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
stat2visco
1#!@Python3_EXECUTABLE@
2"""Pressure Correlation function
3
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.
7
8Usage: stat2visco
9
10Options:
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
18 file)
19
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.
22
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.
26
27Example:
28 stat2visco -f ring5.stat -o ring5.pcorr -e -s
29
30"""
31
32__author__ = "Dan Gezelter (gezelter@nd.edu)"
33__version__ = "$Revision$"
34__date__ = "$Date$"
35
36__copyright__ = "Copyright (c) 2004-present The University of Notre Dame. All Rights Reserved."
37__license__ = "OpenMD"
38
39import sys
40import getopt
41import string
42import math
43
44def usage():
45 print(__doc__)
46
47def readStatFile(statFileName):
48
49 global time
50 global temperature
51 global pressure
52 global volume
53 time = []
54 temperature = []
55 pressure = []
56 volume = []
57
58 if (doShear):
59 global Pxx
60 global Pyy
61 global Pzz
62 global Pxy
63 global Pxz
64 global Pyz
65
66 Pxx = []
67 Pyy = []
68 Pzz = []
69 Pxy = []
70 Pxz = []
71 Pyz = []
72
73 statFile = open(statFileName, 'r')
74
75 print("reading File")
76 pressSum = 0.0
77 volSum = 0.0
78 tempSum = 0.0
79
80 line = statFile.readline()
81 while ("#" in line):
82 line = statFile.readline()
83
84 while True:
85 L = line.split()
86 time.append(float(L[0]))
87 temperature.append(float(L[4]))
88 #
89 # OpenMD prints out pressure in units of atm.
90 #
91 pressure.append(float(L[5]))
92 volume.append(float(L[6]))
93
94 if doShear:
95 if (len(L) > 16):
96 #
97 # OpenMD prints out the pressure tensor in units of amu*fs^-2*Ang^-1
98 #
99 Pxx.append(float(L[8]))
100 Pyy.append(float(L[12]))
101 Pzz.append(float(L[16]))
102 #
103 # symmetrize the off-diagonal terms in the pressure tensor
104 #
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])))
108 else:
109 print("Not enough columns are present in the .stat file")
110 print("to calculate the shear viscosity...")
111 print()
112 print("stat2visco expects to find all 9 elements of the")
113 print("pressure tensor in columns 9-17 of the .stat file")
114 print()
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.")
118 sys.exit()
119
120 line = statFile.readline()
121 if not line: break
122
123 statFile.close()
124
125def computeAverages():
126
127 global tempAve
128 global pressAve
129 global volAve
130 global pvAve
131
132 print("computing Averages")
133
134 tempSum = 0.0
135 pressSum = 0.0
136 volSum = 0.0
137 pvSum = 0.0
138
139 temp2Sum = 0.0
140 press2Sum = 0.0
141 vol2Sum = 0.0
142 pv2Sum = 0.0
143
144 # converts amu*fs^-2*Ang^-1 -> atm
145 pressureConvert = 1.63882576e8
146
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)
158
159 tempAve = tempSum / float(len(time))
160 pressAve = pressSum / float(len(time))
161 volAve = volSum / float(len(time))
162 pvAve = pvSum / float(len(time))
163
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)):
167 volSdev = 0.0
168 else:
169 volSdev = math.sqrt(vol2Sum / float(len(time)) - math.pow(volAve, 2))
170 pvSdev = math.sqrt(pv2Sum / float(len(time)) - math.pow(pvAve, 2))
171
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))
176
177def computeCorrelations(outputFileName):
178
179 # converts amu*fs^-2*Ang^-1 -> atm
180 pressureConvert = 1.63882576e8
181
182 # Boltzmann's constant amu*Ang^2*fs^-2/K
183 kB = 8.31451e-7
184
185 # converts amu Ang^-1 fs^-1 -> g cm^-1 s^-1
186 viscoConvert = 0.16605387
187
188 preV = viscoConvert * volAve / (kB * tempAve)
189 preVi = viscoConvert / (volAve * kB * tempAve)
190
191 if doGreenKubo:
192 gkPcorr = []
193 if doShear:
194 gkXYcorr = []
195 gkXZcorr = []
196 gkYZcorr = []
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
201 pp = 0.0
202 if doShear:
203 ppXY = 0.0
204 ppXZ = 0.0
205 ppYZ = 0.0
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
209 pp = pp + pv1*pv2
210 if doShear:
211 ppXY = ppXY + Pxy[j+i]*Pxy[j]
212 ppXZ = ppXZ + Pxz[j+i]*Pxz[j]
213 ppYZ = ppYZ + Pyz[j+i]*Pyz[j]
214
215 gkPcorr.append(pp / float(len(time) - i))
216 if doShear:
217 gkXYcorr.append(ppXY / float(len(time)-i))
218 gkXZcorr.append(ppXZ / float(len(time)-i))
219 gkYZcorr.append(ppYZ / float(len(time)-i))
220
221
222 if doEinstein:
223 print("computing Einstein-style Correlation Function")
224
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]
228 pSum = []
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 )
232
233 if doShear:
234 xySum = []
235 xySum.append(Pxy[0])
236 xzSum = []
237 xzSum.append(Pxz[0])
238 yzSum = []
239 yzSum.append(Pyz[0])
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])
244
245
246 ePcorr = []
247 dt = time[1] - time[0]
248
249 if doShear:
250 eXYcorr = []
251 eXZcorr = []
252 eYZcorr = []
253
254 # i corresponds to the total duration of the integral
255 for i in range(len(time)):
256 pIntSum = 0.0
257 if doShear:
258 xyIntSum = 0.0
259 xzIntSum = 0.0
260 yzIntSum = 0.0
261 # j corresponds to the starting point of the integral
262 for j in range(len(time) - i):
263 if (j == 0):
264 pInt = dt*pSum[j+i]
265 if doShear:
266 xyInt = dt*xySum[j+i]
267 xzInt = dt*xzSum[j+i]
268 yzInt = dt*yzSum[j+i]
269 else:
270 pInt = dt*(pSum[j+i] - pSum[j-1])
271 if doShear:
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])
275
276 pIntSum = pIntSum + pInt*pInt
277 if doShear:
278 xyIntSum = xyIntSum + xyInt*xyInt
279 xzIntSum = xzIntSum + xzInt*xzInt
280 yzIntSum = yzIntSum + yzInt*yzInt
281 ePcorr.append(pIntSum / float(len(time)-i))
282 if doShear:
283 eXYcorr.append(xyIntSum / float(len(time)-i))
284 eXZcorr.append(xzIntSum / float(len(time)-i))
285 eYZcorr.append(yzIntSum / float(len(time)-i))
286
287
288 outputFile = open(outputFileName, 'w')
289 for i in range(len(time)):
290 if doGreenKubo:
291 if doShear:
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]))
293 else:
294 outputFile.write("%f\t%13e\n" % (time[i], preVi*gkPcorr[i]))
295
296 if doEinstein:
297 if doShear:
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]))
299 else:
300 outputFile.write("%f\t%13e\n" % (time[i], 0.5*preV*ePcorr[i]))
301 outputFile.close()
302
303def main(argv):
304 global doGreenKubo
305 global doEinstein
306 global doShear
307 global haveStatFileName
308 global haveOutputFileName
309
310 haveStatFileName = False
311 haveOutputFileName = False
312 doShear = False
313 doGreenKubo = False
314 doEinstein = False
315
316 try:
317 opts, args = getopt.getopt(argv, "hgesf:o:", ["help", "green-kubo", "einstein", "shear", "stat-file=", "output-file="])
318 except getopt.GetoptError:
319 usage()
320 sys.exit(2)
321 for opt, arg in opts:
322 if opt in ("-h", "--help"):
323 usage()
324 sys.exit()
325 elif opt in ("-g", "--green-kubo"):
326 doGreenKubo = True
327 elif opt in ("-e", "--einstein"):
328 doEinstein = True
329 elif opt in ("-s", "--shear"):
330 doShear = True
331 elif opt in ("-f", "--stat-file"):
332 statFileName = arg
333 haveStatFileName = True
334 elif opt in ("-o", "--output-file"):
335 outputFileName = arg
336 haveOutputFileName = True
337 if (not haveStatFileName):
338 usage()
339 print("No stat file was specified")
340 sys.exit()
341 if (not haveOutputFileName):
342 usage()
343 print("No output file was specified")
344 sys.exit()
345
346 readStatFile(statFileName);
347 computeAverages();
348 computeCorrelations(outputFileName);
349
350if __name__ == "__main__":
351 if len(sys.argv) == 1:
352 usage()
353 sys.exit()
354 main(sys.argv[1:])