[cig-commits] [commit] add_thermodynamic_potentials: Add Modified Tait EoS and expression for G (94d8bac)
cig_noreply at geodynamics.org
cig_noreply at geodynamics.org
Tue Dec 9 09:52:53 PST 2014
Repository : https://github.com/geodynamics/burnman
On branch : add_thermodynamic_potentials
Link : https://github.com/geodynamics/burnman/compare/2e5646d93cedbbf8eae54cc37cffc14e0aa85180...d5ddad03ff9f30f5a4efaddb4e3ec585ea1a7c51
>---------------------------------------------------------------
commit 94d8bac33bad9a6f9d7424ac4c3b4eaa16fd1fc4
Author: Bob Myhill <myhill.bob at gmail.com>
Date: Sun Aug 10 20:09:50 2014 +0200
Add Modified Tait EoS and expression for G
>---------------------------------------------------------------
94d8bac33bad9a6f9d7424ac4c3b4eaa16fd1fc4
burnman/mineral.py | 5 +-
burnman/minerals/HP_2011.py | 54 +++++++++++
burnman/modified_tait.py | 231 +++++++++++++++++++++++---------------------
3 files changed, 178 insertions(+), 112 deletions(-)
diff --git a/burnman/mineral.py b/burnman/mineral.py
index e641665..d6c4d87 100644
--- a/burnman/mineral.py
+++ b/burnman/mineral.py
@@ -11,6 +11,7 @@ import burnman.equation_of_state as eos
import burnman.birch_murnaghan as bm
import burnman.slb as slb
import burnman.mie_grueneisen_debye as mgd
+import burnman.modified_tait as mt
class Mineral(Material):
"""
@@ -59,7 +60,7 @@ class Mineral(Material):
Set the equation of state to be used for this mineral.
Takes a string corresponding to any of the predefined
equations of state: 'bm2', 'bm3', 'mgd2', 'mgd3', 'slb2',
- or 'slb3'. Alternatively, you can pass a user defined
+ 'slb3' or 'mtait'. Alternatively, you can pass a user defined
class which derives from the equation_of_state base class.
"""
if( isinstance(method, basestring)):
@@ -75,6 +76,8 @@ class Mineral(Material):
self.method = bm.BM2()
elif (method == "bm3"):
self.method = bm.BM3()
+ elif (method == "mtait"):
+ self.method = mt.MT()
else:
raise Exception("unsupported material method " + method)
elif ( issubclass(method, eos.EquationOfState) ):
diff --git a/burnman/minerals/HP_2011.py b/burnman/minerals/HP_2011.py
new file mode 100644
index 0000000..44bfccd
--- /dev/null
+++ b/burnman/minerals/HP_2011.py
@@ -0,0 +1,54 @@
+# BurnMan - a lower mantle toolkit
+# Copyright (C) 2012, 2013, Heister, T., Unterborn, C., Rose, I. and Cottaar, S.
+# Released under GPL v2 or later.
+
+"""
+
+HP_2011
+^^^^^^^^
+
+Minerals from Holland and Powell 2011 and references therein.
+
+Note the units in Holland and Powell's Table 1 are not SI. They are:
+H_0 [kJ/mol] i.e. multiply by 1e3 to get J/mol
+err_H_0 [kJ/mol] i.e. multiply by 1e3 to get J/mol
+S [J/mol] i.e. S.I!
+V [kJ/kbar/mol] i.e. multiply by 1e-5 to get m^3/mol
+Cp [kJ/K/mol] is given as a + bT + cT^-2 + dT^-0.5.
+ b is multiplied by 1e5 to be more readable.
+ Thus, conversions to SI are [1e3, 1e-2, 1e3, 1e3]
+a_0 [1e5 K^-1] i.e. multiply by 1e-5 to get K^-1
+K_0 [kbar] i.e. multiply by 1e8 to get Pa
+Kprime_0 [] i.e. SI!
+Kdprime_0 [kbar^-1] i.e. multiply by 1e-8
+
+The values in the database itself are NOT the same as the paper. They are strictly in the units kJ, kbar, K.
+
+There are also parameters which deal with internal order-disorder and Landau transitions. NOTE: These still need to be implemented.
+"""
+
+from burnman.mineral import Mineral
+from burnman.solidsolution import SolidSolution
+
+class stishovite (Mineral):
+ """
+ Holland and Powell, 2011 and references therein
+ """
+ def __init__(self):
+ self.params = {
+ 'formula': '[Si][O]2',
+ 'equation_of_state': 'mtait',
+ 'H_0': -876.39e3,
+ 'S_0': 24.0,
+ 'V_0': 1.401e-5,
+ 'Cp': [68.1,6.01e-3,-1.9782e6,-82.1],
+ 'a_0': 15.8e-6
+ 'K_0': 3090.e8
+ 'Kprime_0': 4.6,
+ 'Kdprime_0': -0.00150e-8,
+ 'molar_mass': .0601,
+ 'n': 3}
+
+ self.uncertainties = {
+ 'err_H_0':0.49e3}
+
diff --git a/burnman/modified_tait.py b/burnman/modified_tait.py
index cc6786b..4a93514 100644
--- a/burnman/modified_tait.py
+++ b/burnman/modified_tait.py
@@ -6,11 +6,39 @@ import numpy as np
import scipy.optimize as opt
import burnman.equation_of_state as eos
-import burnman.birch_murnaghan as bm
-import burnman.debye as debye
+T_0=298.15 # Standard temperature = 25 C
-class MGDBase(eos.EquationOfState):
+def einst(S, n):
+ "
+ Einstein temperature
+ base of p.346, para.1
+ "
+ return 10636./(S/n + 6.44)
+
+def ksi(u):
+ "
+ Einstein function to describe behaviour of ak
+ EQ 11+1
+ "
+ return pow(u,2.)*exp(u)/pow((exp(u)-1.), 2.)
+
+def modified_tait(x, params):
+ """
+ equation for the modified Tait equation of state, returns
+ pressure in the same units that are supplied for the reference bulk
+ modulus (params['K_0'])
+ EQ 2
+ """
+
+ a=(1.+params['Kprime_0'])/(1. + params['Kprime_0'] + params['K_0']*params['Kdprime_0'])
+ b=(params['Kprime_0'])/(params['K_0'] - (params['Kdprime_0'])/(1. + params['Kprime_0']))
+ c=(1. + params['Kprime_0'] + params['K_0']*params['Kdprime_0'])/(params['Kprime_0']*params['Kprime_0'] + params['Kprime_0'] - params['K_0']*params['Kdprime_0'])
+
+ return (pow((x + a - 1.) / a, -1./c) - 1.)/b
+
+
+class MTaitBase(eos.EquationOfState):
"""
Base class for a generic modified Tait equation of state.
References for this can be found in Huang and Chow (1974)
@@ -23,156 +51,137 @@ class MGDBase(eos.EquationOfState):
def grueneisen_parameter(self, pressure, temperature, volume, params):
"""
Returns grueneisen parameter [unitless] as a function of pressure,
- temperature, and volume (EQ B6)
+ temperature, and volume.
+ Not a part of the Modified Tait EoS, currently returns 0.
+ Note that this means we can't calculate Cv or Ks yet.
+ gamma = V*(dP/dE)|_V = (alpha*K_S)/(Cp*rho) = (alpha*K_T)/(Cv*rho)
"""
- return self.__grueneisen_parameter(params['V_0']/volume, params)
+ return 0.
def volume(self, pressure,temperature,params):
"""
Returns volume [m^3] as a function of pressure [Pa] and temperature [K]
- EQ B7
+ EQ 12
"""
- func = lambda x: bm.birch_murnaghan(params['V_0']/x, params) + \
- self.__thermal_pressure(temperature, x, params) - \
- self.__thermal_pressure(300., x, params) - pressure
- V = opt.brentq(func, 0.5*params['V_0'], 1.5*params['V_0'])
- return V
+ a=(1.+params['Kprime_0'])/(1. + params['Kprime_0'] + params['K_0']*params['Kdprime_0'])
+ b=(params['Kprime_0'])/(params['K_0'] - (params['Kdprime_0'])/(1. + params['Kprime_0']))
+ c=(1. + params['Kprime_0'] + params['K_0']*params['Kdprime_0'])/(params['Kprime_0']*params['Kprime_0'] + params['Kprime_0'] - params['K_0']*params['Kdprime_0'])
+
+ Pth=self.__rel_thermal_pressure(temperature,params)
+ x = 1 - a*( 1. - pow(( 1. + b*(pressure-Pth)), -1.0*c))
+ return x*params['V_0']
def isothermal_bulk_modulus(self, pressure,temperature,volume, params):
"""
Returns isothermal bulk modulus [Pa] as a function of pressure [Pa],
- temperature [K], and volume [m^3]. EQ B8
+ temperature [K], and volume [m^3]. EQ 13+2
"""
- K_T = bm.bulk_modulus(volume, params) + \
- self.__thermal_bulk_modulus(temperature,volume, params) - \
- self.__thermal_bulk_modulus(300.,volume, params) #EQB13
- return K_T
+ a=(1.+params['Kprime_0'])/(1. + params['Kprime_0'] + params['K_0']*params['Kdprime_0'])
+ b=(params['Kprime_0'])/(params['K_0'] - (params['Kdprime_0'])/(1. + params['Kprime_0']))
+ c=(1. + params['Kprime_0'] + params['K_0']*params['Kdprime_0'])/(params['Kprime_0']*params['Kprime_0'] + params['Kprime_0'] - params['K_0']*params['Kdprime_0'])
+
+ Pth=self.__rel_thermal_pressure(temperature,params)
+ psubpth=pressure-Pth
+ return params['K_0']*(1. + b(psubpth))*(a + (1.-a)*pow((1. + b(psubpth)), c))
#calculate the mgd shear modulus as a function of P, V, and T
def shear_modulus(self, pressure, temperature, volume, params):
"""
- Returns shear modulus [Pa] as a function of pressure [Pa],
- temperature [K], and volume [m^3]. EQ B11
- """
- if self.order==2:
- return bm.shear_modulus_second_order(volume,params) + \
- self.__thermal_shear_modulus(temperature,volume, params) - \
- self.__thermal_shear_modulus(300.,volume, params) # EQ B11
- elif self.order==3:
- return bm.shear_modulus_third_order(volume,params) + \
- self.__thermal_shear_modulus(temperature,volume, params) - \
- self.__thermal_shear_modulus(300.,volume, params) # EQ B11
- else:
- raise NotImplementedError("")
-
- #heat capacity at constant volume
+ Not implemented.
+ Returns 0.
+ Could potentially apply a fixed Poissons ratio as a rough estimate.
+ """
+ return 0.
+
+ # Cv, heat capacity at constant volume
def heat_capacity_v(self, pressure, temperature, volume, params):
"""
- Returns heat capacity at constant volume at the pressure, temperature, and volume [J/K/mol]
+ Returns heat capacity at constant volume at the pressure, temperature, and volume [J/K/mol].
+ Not yet implemented, returns 0.
"""
- Debye_T = self.__debye_temperature(params['V_0']/volume, params)
- C_v = debye.heat_capacity_v(temperature, Debye_T, params['n'])
- return C_v
+ return 0.
def thermal_expansivity(self, pressure, temperature, volume , params):
"""
Returns thermal expansivity at the pressure, temperature, and volume [1/K]
+ Replace -Pth in EQ 13+1 with P-Pth for non-ambient temperature
"""
- C_v = self.heat_capacity_v(pressure,temperature,volume,params)
- gr = self.__grueneisen_parameter(params['V_0']/volume, params)
- K = self.isothermal_bulk_modulus(pressure, temperature, volume ,params)
- alpha = gr * C_v / K / volume
+ a=(1.+params['Kprime_0'])/(1. + params['Kprime_0'] + params['K_0']*params['Kdprime_0'])
+ b=(params['Kprime_0'])/(params['K_0'] - (params['Kdprime_0'])/(1. + params['Kprime_0']))
+ c=(1. + params['Kprime_0'] + params['K_0']*params['Kdprime_0'])/(params['Kprime_0']*params['Kprime_0'] + params['Kprime_0'] - params['K_0']*params['Kdprime_0'])
+ Pth=self.__rel_thermal_pressure(temperature,params)
+ psubpth=pressure-Pth
+ ein=einst(params['S_0'], params['n'])
+ alpha = params['a_0']*ksi(ein/temperature)/ksi(ein/T_0)*1./((1.+b*psubpth)*(a + (1.-a)*pow((1+b*psubpth), c)))
+
return alpha
- #heat capacity at constant pressure
- def heat_capacity_p(self,pressure, temperature,volume,params):
+ # Heat capacity at ambient pressure
+ # N.B. Cp=-T*(d2G/dT2)|p
+ def heat_capacity_p0(self,temperature,params):
"""
- Returns heat capacity at constant pressure at the pressure, temperature, and volume [J/K/mol]
+ Returns heat capacity at ambient pressure as a function of temperature [J/K/mol]
+ Cp = a + bT + cT^-2 + dT^-0.5 in Holland and Powell, 2011
"""
- alpha = self.thermal_expansivity(pressure,temperature,volume,params)
- gr = self.__grueneisen_parameter(params['V_0']/volume, params)
- C_v = self.heat_capacity_v(pressure,temperature,volume,params)
- C_p = C_v*(1. + gr * alpha * temperature)
- return C_p
+ Cp = params['Cp'][0] + params['Cp'][1]*temperature + params['Cp'][2]*pow(temperature,-2.) + params['Cp'][3]*pow(temperature,-0.5)
+ return Cp
def adiabatic_bulk_modulus(self,pressure,temperature,volume,params):
"""
Returns adiabatic bulk modulus [Pa] as a function of pressure [Pa],
- temperature [K], and volume [m^3]. EQ D6
+ temperature [K], and volume [m^3].
+ Not yet implemented. Returns 0.
"""
- K_T= self.isothermal_bulk_modulus(pressure,temperature,volume,params)
- alpha = self.thermal_expansivity(pressure,temperature,volume,params)
- gr = self.__grueneisen_parameter(params['V_0']/volume, params)
- K_S = K_T*(1. + gr * alpha * temperature)
- return K_S
+ #K_T= self.isothermal_bulk_modulus(pressure,temperature,volume,params)
+ #alpha = self.thermal_expansivity(pressure,temperature,volume,params)
+ #gr = self.__grueneisen_parameter(params['V_0']/volume, params)
+ #K_S = K_T*(1. + gr * alpha * temperature)
+ return 0.
+ def gibbs(self,pressure,temperature,params):
+ """
+ Returns the gibbs free energy [J/mol] as a function of pressure [Pa]
+ and temperature [K].
+ """
+ # Calculate temperature and pressure integrals
+ a=(1.+params['Kprime_0'])/(1. + params['Kprime_0'] + params['K_0']*params['Kdprime_0'])
+ b=(params['Kprime_0'])/(params['K_0'] - (params['Kdprime_0'])/(1. + params['Kprime_0']))
+ c=(1. + params['Kprime_0'] + params['K_0']*params['Kdprime_0'])/(params['Kprime_0']*params['Kprime_0'] + params['Kprime_0'] - params['K_0']*params['Kdprime_0'])
+ Pth=self.__rel_thermal_pressure(temperature,params)
+ psubpth=pressure-Pth
+
+ intCpdT = (params['Cp'][0]*temperature + 0.5*params['Cp'][1]*pow(temperature,2.) - params['Cp'][2]/temperature + 2.*params['Cp'][3]*sqrt(temperature)) - (params['Cp'][0]*T_0 + 0.5*params['Cp'][1]*T_0*T_0 - params['Cp'][2]/T_0 + 2.0*params['Cp'][3]*sqrt(T_0))
+
+ intCpoverTdT = (params['Cp'][0]*log(temperature) + params['Cp'][1]*temperature - 0.5*params['Cp'][2]/pow(temperature,2.) - 2.0*params['Cp'][3]/sqrt(temperature)) - (params['Cp'][0]*log(T_0) + params['Cp'][1]*T_0 - 0.5*params['Cp'][2]/(T_0*T_0) - 2.0*params['Cp'][3]/sqrt(T_0))
+
+ # EQ 13
+ intVdP = pressure*params['V_0']*(1. - a + (a*(pow((1.-b*Pth), 1.-c) - pow((1. + b*(pressure-Pth)), 1.-c))/(b*(c-1.)*pressure)))
+
+ return params['H_0'] + intCpdT - temperature*(params['S_0'] + intCpoverTdT) + intVdP
+
+ # calculate P = P(T0) + Pth
def pressure(self, temperature, volume, params):
"""
Returns pressure [Pa] as a function of temperature [K] and volume[m^3]
EQ B7
"""
- return bm.birch_murnaghan(params['V_0']/volume, params) + \
- self.__thermal_pressure(temperature,volume, params) - \
- self.__thermal_pressure(300.,volume, params)
-
- #calculate the thermal correction to the shear modulus as a function of V, T
- def __thermal_shear_modulus(self, T, V, params):
- gr = self.__grueneisen_parameter(params['V_0']/V, params)
- Debye_T = self.__debye_temperature(params['V_0']/V, params)
- G_th= 3./5. * ( self.__thermal_bulk_modulus(T,V,params) - \
- 6*debye.R*T*params['n']/V * gr * debye.debye_fn(Debye_T/T) ) # EQ B10
- return G_th
-
- #compute the Debye temperature in K. Takes the
- #parameter x, which is V_0/V (molar volumes).
- #Depends on the reference grueneisen parameter,
- #the reference Debye temperature, and the factor
- #q_0, see Matas eq B6
- def __debye_temperature(self, x, params):
- return params['Debye_0']*np.exp((params['grueneisen_0']- \
- self.__grueneisen_parameter(x, params))/params['q_0'])
-
- #compute the grueneisen parameter with depth, according
- #to q_0. Takes x=V_0/V. See Matas eq B6
- def __grueneisen_parameter(self, x, params):
- return params['grueneisen_0']*pow(1./x, params['q_0'])
-
- #calculate isotropic thermal pressure, see
- # Matas et. al. (2007) eq B4
- def __thermal_pressure(self,T,V, params):
- Debye_T = self.__debye_temperature(params['V_0']/V, params)
- gr = self.__grueneisen_parameter(params['V_0']/V, params)
- P_th = gr * debye.thermal_energy(T,Debye_T, params['n'])/V
- return P_th
-
-
- #calculate the thermal correction for the mgd
- #bulk modulus (see matas et al, 2007)
- def __thermal_bulk_modulus(self, T,V,params):
- gr = self.__grueneisen_parameter(params['V_0']/V, params)
- Debye_T = self.__debye_temperature(params['V_0']/V, params)
- K_th = 3.*params['n']*debye.R*T/V * gr * \
- ((1. - params['q_0'] - 3.*gr)*debye.debye_fn(Debye_T/T)+3.*gr*(Debye_T/T)/(np.exp(Debye_T/T) - 1.)) # EQ B5
- return K_th
+ return modified_tait(params['V_0']/volume, params) + \
+ self.__rel_thermal_pressure(temperature, params)
-class MGD3(MGDBase):
- """
- MGD equation of state with third order finite strain expansion for the
- shear modulus (this should be preferred, as it is more thermodynamically
- consistent.
- """
- def __init__(self):
- self.order=3
+ #calculate relative thermal pressure (relative to T_0), see EQ 12 - 1
+ def __rel_thermal_pressure(self,T, params):
+ ein=einst(params['S_0'],params['n'])
+ u=ein/T
+ u_0=ein/T_0
+ P_th = params['a_0']*params['k_0']*ein/ksi(T_0)*((1./(exp(u))-1.))-(1./(exp(u_0))-1.))
+ return P_th
-class MGD2(MGDBase):
+class MT(MTaitBase):
"""
- MGD equation of state with second order finite strain expansion for the
- shear modulus. In general, this should not be used, but sometimes
- shear modulus data is fit to a second order equation of state. In that
- case, you should use this. The moral is, be careful!
+ Standard MT equation of state.
+ This class currently exists for consistency with the MGD,
+ SLB and BM class set structures.
"""
- def __init__(self):
- self.order=2
More information about the CIG-COMMITS
mailing list