pwtools.thermo.Gibbs¶
- class pwtools.thermo.Gibbs(T=None, P=None, etot=None, phdos=None, axes_flat=None, volfunc_ax=None, case=None, **kwds)[source]¶
Bases:
object
Calculate thermodynamic properties on a T-P grid in the quasiharmonic approximation, given some variation grid of unit cell axes (axes_flat) and corresponding phonon DOS data for each grid point.
The axes_flat approach allows us to easily calculate per-axis thermal expansion rates.
We have 3 cases for how unit cell axis can be be varied.
case
axes_flat.shape
cell parameter grid
fitfunc
bulk modulus
1d
(N,) or (N,1)
ax0 = a (-> V) (e.g. cubic or rhombohedral)
G(V), thus any EOS will do
V*d^2G/dV^2
2d
(N,2)
(ax0,ax1) = (a,b), (a,c) or (b,c) (e.g. hexagonal: (a,c))
G(ax0, ax1)
not defined
3d
(N,3)
(ax0,ax1,ax2) (e.g. triclinic)
no default
not defined
Internally, we only deal with ax0 (1d), ax0 + ax1 (2d) and ax0 + ax1 + ax2 (3d), thus for 2d and 3d it doesn’t matter which cell axes is which, you just have to remember :)
Notes
Functions for fitting G(V), V(T) etc are defined in a dictionary attribute
fitfunc
. This is a dict with functions, which have the signaturefunc(x,y)
. The functions get x-y type data and return a class instance. The instances must be aSpline
-like object with aget_min()
method. The__call__()
method must accept a keyword der for calculating derivatives in some cases. See self._default_fit_* to get an idea: for 1dSpline
orPolyFit1D
, for 2d:PolyFit
orInterpol2D
. See alsoscipy.interpolate
. Useset_fitfunc()
to change. This can (and should!) be used to tune fitting methods. See examples below for how to change fit functions.Here is a list of all valid fitfunc keys and what they do:
key
value
‘1d-G’
fit G(V),
__call__(V,der=2)
for B(V) = V*d^2G/dV^2‘2d-G’
fit G(ax0,ax1)
‘3d-G’
fit G(ax0,ax1,ax2), no default, define and test youself, please
‘1d-ax’
fit V(ax0)
‘alpha’
fit x_opt(T), x=ax0,ax1,ax2,V,
__call__(T,der=1)
for alpha_x = 1/x * dx/dT‘C’
fit G_opt(T),
__call__(T,der=2)
for Cp = -T * d^G_opt(T,P)/dT^2Hints for which fitfuncs to choose: The defaults are pretty good, but nevertheless testing is mandatory! Good choices are
PolyFit
/PolyFit1D
for all axes-related grids (1d-G, 2d-G, 1d-ax) since you won’t have too many points here. Then a fit is better than aSpline
. Always usePolyFit(..., scale=True)
or scale the x-y data manually before fitting to the same order of magnitude! For T grids, choose a very fine T-axis (e.g.T=linspace(.., num=300)
and use aSpline
. Needed to resolve details of alpha(T) and C(T).The methods
calc_F()
,calc_H()
andcalc_G()
return dicts with nd-arrays holding calculated thermodynamic properties. Naming convention for dict keys returned by methods: The keys (strings) mimic HDF5 path names, e.g./group0/group1/array
, thus the last name in the path is the name of the array (z in the examples below). All previous names define the grid and thus the dimension of the array. A group name starting with “#” is just a prefix. Below, na=len(a), etc.key
ndim
shape
description
/a/z
1d
(na,)
z on 1d a-grid
/a/b/z
2d
(na,nb)
z on 2d a-b grid
/a/b/c/z
3d
(na,nb,nc)
z on 3d a-b-c grid
/a-b/z
1d
(na*nb,)
z on flattened a-b grid
/a-b-c/z
1d
(na*nb*nc,)
z on flattened a-b-c grid
/#opt/a/z
1d
(na,)
optimized z on a-grid
axes_flat : Usually, flat grids like “ax0-ax1” or “ax0-ax1-ax2” are created by nested loops
[(ax0_i,ax1_i) for ax0_i in ax0 for ax1_i in ax1]
and therefore have shape (nax0*nax1,2) or (nax0*nax1*nax2,3) . But that is not required. They can be completely unstructured (e.g. if points have been added later to the grid manually) – only fitfunc must be able to handle that.Units
B,P
GPa
T
K
F,G
eV
ax{0,1,2}
Ang
Cv,Cp
R (8.4314 J/(mol*K))
alpha_{V,ax{0,1,2}}
1/K
Examples
See
test/test_gibbs.py
for worked examples using fake data. Really, go there and have a look. Now!>>> from pwtools import mpl, crys, eos >>> # cubic cell, 1d case >>> volfunc_ax = lambda x: crys.volume_cc(np.array([[x[0]]*3 + [90]*3])) >>> gibbs=Gibbs(axes_flat=..., etot=..., phdos=..., ... T=linspace(5,2500,100), P=linspace(0,20,5), ... volfunc_ax=volfunc_ax) >>> # EOS fit for G(V), polynomial for heat capacity (default is Spline) >>> gibbs.set_fitfunc('C', lambda x,y: num.PolyFit1D(x,y,deg=5,scale=True)) >>> gibbs.set_fitfunc('1d-G', lambda x,y: eos.EosFit(x,y)) >>> g = gibbs.calc_G(calc_all=True) >>> # 1d case >>> V = g['/ax0/V']; G=g['/T/P/ax0/G']; T=g['/T/T'] >>> # plot G(V) for all T and P=20 GPa >>> plot(V, G[:,-1,:].T) >>> # Cp(T) for all P >>> plot(T,g['/#opt/T/P/Cp']) >>> # 2d case plot G(ax0,ax1) for T=2500 K, P=0 GPa >>> G=g['/T/P/ax0-ax1/G'] >>> d=mpl.Data2D(XY=axes_flat, zz=G[-1,0,:]) >>> fig,ax=mpl.fig_ax3d(); ax.scatter(d.xx,d.yy,d.zz); show()
- __init__(T=None, P=None, etot=None, phdos=None, axes_flat=None, volfunc_ax=None, case=None, **kwds)[source]¶
- Parameters:
T (1d array) – temperature [K]
P (1d array) – pressure [GPa]
etot (1d array, (axes_flat.shape[0],)) – Total energy [eV] for each axes_flat[i,…]
phdos (sequence of 2d arrays (axes_flat.shape[0],)) – Phonon dos arrays (nfreq, 2) for each axes grid point. axes_flat[i,…] -> phdos[i] = <2d array (nfreq,2)>, units see
HarmonicThermo
. For each arrayphdos[i][:,0] = freq
,phdos[i][:,1] = dos
. Those are passed toHarmonicThermo
.axes_flat (1d or 2d array) –
Flattened cell axes variation grid (for example result of nested loop over axes to vary). Will be cast to shape (N,1) if 1d with shape (N,) .
1d: (N,) or (N,1) -> vary one cell axis, i.e. cubic cell2d: (N,2) -> vary 2 (e.g. a and c for hexagonal)example:itertools.product(ax0, ax1)
3d: (N,3) -> vary a,b,c (general triclinic)example:itertools.product(ax0, ax1, ax2)
volfunc_ax (callable) –
calculate cell volume based on cell axes, V[i] = volfunc_ax(axes_flat[i,…]) where axes_flat[i,…]:
1d: [a0]2d: [a0, a1]3d: [a0, a1, a2]with a0,a1,a2 the length of the unit cell axes.
case (str, optional) – ‘1d’, ‘2d’, ‘3d’ or None. If None then it will be determined from axes_flat.shape[1]. Can be used to evaluate “fake” 1d data: set case=’1d’ but let axes_flat be (N,2) or (N,3)
**kwds (keywords) – passed to HarmonicThermo and added here as self.<key>=<value>
Methods
calc_F
([calc_all])Free energy properties along T axis for each axes grid point (ax0,ax1,ax2) in self.axes_flat.
calc_G
([ret, calc_all])Gibbs free energy and related properties on T-P grid.
calc_H
([calc_all])Enthalpy H=E+P*V, B and related properties on P grid without zero-point contributions.
set_fitfunc
(what, func)Update dict with fitting functions:
self.fitfunc[what] = func
.