Skip to content

Commit 9546b99

Browse files
committed
added example for optimal thermobarometry
1 parent 3e88955 commit 9546b99

File tree

2 files changed

+148
-0
lines changed

2 files changed

+148
-0
lines changed

docs/examples.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ Advanced examples:
167167
- :mod:`~examples.example_fit_data`,
168168
- :mod:`~examples.example_fit_eos`,
169169
- :mod:`~examples.example_fit_solution`,
170+
- :mod:`~examples.example_optimal_thermobarometry`,
170171
- :mod:`~examples.example_equilibrate`, and
171172
- :mod:`~examples.example_olivine_binary`.
172173

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
# This file is part of BurnMan - a thermoelastic and thermodynamic toolkit
2+
# for the Earth and Planetary Sciences
3+
# Copyright (C) 2012 - 2025 by the BurnMan team, released under the GNU
4+
# GPL v2 or later.
5+
6+
7+
"""
8+
example_optimal_thermobarometry
9+
-------------------------------
10+
11+
This example script is intended to demonstrate optimal thermobarometry
12+
using BurnMan. The technique is based on the work of Powell and Holland
13+
(1994; American Mineralogist 79 (1-2): 120-133).
14+
We cover importing BurnMan modules, creating a composite
15+
material representing a mineral assemblage, fitting the compositions of
16+
the constituent minerals to their solution models, and estimating the
17+
pressure and temperature conditions of equilibration based on the
18+
mineral compositions and their uncertainties. Finally, we print
19+
the estimated conditions along with their uncertainties and correlations.
20+
21+
*Uses:*
22+
23+
* :doc:`mineral_database`
24+
* :func:`burnman.optimize.composition_fitting.fit_composition_to_solution`
25+
* :func:`burnman.optimize.thermobarometry.estimate_conditions`
26+
27+
28+
*Demonstrates:*
29+
30+
* creating mineral assemblages
31+
* fitting mineral compositions to solution models
32+
* estimating pressure and temperature conditions of equilibration
33+
"""
34+
35+
import numpy as np
36+
from burnman import Composite
37+
from burnman.minerals import mp50MnNCKFMASHTO, HP_2011_ds62
38+
from burnman.optimize.composition_fitting import fit_composition_to_solution
39+
from burnman.tools.thermobarometry import estimate_conditions
40+
41+
if __name__ == "__main__":
42+
43+
# 1) Define observed mineral assemblage
44+
mu = mp50MnNCKFMASHTO.mu()
45+
bi = mp50MnNCKFMASHTO.bi()
46+
g = mp50MnNCKFMASHTO.g()
47+
ilmm = mp50MnNCKFMASHTO.ilmm()
48+
st = mp50MnNCKFMASHTO.st()
49+
q = HP_2011_ds62.q()
50+
51+
assemblage = Composite([mu, bi, g, ilmm, st, q])
52+
53+
# 2) Fit the measured compositions (in molar amounts) to the solution
54+
# models for each mineral in the assemblage.
55+
# The amounts do not need to sum to any particular number,
56+
# as the fitting function will normalize them appropriately.
57+
# The compositions correspond approximately to the expected
58+
# compositions at about 4 kbar and 873 K.
59+
60+
# a) Muscovite
61+
fitted_species = ["Na", "Ca", "K", "Fe", "Mg", "Al", "Si"]
62+
species_amounts = np.array([0.40, 0.01, 0.55, 0.01, 0.01, 3.00, 3.00])
63+
species_covariances = np.diag(
64+
np.array([0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01]) ** 2
65+
)
66+
popt, pcov, res = fit_composition_to_solution(
67+
mu, fitted_species, species_amounts, species_covariances
68+
)
69+
mu.set_composition(popt)
70+
mu.compositional_covariances = pcov
71+
72+
# b) Biotite (requires parameter constraining order state of
73+
# Mg and Fe on the first two sites)
74+
fitted_species = ["Mn", "Fe", "Mg", "Al", "Si", "Ti", "Mg_M3"]
75+
species_amounts = np.array([0.01, 1.50, 1.00, 1.65, 2.65, 0.20, 0.10])
76+
species_covariances = np.diag(
77+
np.array([0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.1]) ** 2
78+
)
79+
variable_conversions = {"Mg_M3": {"Mgmthree_A": 1.0}}
80+
popt, pcov, res = fit_composition_to_solution(
81+
bi, fitted_species, species_amounts, species_covariances, variable_conversions
82+
)
83+
bi.set_composition(popt)
84+
bi.compositional_covariances = pcov
85+
86+
# c) Garnet
87+
fitted_species = ["Mn", "Fe", "Mg", "Ca", "Al", "Si"]
88+
species_amounts = np.array([0.25, 2.30, 0.40, 0.05, 2.00, 3.00])
89+
species_covariances = np.diag(np.array([0.01, 0.01, 0.01, 0.01, 0.01, 0.01]) ** 2)
90+
popt, pcov, res = fit_composition_to_solution(
91+
g, fitted_species, species_amounts, species_covariances
92+
)
93+
g.set_composition(popt)
94+
g.compositional_covariances = pcov
95+
96+
# d) Ilmenite (requires parameter constraining order state of Fe and Ti)
97+
fitted_species = ["Mn", "Fe", "Ti", "Mg", "Fe2+_A"]
98+
species_amounts = np.array([0.05, 1.0, 0.90, 0.05, 0.4])
99+
species_covariances = np.diag(np.array([0.01, 0.01, 0.01, 0.01, 0.2]) ** 2)
100+
species_conversions = {"Fe2+_A": {"Fea_A": 1.0}}
101+
popt, pcov, res = fit_composition_to_solution(
102+
ilmm, fitted_species, species_amounts, species_covariances, species_conversions
103+
)
104+
ilmm.set_composition(popt)
105+
ilmm.compositional_covariances = pcov
106+
107+
# e) Staurolite
108+
fitted_species = ["Mn", "Fe", "Mg", "Al", "Si", "Ti"]
109+
species_amounts = np.array([0.05, 3.30, 0.72, 17.78, 7.50, 0.12])
110+
species_covariances = np.diag(np.array([0.01, 0.01, 0.01, 0.01, 0.01, 0.01]) ** 2)
111+
popt, pcov, res = fit_composition_to_solution(
112+
st, fitted_species, species_amounts, species_covariances
113+
)
114+
st.set_composition(popt)
115+
st.compositional_covariances = pcov
116+
117+
# f) Quartz (no fitting needed)
118+
119+
# 3) Estimate the pressure and temperature conditions of equilibration
120+
# based on the fitted compositions and their uncertainties, and
121+
# also the endmember covariances provided by the underlying dataset.
122+
res = estimate_conditions(
123+
assemblage,
124+
dataset_covariances=HP_2011_ds62.cov(),
125+
guessed_conditions=np.array([0.5e9, 500.0]),
126+
small_fraction_tol=0.01,
127+
)
128+
129+
# 4) Print the estimated conditions along with their uncertainties
130+
# and correlations.
131+
print(
132+
f"Estimated Pressure: {assemblage.pressure/1.e9:.2f} "
133+
f"+/- {np.sqrt(res.xcov[0, 0])/1.e9:.2f} GPa"
134+
)
135+
print(
136+
f"Estimated Temperature: {assemblage.temperature:.2f} "
137+
f"+/- {np.sqrt(res.xcov[1, 1]):.2f} K"
138+
)
139+
print(f"Correlation between P and T: {res.xcorr:.4f}")
140+
print(f"Number of Reactions: {res.n_reactions}")
141+
print(f"Number of Parameters: {res.n_params}")
142+
print(f"Degrees of Freedom: {res.degrees_of_freedom}")
143+
print(f"Reduced Chi-squared: {res.reduced_chisqr:.4f}")
144+
print(f"Fit (sqrt reduced chi-squared): {res.fit:.4f}")
145+
print("Weighted reaction affinities:")
146+
np.set_printoptions(precision=2)
147+
print(res.weighted_affinities)

0 commit comments

Comments
 (0)