I am not much experienced in Python, just write some small script. All my codes are procedural. They work fine, and I always check them with pep8
.
One of them is:
#!/usr/bin/python3
import os
import sys
import numpy as np
import scipy as sp
import scipy.optimize
import matplotlib.pyplot as plt
def f(x, a, b, c, d):
return a + b*x + c*x**2 + d*x**3
data = []
fout = "tmpft" # sys.argv[1] + "_trial.dat"
with open(fout, "w") as of:
for subdir, dirs, files in os.walk(sys.argv[1]):
for inp in files:
if inp.endswith("SCF.out"):
fsys = subdir + "/" + inp
# print(fsys)
with open(fsys) as finp:
for line in finp:
if "lattice constant ALAT" in line:
lata = float(line.strip()[-7:])/1.88973
if " ERR " in line:
mom = line.strip()[61:70]
if "SCF - cycle converged" in line:
etot = float(line.lstrip()[10:25])
of.write("{:<10f} {:<15f} {:<15f}\n"
.format(lata, etot, float(mom)))
ffout = sys.argv[1]+".dat"
with open(ffout, "w") as ff:
ff.write("#lat(A) ETOT MOM\n")
with open(fout, "r") as uns:
for line in sorted(uns):
ff.write(line)
values = np.genfromtxt(fout, dtype=None, delimiter=' ', usecols=[0, 1, 2])
os.remove(fout)
etot = values[:, 1]
latp = values[:, 0]
popt, pcov = sp.optimize.curve_fit(f, latp, etot)
res = sp.optimize.minimize(lambda x: f(x, *popt), 2.8)
print('Function is minimized for {0}.'.format(float(res['x'])))
with open(ffout, 'a') as ff:
ff.write('#Function is minimized for {0}\n'.format(float(res['x'])))
# Plot data
pout = sys.argv[1]+".png"
x = sp.linspace(2.80, 3.05, 100)
y = f(x, *popt)
plt.plot(x, y, lw=3)
plt.xlabel("Lattice Parameter")
plt.ylabel("Energy")
plt.title(sys.argv[1])
plt.scatter(latp, etot, s=60)
plt.scatter(res['x'], f(res['x'], *popt), color='red', s=80)
plt.savefig(pout)
plt.show()
This works fine, i.e. gives me proper/correct result. But I wonder if this is a good way of writing Python. If I take this as my standard example (most of my Python interaction is like this: read a file, fetch some data, post-process it and plot), how I can make it better? By "better", I mean, optimized, reusable and readable.
Like, as I already said, most of my python involves reading a line that matched a string. So, I would like to have it as a function (in C/fortran sense) etc.