[cig-commits] [commit] add_thermodynamic_potentials: Added chemical potential and fugacity functions and examples (5ef1a29)

cig_noreply at geodynamics.org cig_noreply at geodynamics.org
Tue Dec 9 09:55:31 PST 2014


Repository : https://github.com/geodynamics/burnman

On branch  : add_thermodynamic_potentials
Link       : https://github.com/geodynamics/burnman/compare/2e5646d93cedbbf8eae54cc37cffc14e0aa85180...d5ddad03ff9f30f5a4efaddb4e3ec585ea1a7c51

>---------------------------------------------------------------

commit 5ef1a29b106ff6d68671f20dfe7d2c93241d3720
Author: Bob Myhill <myhill.bob at gmail.com>
Date:   Wed Sep 3 17:26:12 2014 +0200

    Added chemical potential and fugacity functions and examples


>---------------------------------------------------------------

5ef1a29b106ff6d68671f20dfe7d2c93241d3720
 burnman/chemicalpotentials.py      | 77 +++++++++++++++++++++++++++++++++-----
 burnman/test_chemicalpotentials.py | 34 ++++++++++++++---
 2 files changed, 95 insertions(+), 16 deletions(-)

diff --git a/burnman/chemicalpotentials.py b/burnman/chemicalpotentials.py
index 548681d..f2b5c23 100644
--- a/burnman/chemicalpotentials.py
+++ b/burnman/chemicalpotentials.py
@@ -6,28 +6,85 @@ import burnman
 from burnman import minerals
 from processchemistry import *
 import numpy as np
+from scipy.linalg import lu
 
+R=8.3145
 # This module computes chemical potentials (partial molar gibbs free energies) for an assemblage based on the Gibbs free energies and compositions of the individual phases.
 
 # It can also calculate fugacities based on the gibbs free energies of the endmembers corresponding to chemical components.
 
 # It can also calculate fugacities relative to other bulk compositions
 
-def chemicalpotentials(minerals, component_formulae):
-    mineral_gibbs=[]
-    mineral_formulae=[]
-    for mineral in minerals:
-        mineral_gibbs.append(mineral.gibbs)
-        mineral_formulae.append(mineral.params['formula'])
+def chemicalpotentials(assemblage, component_formulae):
+    """
+    The compositional space of the components does not have to be a 
+    superset of the compositional space of the assemblage. Nor do they have to
+    compose an orthogonal basis. 
 
+    The components must each be described by a linear mineral combination
+
+    The mineral compositions must be linearly independent
+
+        Parameters
+        ----------
+        assemblage : list of classes
+            List of material classes
+            set_method and set_state should already have been used
+
+        component_formulae : list of dictionaries
+            List of chemical component formula dictionaries
+            No restriction on length
+
+        Returns
+        -------
+        component_potentials : array of floats
+            Array of chemical potentials of components
+
+    """
+    mineral_gibbs=[mineral.gibbs for mineral in assemblage]
+    mineral_formulae=[mineral.params['formula'] for mineral in assemblage]
     mineral_compositions, elements=compositional_array(mineral_formulae)
 
-    for i in range(len(component_formulae)):
-        component_formulae[i]=dictionarize_formula(component_formulae[i])
+    pl, u = lu(mineral_compositions, permute_l=True)
+    assert(min(np.dot(np.square(u), np.ones(shape=len(elements)))) > 1e-6), \
+        'Mineral compositions do not form an independent set of basis vectors'
 
     component_compositions=ordered_compositional_array(component_formulae, elements)
-    component_proportions=np.linalg.lstsq(component_compositions.T, mineral_compositions.T)[0].T
-    component_potentials=np.linalg.solve(component_proportions,mineral_gibbs)
+
+    p=np.linalg.lstsq(mineral_compositions.T,component_compositions.T)
+    for idx, error in enumerate(p[1]):
+        assert (error < 1e-10), \
+            'Component %d not defined by prescribed assemblage' % (idx+1)
+
+    mineral_proportions=np.around(p[0],10).T
+
+    component_potentials=np.dot(mineral_proportions, mineral_gibbs)
 
     return component_potentials
 
+def fugacity(component_formula, standard_material, assemblage):
+    """
+        Parameters
+        ----------
+        component_formula : dictionary
+            Chemical formula dictionary
+
+        standard_material: class
+            Material class
+            set_method and set_state should already have been used
+
+        assemblage: list of classes
+            List of material classes
+            set_method and set_state should already have been used
+
+        Returns
+        -------
+        fugacity : float
+            Value of the fugacity of the component with respect to
+            the standard material
+
+    """
+    chemical_potential=chemicalpotentials(assemblage, [component_formula])[0]
+
+    fugacity=np.exp((chemical_potential - standard_material.gibbs)/(R*assemblage[0].temperature))
+    return fugacity
diff --git a/burnman/test_chemicalpotentials.py b/burnman/test_chemicalpotentials.py
index 1664d28..eb0b3ad 100644
--- a/burnman/test_chemicalpotentials.py
+++ b/burnman/test_chemicalpotentials.py
@@ -7,24 +7,46 @@ from burnman import minerals
 from chemicalpotentials import *
 import numpy as np
 
-
+'''
+Here we initialise the minerals we'll be using
+'''
 P=1.e8
 T=1000.
 
 py=minerals.HP_2011_ds62.py()
 fo=minerals.HP_2011_ds62.fo()
 en=minerals.HP_2011_ds62.en()
-
-minerals=[py, fo, en]
+per=minerals.HP_2011_ds62.per()
+minerals=[py, fo, en, per]
 
 for mineral in minerals:
     mineral.set_method('mtait')
     mineral.set_state(P, T)
 
+
+'''
+Here we find chemical potentials of MgO, Al2O3 and SiO2 for
+an assemblage containing pyrope, forsterite and enstatite 
+at 0.1 GPa, 1000 K
+'''
+
+assemblage=[py, fo, en]
 component_formulae=['MgO', 'Al2O3', 'SiO2']
+component_formulae_dict=[dictionarize_formula(f) for f in component_formulae]
+chem_potentials=chemicalpotentials(assemblage, component_formulae_dict)
+
+for idx, component_formula in enumerate(component_formulae):
+    print "mu("+component_formula+"):", chem_potentials[idx]
+print ''
 
-chem_potentials=chemicalpotentials(minerals, component_formulae)
 
-for idx, mineral in enumerate(minerals):
-    print mineral.params['name'], chem_potentials[idx]
+'''
+Here we find the 'periclase fugacity' of the assemblage
+Fugacity is often defined relative to some reference pressure
+Here we use room pressure, 100 kPa
+'''
 
+Pr=1.e5
+per.set_state(Pr, T)
+component=dictionarize_formula('MgO')
+print 'log(fugacity_per):', np.log10(fugacity(component, per, assemblage))



More information about the CIG-COMMITS mailing list