[cig-commits] [commit] add_thermodynamic_potentials: Add missing file (76690db)
cig_noreply at geodynamics.org
cig_noreply at geodynamics.org
Tue Dec 9 09:54:42 PST 2014
Repository : https://github.com/geodynamics/burnman
On branch : add_thermodynamic_potentials
Link : https://github.com/geodynamics/burnman/compare/2e5646d93cedbbf8eae54cc37cffc14e0aa85180...d5ddad03ff9f30f5a4efaddb4e3ec585ea1a7c51
>---------------------------------------------------------------
commit 76690db530612db30891abde722be7ef30b8e96d
Author: ian-r-rose <ian.r.rose at gmail.com>
Date: Tue Sep 2 12:52:58 2014 -0700
Add missing file
>---------------------------------------------------------------
76690db530612db30891abde722be7ef30b8e96d
burnman/solutionmodel.py | 194 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 194 insertions(+)
diff --git a/burnman/solutionmodel.py b/burnman/solutionmodel.py
new file mode 100644
index 0000000..a091cc2
--- /dev/null
+++ b/burnman/solutionmodel.py
@@ -0,0 +1,194 @@
+# BurnMan - a lower mantle toolkit
+# Copyright (C) 2012-2014, Myhill, R., Heister, T., Unterborn, C., Rose, I. and Cottaar, S.
+# Released under GPL v2 or later.
+
+import numpy as np
+import warnings
+import burnman
+from burnman.processchemistry import *
+
+R = 8.3145 # J/K/mol
+
+class SolutionModel:
+ """
+ This is the base class for a solution model, intended for use
+ in defining solid solutions and performing thermodynamic calculations
+ on them.
+
+ A user wanting a new solution model should define the functions for
+ excess_gibbs_free_energy and excess_volume. In the base class these
+ return zero, so if this class is used then the Gibbs free energy and molar
+ volume of a solution are just the weighted arithmetic averages of the
+ different endmember values.
+ """
+
+ def excess_gibbs_free_energy( self, pressure, temperature, molar_fractions):
+ """
+ Given a list of molar fractions of different phases,
+ compute the excess Gibbs free energy of the solution,
+ relative to an ideal model.
+
+ Parameters
+ ----------
+ pressure : float
+ Pressure at which to evaluate the solution model. [Pa]
+
+ temperature : float
+ Temperature at which to evaluate the solution. [K]
+
+ molar_fractions : list of floats
+ List of molar fractions of the different endmembers in solution
+
+ Returns
+ -------
+ G_excess : float
+ The excess Gibbs free energy
+ """
+ return 0.0
+
+ def excess_volume( self, pressure, temperature, molar_fractions):
+ """
+ Given a list of molar fractions of different phases,
+ compute the excess Gibbs free energy of the solution,
+ relative to an ideal model. The base class implementation
+ assumes that the excess volume is zero.
+
+ Parameters
+ ----------
+ pressure : float
+ Pressure at which to evaluate the solution model. [Pa]
+
+ temperature : float
+ Temperature at which to evaluate the solution. [K]
+
+ molar_fractions : list of floats
+ List of molar fractions of the different endmembers in solution
+
+ Returns
+ -------
+ V_excess : float
+ The excess volume of the solution
+ """
+ return 0.0
+
+
+class IdealSolution ( SolutionModel ):
+ """
+ A very simple class representing an ideal solution model.
+ Calculate the excess gibbs free energy due to configurational
+ entropy, all the other excess terms return zero.
+ """
+ def __init__(self, endmembers):
+
+ self.n_endmembers = len(endmembers)
+ self.formulas = [e[1] for e in endmembers]
+
+ # Process solid solution chemistry
+ self.solution_formulae, self.n_sites, self.sites, self.n_occupancies, self.endmember_occupancies, self.site_multiplicities = \
+ ProcessSolidSolutionChemistry(self.formulas)
+
+ def excess_gibbs_free_energy( self, pressure, temperature, molar_fractions ):
+ return self.ideal_gibbs_excess( temperature, molar_fractions )
+
+ def ideal_gibbs_excess ( self, temperature, molar_fractions ):
+
+ activities = self.ideal_activities( molar_fractions )
+ gibbs_excess_ideal = 0.0
+
+ tol = 1.e-10
+ for i in range(self.n_endmembers):
+ if molar_fractions[i] > tol:
+ gibbs_excess_ideal = gibbs_excess_ideal + \
+ molar_fractions[i] * R * temperature * np.log(activities[i])
+
+ return gibbs_excess_ideal
+
+ def ideal_activities ( self, molar_fractions ):
+
+ site_occupancies=np.dot(molar_fractions, self.endmember_occupancies)
+ activities=np.empty(shape=(self.n_endmembers))
+
+ for e in range(self.n_endmembers):
+ activities[e]=1.0
+ normalisation_constant=1.0
+ for occ in range(self.n_occupancies):
+ if self.endmember_occupancies[e][occ] != 0: #integer?
+ activities[e]=activities[e]*np.power(site_occupancies[occ],self.site_multiplicities[occ])
+ normalisation_constant=normalisation_constant/np.power(self.endmember_occupancies[e][occ],self.site_multiplicities[occ])
+ activities[e]=normalisation_constant*activities[e]
+
+ return activities
+
+
+class AsymmetricVanLaar ( IdealSolution ):
+ """
+ Solution model implementing the Asymmetric Van Laar formulation
+ (best reference?).
+ """
+
+ def __init__( self, endmembers, alphas, enthalpy_interaction, volume_interaction = None, entropy_interaction = None ):
+
+ self.n_endmembers = len(endmembers)
+
+ # Create array of van Laar parameters
+ self.alpha=np.array(alphas)
+
+ # Create 2D arrays of interaction parameters
+ self.Wh=np.zeros(shape=(self.n_endmembers,self.n_endmembers))
+ self.Ws=np.zeros(shape=(self.n_endmembers,self.n_endmembers))
+ self.Wv=np.zeros(shape=(self.n_endmembers,self.n_endmembers))
+
+ #setup excess enthalpy interaction matrix
+ for i in range(self.n_endmembers):
+ for j in range(i+1, self.n_endmembers):
+ self.Wh[i][j]=2.*enthalpy_interaction[i][j-i-1]/(self.alpha[i]+self.alpha[j])
+
+ if entropy_interaction is not None:
+ for i in range(self.n_endmembers):
+ for j in range(i+1, self.n_endmembers):
+ self.Ws[i][j]=2.*entropy_interaction[i][j-i-1]/(self.alpha[i]+self.alpha[j])
+
+ if volume_interaction is not None:
+ for i in range(self.n_endmembers):
+ for j in range(i+1, self.n_endmembers):
+ self.Wv[i][j]=2.*volume_interaction[i][j-i-1]/(self.alpha[i]+self.alpha[j])
+
+ #initialize ideal solution model
+ IdealSolution.__init__(self, endmembers )
+
+ def excess_gibbs_free_energy( self, pressure, temperature, molar_fractions ):
+
+ ideal_gibbs = IdealSolution.ideal_gibbs_excess( self, temperature, molar_fractions )
+
+
+ phi=np.array([self.alpha[i]*molar_fractions[i] for i in range(self.n_endmembers)])
+ phi=np.divide(phi, np.sum(phi))
+
+ H_excess=np.dot(self.alpha.T,molar_fractions)*np.dot(phi.T,np.dot(self.Wh,phi))
+ S_excess=np.dot(self.alpha.T,molar_fractions)*np.dot(phi.T,np.dot(self.Ws,phi))
+ V_excess=np.dot(self.alpha.T,molar_fractions)*np.dot(phi.T,np.dot(self.Wv,phi))
+
+ non_ideal_gibbs = H_excess - temperature*S_excess + pressure*V_excess
+
+ return ideal_gibbs + non_ideal_gibbs
+
+
+ def excess_volume ( self, pressure, temperature, molar_fractions ):
+
+ phi=np.array([self.alpha[i]*molar_fractions[i] for i in range(self.n_endmembers)])
+ phi=np.divide(phi, np.sum(phi))
+
+ V_excess=np.dot(self.alpha.T,molar_fractions)*np.dot(phi.T,np.dot(self.Wv,phi))
+ return V_excess
+
+
+
+class SymmetricVanLaar ( AsymmetricVanLaar ):
+ """
+ Solution model implementing the Symmetric Van Laar solution
+ """
+ def __init__( self, endmembers, enthalpy_interaction, volume_interaction = None, entropy_ineraction = None ):
+ #symmetric case if all the alphas are equal?
+ alphas = np.ones( len(endmembers) )
+ AsymmetricVanLaar.__init__(self, endmembers, alphas, enthalpy_interaction, volume_ineteraction, entropy_interaction )
+
More information about the CIG-COMMITS
mailing list