db = sql.SQLiteDB('calc.db', table='calc') idx_lst = db.get_list1d("select idx from calc") cols = [ ('etot', 'float'), # eV ('pressure', 'float'), # GPa ('volume', 'float'), # Ang**3 ('forces_rms', 'float'), # eV / Ang ('sxx', 'float'), # GPa ('syy', 'float'), # GPa ('szz', 'float'), # GPa ] db.add_columns(cols) for idx in idx_lst: print(idx) struct = io.cpickle_load('results/%i/traj.pk' % idx)[-1] db.execute("update calc set etot=? where idx==?", (struct.etot, idx)) db.execute("update calc set volume=? where idx==?", (struct.volume, idx)) db.execute("update calc set pressure=? where idx==?", (struct.pressure, idx)) db.execute("update calc set sxx=? where idx==?", (struct.stress[0, 0], idx)) db.execute("update calc set syy=? where idx==?", (struct.stress[1, 1], idx)) db.execute("update calc set szz=? where idx==?", (struct.stress[2, 2], idx)) db.execute("update calc set forces_rms=? where idx==?", (num.rms(struct.forces), idx)) db.commit()
# Load parsed results and put some values in the database. from pwtools import sql, io, num db = sql.SQLiteDB('calc.db', table='calc') idx_lst = db.get_list1d("select idx from calc") cols = [('etot', 'float'), # eV ('pressure', 'float'), # GPa ('volume', 'float'), # Ang**3 ('forces_rms', 'float'), # eV / Ang ('sxx', 'float'), # GPa ('syy', 'float'), # GPa ('szz', 'float'), # GPa ] db.add_columns(cols) for idx in idx_lst: print idx struct = io.cpickle_load('results/%i/traj.pk' %idx)[-1] db.execute("update calc set etot=? where idx==?", (struct.etot, idx)) db.execute("update calc set volume=? where idx==?", (struct.volume, idx)) db.execute("update calc set pressure=? where idx==?", (struct.pressure, idx)) db.execute("update calc set sxx=? where idx==?", (struct.stress[0,0], idx)) db.execute("update calc set syy=? where idx==?", (struct.stress[1,1], idx)) db.execute("update calc set szz=? where idx==?", (struct.stress[2,2], idx)) db.execute("update calc set forces_rms=? where idx==?", (num.rms(struct.forces), idx)) db.commit()
def __init__(self, freq, dos, temp=None, skipfreq=False, eps=1.5 * num.EPS, fixnan=False, nanfill=0.0, dosarea=None, integrator=trapz, verbose=True): """ Parameters ---------- freq : 1d array frequency f (NOT 2*pi*f) [cm^-1] dos : 1d array phonon dos such that int(freq) dos = 3*natom temp : 1d array, optional temperature range [K], if not given in the constructor then use `temp` in the calculation methods skipfreq : bool, optional Ignore frequencies and DOS values where the frequencies are negative or close to zero, i.e. all DOS curve values where `freq` < `eps`. The number and rms of the skipped values is printed if `verbose=True`. eps : float, optional Threshold for `skipfreq`. Default is ~1.5*2.2e-16 . fixnan : bool, optional Use if YKWYAD, test before using! Currently, set all NaNs occuring during integration to `nanfill`. This is a HACK b/c we must assume that these numbers should be `nanfill`. nanfill : float, optional During integration over temperature, set NaNs to this value. dosarea : float or None If not None, then re-normalize the area int(freq) dos to `dosarea`, after `skipfreq` was applied if used. integrator : callable Function which integrates x-y data. Called as ``integrator(y,x)``, like ``scipy.integrate.{trapz,simps}``. Usually, `trapz` is numerically more stable for weird DOS data and accurate enough if the freqeuency axis resolution is good. verbose : bool, optional Print warnings. Recommended for testing. Notes ----- `skipfreq` and `fixnan`: Sometimes, a few frequencies (ususally the 1st few values only) are close to zero and negative, and the DOS is very small there. `skipfreq` can be used to ignore this region. The default is False b/c it may hide large negative frequencies (i.e. unstable structure), which is a perfectly valid result (but you shouldn't do thermodynamics with that :) Even if there are no negative frequencies, you can have frequencies (usually the first) beeing exactly zero or close to that (order 1e-17). That can cause numerical problems (NaNs) in some calculations so we may skip them and their DOS values, which must be assumed to be small. If you still encounter NaNs during integration, you may use `fixnan` to set them to `nanfill`. But that is a hack. If you cannot get rid of NaNs by `skipfreq`, then your freq-dos data is probably fishy! """ # Notes # ----- # - This is actually a re-implementation of F_QHA.f90 found in Quantum # Espresso as of v4.2. # - All relations can be found in M.T. Dove, Introduction to Lattice # Dynamics, ch. 5 . # - The frequency axis "f" in cm^-1 is what QE's matdyn.x returns # when it calculates the phonon DOS (input: dos=.true.). # - For high T, Cv in units of R, the universal gas constant, should # approach 3*N where N = natom = atoms in the unit cell. This is the # Dulong-Petit limit (usually 3*N*R, here 3*N). # # Theory (example Cv): # -------------------- # # Let Z = hbar*w/(2*kb*T), D(w) = phonon dos. # Cv(T) = kb * Z**2 * Int(w) [w**2 * D(w) / sinh(z))**2] # # Cv is in J/K. To get Cv in R[J/(mol*K)], one would have to do # Cv[J/K] * Navo[1/mol] / R = Cv[J/K] / kb[J/K] # since kb = R/Navo, with # R = gas constant = 8.314 J/(mol*K) # Navo = Avogadro's number = 6e23 # # So, Cv [R] == Cv [kb]. The same holds for the entropy Svib. # # We save the division by "kb" by dropping the "kb" prefactor: # Cv(T) = Z**2 * Int(w) [w**2 * D(w) / sinh(z))**2] # ^^^^ # random note: # # in F_QHA.f90: # a3 = 1.0/8065.5/8.617e-5 # = hbar*c0*100*2*pi / kb # Did you know that? # # All formulas (cv, fvib etc) are written for angular frequency # w=2*pi*freq. Either we use hbar*w or h*freq. We do the latter. # We also convert s -> cm and keep freq in [cm^-1]. # # cm^-1 -> 1/s : * c0*100 # 1/s -> cm^-1 : / (c0*100) # s -> cm : * c0*100 # => hbar or h: J*s -> J*cm : *c0*100 self.f = freq self.dos = dos self.T = temp self.h = hplanck * c0 * 100 self.kb = kb self.fixnan = fixnan self.skipfreq = skipfreq self.verbose = verbose self.eps = eps self.nanfill = nanfill self.dosarea = dosarea self.integrator = integrator assert len(self.f) == len(self.dos), ("freq and dos don't have " "equal length") if self.verbose: print("HarmonicThermo: number of dos points: %i" % len(self.f)) if self.skipfreq: mask = self.f > self.eps if self.verbose: imask = np.invert(mask) nskip = len(imask.nonzero()[0]) if len(imask) > 0: frms = num.rms(self.f[imask]) drms = num.rms(self.dos[imask]) self._printwarn("HarmonicThermo: skipping %i dos points: " "rms(f)=%e, rms(dos)=%e" % (nskip, frms, drms)) self.f = self.f[mask] self.dos = self.dos[mask] if self.dosarea is not None: self.dos = self._norm_int(self.dos, self.f, area=float(self.dosarea))
def __init__(self, freq, dos, temp=None, skipfreq=False, eps=1.5*num.EPS, fixnan=False, nanfill=0.0, dosarea=None, integrator=trapz, verbose=True): """ Parameters ---------- freq : 1d array frequency f (NOT 2*pi*f) [cm^-1] dos : 1d array phonon dos such that int(freq) dos = 3*natom temp : 1d array, optional temperature range [K], if not given in the constructor then use `temp` in the calculation methods skipfreq : bool, optional Ignore frequencies and DOS values where the frequencies are negative or close to zero, i.e. all DOS curve values where `freq` < `eps`. The number and rms of the skipped values is printed if `verbose=True`. eps : float, optional Threshold for `skipfreq`. Default is ~1.5*2.2e-16 . fixnan : bool, optional Use if YKWYAD, test before using! Currently, set all NaNs occuring during integration to `nanfill`. This is a HACK b/c we must assume that these numbers should be `nanfill`. nanfill : float, optional During integration over temperature, set NaNs to this value. dosarea : float or None If not None, then re-normalize the area int(freq) dos to `dosarea`, after `skipfreq` was applied if used. integrator : callable Function which integrates x-y data. Called as ``integrator(y,x)``, like ``scipy.integrate.{trapz,simps}``. Usually, `trapz` is numerically more stable for weird DOS data and accurate enough if the freqeuency axis resolution is good. verbose : bool, optional Print warnings. Recommended for testing. Notes ----- `skipfreq` and `fixnan`: Sometimes, a few frequencies (ususally the 1st few values only) are close to zero and negative, and the DOS is very small there. `skipfreq` can be used to ignore this region. The default is False b/c it may hide large negative frequencies (i.e. unstable structure), which is a perfectly valid result (but you shouldn't do thermodynamics with that :) Even if there are no negative frequencies, you can have frequencies (usually the first) beeing exactly zero or close to that (order 1e-17). That can cause numerical problems (NaNs) in some calculations so we may skip them and their DOS values, which must be assumed to be small. If you still encounter NaNs during integration, you may use `fixnan` to set them to `nanfill`. But that is a hack. If you cannot get rid of NaNs by `skipfreq`, then your freq-dos data is probably fishy! """ # Notes # ----- # - This is actually a re-implementation of F_QHA.f90 found in Quantum # Espresso as of v4.2. # - All relations can be found in M.T. Dove, Introduction to Lattice # Dynamics, ch. 5 . # - The frequency axis "f" in cm^-1 is what QE's matdyn.x returns # when it calculates the phonon DOS (input: dos=.true.). # - For high T, Cv in units of R, the universal gas constant, should # approach 3*N where N = natom = atoms in the unit cell. This is the # Dulong-Petit limit (usually 3*N*R, here 3*N). # # Theory (example Cv): # -------------------- # # Let Z = hbar*w/(2*kb*T), D(w) = phonon dos. # Cv(T) = kb * Z**2 * Int(w) [w**2 * D(w) / sinh(z))**2] # # Cv is in J/K. To get Cv in R[J/(mol*K)], one would have to do # Cv[J/K] * Navo[1/mol] / R = Cv[J/K] / kb[J/K] # since kb = R/Navo, with # R = gas constant = 8.314 J/(mol*K) # Navo = Avogadro's number = 6e23 # # So, Cv [R] == Cv [kb]. The same holds for the entropy Svib. # # We save the division by "kb" by dropping the "kb" prefactor: # Cv(T) = Z**2 * Int(w) [w**2 * D(w) / sinh(z))**2] # ^^^^ # random note: # # in F_QHA.f90: # a3 = 1.0/8065.5/8.617e-5 # = hbar*c0*100*2*pi / kb # Did you know that? # # All formulas (cv, fvib etc) are written for angular frequency # w=2*pi*freq. Either we use hbar*w or h*freq. We do the latter. # We also convert s -> cm and keep freq in [cm^-1]. # # cm^-1 -> 1/s : * c0*100 # 1/s -> cm^-1 : / (c0*100) # s -> cm : * c0*100 # => hbar or h: J*s -> J*cm : *c0*100 self.f = freq self.dos = dos self.T = temp self.h = hplanck * c0 * 100 self.kb = kb self.fixnan = fixnan self.skipfreq = skipfreq self.verbose = verbose self.eps = eps self.nanfill = nanfill self.dosarea = dosarea self.integrator = integrator assert len(self.f) == len(self.dos), ("freq and dos don't have " "equal length") if self.verbose: print "HarmonicThermo: number of dos points: %i" %len(self.f) if self.skipfreq: mask = self.f > self.eps if self.verbose: imask = np.invert(mask) nskip = len(imask.nonzero()[0]) if len(imask) > 0: frms = num.rms(self.f[imask]) drms = num.rms(self.dos[imask]) self._printwarn("HarmonicThermo: skipping %i dos points: " "rms(f)=%e, rms(dos)=%e" %(nskip, frms, drms)) self.f = self.f[mask] self.dos = self.dos[mask] if self.dosarea is not None: self.dos = self._norm_int(self.dos, self.f, area=float(self.dosarea))