3__author__ = "Dan Gezelter (gezelter@nd.edu)"
4__copyright__ = "Copyright (c) 2004-present The University of Notre Dame. All Rights Reserved."
11from argparse import RawDescriptionHelpFormatter
13def readStatFile(statFileName):
25 statFile = open(statFileName, 'r')
28 line = statFile.readline()
30 line = statFile.readline()
35 # OpenMD prints out the pressure tensor in units of amu*fs^-2*Ang^-1
37 TimeStamp.append(float(L[0]))
38 Pxx.append(float(L[8]))
39 Pyy.append(float(L[12]))
40 Pzz.append(float(L[16]))
42 print("Not enough columns are present in the .stat file")
43 print("to calculate the shear viscosity...")
45 print("stat2tension expects to find all 9 elements of the")
46 print("pressure tensor in columns 9-17 of the .stat file")
48 print("You may need to set the statFileFormat string")
49 print("explicitly in your .omd file when running OpenMD.")
50 print("Consult the OpenMD documentation for more details.")
53 line = statFile.readline()
58def computeAverages(Lz, outFileName):
60 print("computing Averages")
62 outFile = open(outFileName, 'w')
63 outFile.write("# Time \t Surface Tension \n")
66 # converts amu fs^-2 to milli N / m (a common surface tension unit)
67 gammaConvert = 1.660539040e6
71 for i in range(len(Pzz)):
72 instaGamma = gammaConvert * Lz * 0.5 * (Pzz[i] - 0.5 * (Pxx[i] + Pyy[i]))
73 gammaSum = gammaSum + instaGamma
74 gamma2Sum = gamma2Sum + instaGamma * instaGamma
76 gammaAve = gammaSum / float(i+1)
77 outFile.write(str(TimeStamp[i]) + "\t" + str(gammaAve) + "\n")
80 gammaAve = gammaSum / float(len(Pzz))
81 gammaSdev = math.sqrt(gamma2Sum / float(len(Pzz)) - math.pow(gammaAve, 2))
82 gammaErr = gammaSdev * 1.96 / math.sqrt(len(Pzz))
84 print("Average surface tension = %f +/- %f (mN/m)" % (gammaAve, gammaErr))
90 parser = argparse.ArgumentParser(prog="stat2tension",
91 formatter_class=argparse.RawDescriptionHelpFormatter,
93This script accumulates the surface tension from an OpenMD stat file
94that has been run with PRESSURE_TENSOR added to the statFileFormat.
96This script assumes that the interface is normal to the z-axis, so
100and that the tangential contributions are averaged over the remaining axes:
102 Pt(z) = (Pxx + Pyy) / 2
104The surface tension is defined using the normal and tangential components:
106 \gamma = \int_{-\infty}^{\infty} (Pn - Pt(z)) dz
108The tangential pressure is different from the normal pressure only in
109the vicinity of the interfaces, so the net surface tension for the
110system can be simplified:
112 \gamma = Lz (Pn - <Pt>)
114where <Pt> is the statistical average of the tangential pressure.
116In practice, many surface tension simulations comprise two regions,
117with one material in each region. Periodic boundary conditions then
118require two interfaces, so
120 \gamma = Lz (Pn - <Pt>)
122For more details: Vazquez, U.O.M., Shinoda, W., Moore, P.B. et al.
123J Math Chem (2009) 45: 161. doi:10.1007/s10910-008-9374-7
125 epilog="Example: stat2tension -s iceWater.stat -z 120.45 -o iceWater.tens")
127 parser.add_argument("-s", "--stat-file=",
128 action="store", required=True, dest="statFileName",
129 help="use specified stat (.stat) file")
131 parser.add_argument("-z", "--box-length=",
132 action="store", required=True, dest="Lz", type=float,
133 help="dimension of the box in the normal (z) direction")
134 parser.add_argument("-o", "--output-file=",
135 action="store", required=True, dest="outFileName",
136 help="specified output (.tens) file")
139 if len(sys.argv) == 1:
142 args = parser.parse_args()
144 if (not args.statFileName):
146 parser.error("No stat file name was specified")
150 parser.error("No box z-length was specified")
152 if (not args.outFileName):
154 parser.error("No outpuf file name was specified")
156 readStatFile(args.statFileName)
157 computeAverages(args.Lz, args.outFileName)
159if __name__ == "__main__":