VolFe 0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- VolFe/__init__.py +30 -0
- VolFe/_version.py +8 -0
- VolFe/batch_calculations.py +2033 -0
- VolFe/calculations.py +954 -0
- VolFe/differential_equations.py +601 -0
- VolFe/equilibrium_equations.py +3190 -0
- VolFe/import_files.py +10 -0
- VolFe/isotopes.py +181 -0
- VolFe/melt_gas.py +821 -0
- VolFe/model_dependent_variables.py +1534 -0
- VolFe-0.2.dist-info/METADATA +23 -0
- VolFe-0.2.dist-info/RECORD +14 -0
- VolFe-0.2.dist-info/WHEEL +5 -0
- VolFe-0.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,1534 @@
|
|
|
1
|
+
# model_dependent_variables.py
|
|
2
|
+
|
|
3
|
+
import pandas as pd
|
|
4
|
+
import numpy as np
|
|
5
|
+
import gmpy2 as gp
|
|
6
|
+
import math
|
|
7
|
+
import densityx as dx
|
|
8
|
+
import PySulfSat as ss
|
|
9
|
+
|
|
10
|
+
#import VolFe.melt_gas as mg
|
|
11
|
+
|
|
12
|
+
#from VolFe.melt_gas import *
|
|
13
|
+
import VolFe.melt_gas as mg
|
|
14
|
+
|
|
15
|
+
################
|
|
16
|
+
### Contents ###
|
|
17
|
+
################
|
|
18
|
+
# Solubility constants
|
|
19
|
+
# Solid/liquid saturation
|
|
20
|
+
# Equilibrium constants
|
|
21
|
+
# Fugacity coefficients
|
|
22
|
+
# Speciation
|
|
23
|
+
# Isotope fractionation factors
|
|
24
|
+
|
|
25
|
+
#################################################################################################################################
|
|
26
|
+
##################################################### SOLUBILITY CONSTANTS ######################################################
|
|
27
|
+
#################################################################################################################################
|
|
28
|
+
|
|
29
|
+
###################################
|
|
30
|
+
### Solubility constant for H2O ###
|
|
31
|
+
###################################
|
|
32
|
+
def C_H2O(PT,melt_wf,species,models):
|
|
33
|
+
|
|
34
|
+
"""
|
|
35
|
+
Solubility constant for disolving H2O in the melt.
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
Parameters
|
|
39
|
+
----------
|
|
40
|
+
PT: pandas.DataFrame
|
|
41
|
+
Dataframe of pressure-temperature conditions:
|
|
42
|
+
pressure (bars) as "P"
|
|
43
|
+
temperature ('C) as "T"
|
|
44
|
+
|
|
45
|
+
melt_wf: pandas.DataFrame
|
|
46
|
+
Dataframe of melt composition, not used but kept in case dependence on melt composition is required.
|
|
47
|
+
|
|
48
|
+
species: pandas.DataFrame
|
|
49
|
+
Dataframe of species.csv file.
|
|
50
|
+
|
|
51
|
+
models: pandas.DataFrame
|
|
52
|
+
Typically dataframe of models.csv file
|
|
53
|
+
Minimum requirement is dataframe with row labels of "Hspeciation" and "water" and column label of "option"
|
|
54
|
+
See models.csv for available options
|
|
55
|
+
|
|
56
|
+
Returns
|
|
57
|
+
-------
|
|
58
|
+
Solubility constant for H2O as <class 'mpfr'>
|
|
59
|
+
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
if models.loc["Hspeciation","option"] == "none": ### C_H2O = (xmH2O)^2/fH2O ### (mole fraction)
|
|
63
|
+
model = models.loc["water","option"]
|
|
64
|
+
if model == "ETN-1" or model == "PST-9": # Fitted to ETN-1 and PST-9 from Lesne et al. (2011) 162:133-151
|
|
65
|
+
C = 4.77591e-6
|
|
66
|
+
elif model == "VES-9": # Fitted to VES-9 from Lesne et al. (2011) 162:133-151
|
|
67
|
+
C = 5.46061e-6
|
|
68
|
+
elif model == "rhyolite": # Fitted to Blank et al. (1993) and Silver et al. (1990) datasets
|
|
69
|
+
C = 5.13488743E-06
|
|
70
|
+
elif model == "evo": # Fitted to match EVo
|
|
71
|
+
C = 2.782e-6
|
|
72
|
+
elif model == "Lesne11mod": # modified general model from Lesne et al. (2011) 162:133-151
|
|
73
|
+
C = 5.62316e-6
|
|
74
|
+
elif model == "AllisonDataComp": # fitted to experimental data compilation from Allison et al. (2022) for H2O < 6 wt%
|
|
75
|
+
C = 4.6114e-6
|
|
76
|
+
elif model == "test": #test
|
|
77
|
+
R_ = 83.144621 # cm3 bar K−1 mol−1
|
|
78
|
+
DV = 12 # cm3/mol
|
|
79
|
+
P0 = 1.0 # bar
|
|
80
|
+
A = 4.6114e-6
|
|
81
|
+
B = -((DV/(R_*T_K))*(P-P0))
|
|
82
|
+
C = A*gp.exp(B)
|
|
83
|
+
elif model == "test2": # for Ptot paper
|
|
84
|
+
C = gp.exp(-12.29)
|
|
85
|
+
elif model == "carbon":
|
|
86
|
+
C = 1.5e-9
|
|
87
|
+
elif model == "test3":
|
|
88
|
+
C = 6.22885E-09 # like 1000 ppm H2O at 730 bar
|
|
89
|
+
|
|
90
|
+
elif models.loc["Hspeciation","option"] == "linear": ### C_H2O = xmH2O/fH2O ### (mole fraction)
|
|
91
|
+
C = 0.00007925494 # like AllisonDataComp... I think.
|
|
92
|
+
|
|
93
|
+
else: ### C_H2O = xmH2Omol/fH2O ### (mole fraction)
|
|
94
|
+
P = PT['P']
|
|
95
|
+
model = models.loc["water","option"]
|
|
96
|
+
P0 = 1.0 # bar
|
|
97
|
+
R = 83.15 # cm3 etc.
|
|
98
|
+
T0 = 1473.15 # K
|
|
99
|
+
if model == "Dixon95": # Dixon et al. (1995) - no compositional dependence
|
|
100
|
+
DV = 12.
|
|
101
|
+
A = 3.28e-5
|
|
102
|
+
C = A*gp.exp((-DV*(P-P0))/(R*T0))
|
|
103
|
+
elif model == "alkali basalt": # Lesne et al. (2011) 162:133-151 eqn 31 with added RT term otherwise it will not work
|
|
104
|
+
A = 5.71e-5 # XmH2Om0
|
|
105
|
+
DV = 26.9 # VH2Om0 in cm3/mol
|
|
106
|
+
C = A*gp.exp((-DV*(P-P0))/(R*T0))
|
|
107
|
+
elif model == "ETN-1": # Fitted to ETN-1 and VES-9 Xm_H2Omol calculated at 1200 'C data from Lesne et al. (2011) 162:133-151
|
|
108
|
+
C = 3.3989655e-6
|
|
109
|
+
elif model == "VES-9": # Fitted to ETN-1 and VES-9 Xm_H2Omol calculated at 1200 'C data from Lesne et al. (2011) 162:133-151
|
|
110
|
+
C = 3.3989655e-6
|
|
111
|
+
elif model == "PST-9": # Fitted to PST-9 Xm_H2Omol calculated at 1200 'C data from Lesne et al. (2011) 162:133-151
|
|
112
|
+
C = 1.7022269e-6
|
|
113
|
+
|
|
114
|
+
return C
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
##############################################
|
|
119
|
+
### Solubility constant for carbon dioxide ###
|
|
120
|
+
##############################################
|
|
121
|
+
def C_CO3(PT,melt_wf,species,models): ### C_CO2,T = xmCO2,T/fCO2 ### (mole fraction) ***except Shishkina14 - wmCO2 ppm***
|
|
122
|
+
|
|
123
|
+
"""
|
|
124
|
+
Solubility constant for disolving CO2 in the melt: C_CO2,T = xmCO2,T/fCO2 [all oxidised carbon - i.e., CO2mol and CO32- - as CO2,T]
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
Parameters
|
|
128
|
+
----------
|
|
129
|
+
PT: pandas.DataFrame
|
|
130
|
+
Dataframe of pressure-temperature conditions
|
|
131
|
+
pressure (bars) as "P"
|
|
132
|
+
temperature ('C) as "T"
|
|
133
|
+
|
|
134
|
+
melt_wf: pandas.DataFrame
|
|
135
|
+
Dataframe of melt composition (SiO2, TiO2, etc.)
|
|
136
|
+
Not normally required unless "carbon dioxide" option requires melt composition.
|
|
137
|
+
|
|
138
|
+
species: pandas.DataFrame
|
|
139
|
+
Dataframe of species.csv file.
|
|
140
|
+
|
|
141
|
+
models: pandas.DataFrame
|
|
142
|
+
Typically dataframe of models.csv file
|
|
143
|
+
Minimum requirement is dataframe with row label of "carbon dioxide" and column label of "option"
|
|
144
|
+
See models.csv for available options
|
|
145
|
+
|
|
146
|
+
Returns
|
|
147
|
+
-------
|
|
148
|
+
Solubility constant for CO2 as <class 'mpfr'>
|
|
149
|
+
|
|
150
|
+
"""
|
|
151
|
+
|
|
152
|
+
model = models.loc["carbon dioxide","option"]
|
|
153
|
+
|
|
154
|
+
P = PT['P']
|
|
155
|
+
T_K = PT['T']+273.15
|
|
156
|
+
# Calculate cation proportions with no volatiles but correct Fe speciation if available (a la Dixon 1997)
|
|
157
|
+
melt_comp = mg.melt_cation_proportion(melt_wf,species,"no","no")
|
|
158
|
+
|
|
159
|
+
R = 83.15
|
|
160
|
+
T0 = 1473.15 # K
|
|
161
|
+
PI = -6.5*(melt_comp["Si"]+melt_comp["Al"]) + 20.17*(melt_comp["Ca"] + 0.8*melt_comp["K"] + 0.7*melt_comp["Na"] + 0.4*melt_comp["Mg"] + 0.4*melt_comp["FeT"]) # Dixon (1997) Am. Min. 82:368-378
|
|
162
|
+
PI_ = (melt_comp["Ca"] + 0.8*melt_comp["K"] + 0.7*melt_comp["Na"] + 0.4*melt_comp["Mg"] + 0.4*melt_comp["FeT"])/(melt_comp["Si"] + melt_comp["Al"]) # Shishkina et al. (2014) Chem. Geol. 388:112-129
|
|
163
|
+
DH = -13.1 # kJ/mol # Lesne et al. (2011) CMP 162:153-168 from basanite of Holloway & Blank (1994)
|
|
164
|
+
|
|
165
|
+
if model == "Dixon95": # Dixon et al. (1995)
|
|
166
|
+
DV = 23. # cm3/mol
|
|
167
|
+
P0 = 1.0 # bar
|
|
168
|
+
A = 3.8e-7
|
|
169
|
+
B = (-DV*(P-P0))/(R*T0)
|
|
170
|
+
C = A*gp.exp(B)
|
|
171
|
+
elif model == "Dixon97": # Compositional dependence from Dixon (1997) Am. Min. 82:368-378 as shown by Witham et al. (2012) [assumes PI-SiO2 relationship in caption of figre 2 is 10.19 instead of 10.9 - if 10.9 is assumed you get negative C_CO3]
|
|
172
|
+
DV = 23 # cm3/mol
|
|
173
|
+
P0 = 1.0 # bar
|
|
174
|
+
A = (7.94e-7)*(PI+0.762)
|
|
175
|
+
B = (-DV*(P-P0))/(R*T0)
|
|
176
|
+
C = A*gp.exp(B)
|
|
177
|
+
elif model == "Lesne11": # Lesne et al. (2011)
|
|
178
|
+
DV = 23 # cm3/mol
|
|
179
|
+
P0 = 1.0 # bar
|
|
180
|
+
A = 7.94e-7*((((871*PI)+93.0)/1000.0)+0.762)
|
|
181
|
+
B = (-DV*(P-P0))/(R*T0)
|
|
182
|
+
C = A*gp.exp(B)
|
|
183
|
+
elif model == "VES-9": # Lesne et al. (2011) CMP 162:153-168
|
|
184
|
+
DV = 31.0 # cm3/mol
|
|
185
|
+
P0 = 1000.0 # bar
|
|
186
|
+
A = gp.exp(-14.10)
|
|
187
|
+
B = -((DV/(R*T_K))*(P-P0)) + (DH/R)*((1.0/T0) - (1.0/T_K))
|
|
188
|
+
C = A*gp.exp(B)
|
|
189
|
+
elif model == "ETN-1": # Lesne et al. (2011) CMP 162:153-168
|
|
190
|
+
DV = 23.0 # cm3/mol
|
|
191
|
+
P0 = 1000.0 # bar
|
|
192
|
+
A = gp.exp(-14.55)
|
|
193
|
+
B = -((DV/(R*T_K))*(P-P0)) + (DH/R)*((1.0/T0) - (1.0/T_K))
|
|
194
|
+
C = A*gp.exp(B)
|
|
195
|
+
elif model == "PST-9": # Lesne et al. (2011) CMP 162:153-168
|
|
196
|
+
DV = 6.0 # cm3/mol
|
|
197
|
+
P0 = 1000.0 # bar
|
|
198
|
+
A = gp.exp(-14.74)
|
|
199
|
+
B = -((DV/(R*T_K))*(P-P0)) + (DH/R)*((1.0/T0) - (1.0/T_K))
|
|
200
|
+
C = A*gp.exp(B)
|
|
201
|
+
elif model == "Shishkina14": # modified from Shishkina et al. (2014) Chem. Geol. 388:112-129
|
|
202
|
+
A = 1.164 # modified by converting P^A to APyCO2 but only including data up to and including 400 MPa
|
|
203
|
+
B = 6.71*PI_-1.345
|
|
204
|
+
C = A*gp.exp(B)
|
|
205
|
+
elif model == "Sunset Crater": # Sunset Crater from Allison et al. (2022) CMP 177:40
|
|
206
|
+
R_ = 83.144621 # cm3 bar K−1 mol−1
|
|
207
|
+
DV = 16.40 # cm3/mol
|
|
208
|
+
P0 = 1000.0 # bar
|
|
209
|
+
A = gp.exp(-14.67)
|
|
210
|
+
B = -((DV/(R_*T_K))*(P-P0))
|
|
211
|
+
C = A*gp.exp(B)
|
|
212
|
+
elif model == "SFVF": # SFVF from Allison et al. (2022) CMP 177:40
|
|
213
|
+
R_ = 83.144621 # cm3 bar K−1 mol−1
|
|
214
|
+
DV = 15.02 # cm3/mol
|
|
215
|
+
P0 = 1000.0 # bar
|
|
216
|
+
A = gp.exp(-14.87)
|
|
217
|
+
B = -((DV/(R_*T_K))*(P-P0))
|
|
218
|
+
C = A*gp.exp(B)
|
|
219
|
+
elif model == "Erebus": # Erebus from Allison et al. (2022) CMP 177:40
|
|
220
|
+
R_ = 83.144621 # cm3 bar K−1 mol−1
|
|
221
|
+
DV = -14.65 # cm3/mol
|
|
222
|
+
P0 = 1000.0 # bar
|
|
223
|
+
A = gp.exp(-14.65)
|
|
224
|
+
B = -((DV/(R_*T_K))*(P-P0))
|
|
225
|
+
C = A*gp.exp(B)
|
|
226
|
+
elif model == "Vesuvius": # Vesuvius from Allison et al. (2022) CMP 177:40
|
|
227
|
+
R_ = 83.144621 # cm3 bar K−1 mol−1
|
|
228
|
+
DV = 24.42 # cm3/mol
|
|
229
|
+
P0 = 1000.0 # bar
|
|
230
|
+
A = gp.exp(-14.04)
|
|
231
|
+
B = -((DV/(R_*T_K))*(P-P0))
|
|
232
|
+
C = A*gp.exp(B)
|
|
233
|
+
elif model == "Etna": # Etna from Allison et al. (2022) CMP 177:40
|
|
234
|
+
R_ = 83.144621 # cm3 bar K−1 mol−1
|
|
235
|
+
DV = 21.59 # cm3/mol
|
|
236
|
+
P0 = 1000.0 # bar
|
|
237
|
+
A = gp.exp(-14.28)
|
|
238
|
+
B = -((DV/(R_*T_K))*(P-P0))
|
|
239
|
+
C = A*gp.exp(B)
|
|
240
|
+
elif model == "Stromboli": # Stromboli from Allison et al. (2022) CMP 177:40
|
|
241
|
+
R_ = 83.144621 # cm3 bar K−1 mol−1
|
|
242
|
+
DV = 14.93 # cm3/mol
|
|
243
|
+
P0 = 1000.0 # bar
|
|
244
|
+
A = gp.exp(-14.68)
|
|
245
|
+
B = -((DV/(R_*T_K))*(P-P0))
|
|
246
|
+
C = A*gp.exp(B)
|
|
247
|
+
elif model == "Basanite": # Basanite composition from Holloway and Blank (1994), data from Allison et al. (2022) CMP 177:40
|
|
248
|
+
R_ = 83.144621 # cm3 bar K−1 mol−1
|
|
249
|
+
DV = 21.72 # cm3/mol
|
|
250
|
+
P0 = 1000.0 # bar
|
|
251
|
+
A = gp.exp(-14.32)
|
|
252
|
+
B = -((DV/(R_*T_K))*(P-P0))
|
|
253
|
+
C = A*gp.exp(B)
|
|
254
|
+
elif model == "Leucite": # Leucite composition from Thibault and Holloway (1994), data from Allison et al. (2022) CMP 177:40
|
|
255
|
+
R_ = 83.144621 # cm3 bar K−1 mol−1
|
|
256
|
+
DV = 21.53 # cm3/mol
|
|
257
|
+
P0 = 1000.0 # bar
|
|
258
|
+
A = gp.exp(-13.36)
|
|
259
|
+
B = -((DV/(R_*T_K))*(P-P0))
|
|
260
|
+
C = A*gp.exp(B)
|
|
261
|
+
elif model == "AH3 phonotephrite": # AH3 Phonotephrite composition from Vetere et al. (2014), data from Allison et al. (2022) CMP 177:40
|
|
262
|
+
R_ = 83.144621 # cm3 bar K−1 mol−1
|
|
263
|
+
DV = 30.45 # cm3/mol
|
|
264
|
+
P0 = 1000.0 # bar
|
|
265
|
+
A = gp.exp(-13.26)
|
|
266
|
+
B = -((DV/(R_*T_K))*(P-P0))
|
|
267
|
+
C = A*gp.exp(B)
|
|
268
|
+
elif model == "N72 Basalt": # N72 basalt composition from Shishkina et al. (2010), data from Allison et al. (2022) CMP 177:40
|
|
269
|
+
R_ = 83.144621 # cm3 bar K−1 mol−1
|
|
270
|
+
DV = 19.05 # cm3/mol
|
|
271
|
+
P0 = 1000.0 # bar
|
|
272
|
+
A = gp.exp(-14.86)
|
|
273
|
+
B = -((DV/(R_*T_K))*(P-P0))
|
|
274
|
+
C = A*gp.exp(B)
|
|
275
|
+
elif model == "Allison22mod": # modified from Allison et al. (2022) CMP 177:40
|
|
276
|
+
P0 = 1000. # bars
|
|
277
|
+
R_ = 83.144621 # cm3 bar K−1 mol−1
|
|
278
|
+
DV = -3350.650 + 3375.552*(Si+Na) + 2625.385*Ti + 3105.426*Al + 3628.018*Fe2 + 3323.320*(Mg+Ca) + 3795.115*K + 47.004*(Na/(Na+K)) # cm/mol
|
|
279
|
+
lnK0 = -128.365 + 114.098*Si + 92.263*(Ti+Al) + 122.644*(Fe2+Ca+Na) + 111.549*Mg + 138.855*K + 2.239*(Na/(Na+K))
|
|
280
|
+
A = gp.exp(lnK0)
|
|
281
|
+
B = ((-1.*DV)*(P-P0))/(R_*T_K)
|
|
282
|
+
C = A*gp.exp(B)
|
|
283
|
+
elif model == "scaledCsulfate": # O'Neill & Mavrogenes (2022) GCA 334:368-382 eq[12a]
|
|
284
|
+
# Mole fractions in the melt on cationic lattice (all Fe as FeO) no volatiles
|
|
285
|
+
lnC = -8.02 + ((21100. + 44000.*Na + 18700.*Mg + 4300.*Al + 44200.*K + 35600.*Ca + 12600.*Mn + 16500.*FeT)/T_K) #CS6+ = [S6+, ppm]/fSO3
|
|
286
|
+
Csulfate = gp.exp(lnC)*KOSg2(PT,models) # ppm S
|
|
287
|
+
lnCsulfate = math.log(Csulfate)
|
|
288
|
+
lnC=-0.46*lnCsulfate
|
|
289
|
+
A = gp.exp(lnC)
|
|
290
|
+
DV = 23.
|
|
291
|
+
P0 = 1000. # bars
|
|
292
|
+
R_ = 83.144621 # cm3 bar K−1 mol−1
|
|
293
|
+
B = ((-1.*DV)*(P-P0))/(R_*T_K)
|
|
294
|
+
C = A*gp.exp(B)
|
|
295
|
+
elif model == "Blank93": # Blank et al. (1993) - rhyolite - tried for workshop
|
|
296
|
+
DV = 28 # cm3/mol
|
|
297
|
+
P0 = 1.0 # bar
|
|
298
|
+
A = gp.exp(-14.45)
|
|
299
|
+
B = (-DV*(P-P0))/(R*(850.+273.15))
|
|
300
|
+
C = A*gp.exp(B)
|
|
301
|
+
elif model == "Behrens04fit": # Fit to Behrens et al. (2004) - tried for workshop
|
|
302
|
+
DV = 41.8 # cm3/mol
|
|
303
|
+
P0 = 1.0 # bar
|
|
304
|
+
A = gp.exp(-14.2)
|
|
305
|
+
B = (-DV*(P-P0))/(R*(1250.+273.15))
|
|
306
|
+
C = A*gp.exp(B)
|
|
307
|
+
elif model == "dacite": # Fit to Behrens et al. (2004) using Ptot
|
|
308
|
+
DV = 36.5 # cm3/mol
|
|
309
|
+
P0 = 1.0 # bar
|
|
310
|
+
A = gp.exp(-14.3)
|
|
311
|
+
B = (-DV*(P-P0))/(R*(1250.+273.15))
|
|
312
|
+
C = A*gp.exp(B)
|
|
313
|
+
elif model == "test": # for Ptot paper!!!
|
|
314
|
+
P0 = 1.0 # bar
|
|
315
|
+
# "CO2mol"
|
|
316
|
+
#DV1 = 24.2340838328 # cm3/mol
|
|
317
|
+
#A1 = gp.exp(-14.92978383)
|
|
318
|
+
#B1 = (-DV1*(P-P0))/(R*T_K)
|
|
319
|
+
# "CO32-"
|
|
320
|
+
#DV2 = 8.912862511 # cm3/mol
|
|
321
|
+
#A2 =gp.exp(])
|
|
322
|
+
#B2 = (-DV2*(P-P0))/(R*T_K)
|
|
323
|
+
#C = A1*gp.exp(B1) + A2*gp.exp(B2)
|
|
324
|
+
# "average"
|
|
325
|
+
DV2 = 16.57 # cm3/mol
|
|
326
|
+
A2 =gp.exp(-15.275)
|
|
327
|
+
B2 = (-DV2*(P-P0))/(R*T_K)
|
|
328
|
+
C = A2*gp.exp(B2)
|
|
329
|
+
elif model == "water":
|
|
330
|
+
C = 27.e-6
|
|
331
|
+
return C
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
########################################
|
|
335
|
+
### solubility constant for sulfide ###
|
|
336
|
+
########################################
|
|
337
|
+
def C_S(PT,melt_wf,species,models): ### C_S = wmS2-*(fO2/fS2)^0.5 ### (weight ppm)
|
|
338
|
+
|
|
339
|
+
"""
|
|
340
|
+
Solubility constant for disolving S in the melt as S2- in ppmw: C_S = wmS2-*(fO2/fS2)^0.5
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
Parameters
|
|
344
|
+
----------
|
|
345
|
+
PT: pandas.DataFrame
|
|
346
|
+
Dataframe of pressure-temperature conditions
|
|
347
|
+
pressure (bars) as "P"
|
|
348
|
+
temperature ('C) as "T"
|
|
349
|
+
|
|
350
|
+
melt_wf: pandas.DataFrame
|
|
351
|
+
Dataframe of melt composition (SiO2, TiO2, etc.)
|
|
352
|
+
|
|
353
|
+
species: pandas.DataFrame
|
|
354
|
+
Dataframe of species.csv file.
|
|
355
|
+
|
|
356
|
+
models: pandas.DataFrame
|
|
357
|
+
Typically dataframe of models.csv file
|
|
358
|
+
Minimum requirement is dataframe with row label of "sulfide" and column label of "option"
|
|
359
|
+
See models.csv for available options
|
|
360
|
+
|
|
361
|
+
Returns
|
|
362
|
+
-------
|
|
363
|
+
Solubility constant for CO2 as <class 'mpfr'>
|
|
364
|
+
|
|
365
|
+
"""
|
|
366
|
+
|
|
367
|
+
model = models.loc["sulfide","option"]
|
|
368
|
+
|
|
369
|
+
T = PT['T'] + 273.15 # T in K
|
|
370
|
+
|
|
371
|
+
def ONeill21(T,melt_comp):
|
|
372
|
+
lnC = (8.77 - (23590.0/T) + (1673.0/T)*(6.7*(melt_comp["Na"]+melt_comp["K"]) + 4.9*melt_comp["Mg"] + 8.1*melt_comp["Ca"] + 8.9*(melt_comp["FeT"]+melt_comp["Mn"]) + 5.0*melt_comp["Ti"] + 1.8*melt_comp["Al"] - 22.2*melt_comp["Ti"]*(melt_comp["FeT"]+melt_comp["Mn"]) + 7.2*melt_comp["FeT"]*melt_comp["Si"]) - 2.06*math.erf(-7.2*(melt_comp["FeT"]+melt_comp["Mn"])))
|
|
373
|
+
return lnC
|
|
374
|
+
|
|
375
|
+
if model == "ONeill21":
|
|
376
|
+
# Mole fractions in the melt on cationic lattice (all Fe as FeO) no volatiles
|
|
377
|
+
melt_comp = mg.melt_cation_proportion(melt_wf,species,"no","no")
|
|
378
|
+
lnC = ONeill21(T,melt_comp)
|
|
379
|
+
|
|
380
|
+
if model == "ONeill21dil":
|
|
381
|
+
# Mole fractions in the melt on cationic lattice (all Fe as FeO) no volatiles
|
|
382
|
+
melt_comp = mg.melt_cation_proportion(melt_wf,species,"water","no")
|
|
383
|
+
lnC = ONeill21(T,melt_comp)
|
|
384
|
+
|
|
385
|
+
if model == "ONeill21hyd":
|
|
386
|
+
# Mole fractions in the melt on cationic lattice (all Fe as FeO) no volatiles
|
|
387
|
+
melt_comp = mg.melt_cation_proportion(melt_wf,species,"no","no")
|
|
388
|
+
lnC_nondil = ONeill21(T,melt_comp)
|
|
389
|
+
melt_comp = mg.melt_cation_proportion(melt_wf,species,"water","no")
|
|
390
|
+
lnCdil = ONeill21(T,melt_comp)
|
|
391
|
+
lnCH = (melt_comp["H"]*(6.4 + 12.4*melt_comp["H"] - 20.3*melt_comp["Si"] + 73.0*(melt_comp["Na"]+melt_comp["K"])))
|
|
392
|
+
lnC = lnCdil+lnCH
|
|
393
|
+
|
|
394
|
+
elif model == "FR54-S1":
|
|
395
|
+
lnC = math.log(((1.3e-4)*10000.))
|
|
396
|
+
|
|
397
|
+
C = math.exp(lnC)
|
|
398
|
+
return C
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
########################################
|
|
403
|
+
### solubility constant for sulfate ###
|
|
404
|
+
########################################
|
|
405
|
+
def C_SO4(PT,melt_wf,species,models): ### C_SO4 = wmS6+*(fS2*fO2^3)^-0.5 ### (weight ppm)
|
|
406
|
+
model = models.loc["sulfate","option"]
|
|
407
|
+
T = PT['T'] + 273.15 # T in Kelvin
|
|
408
|
+
P = PT['P'] # P in bars
|
|
409
|
+
slope = 115619.707 # slope for T-dependence for melt inclusion fits
|
|
410
|
+
|
|
411
|
+
if model == "Nash19": # Nash et al. (2019) EPSL 507:187-198
|
|
412
|
+
S = 1. # S6+/S2- ratio of S6+/S2- of 0.5
|
|
413
|
+
Csulfide = C_S(PT,melt_wf,species,models)
|
|
414
|
+
A = PT_KCterm(PT,melt_wf,species,models) # P, T, compositional term from Kress & Carmicheal (1991)
|
|
415
|
+
B = (8743600/T**2) - (27703/T) + 20.273 # temperature dependence from Nash et al. (2019)
|
|
416
|
+
a = 0.196 # alnfO2 from Kress & Carmicheal (1991)
|
|
417
|
+
F = 10**(((math.log10(S))-B)/8.)
|
|
418
|
+
fO2 = math.exp(((math.log(0.5*F))-A)/a)
|
|
419
|
+
Csulfate = (S*Csulfide)/(fO2**2)
|
|
420
|
+
elif model == "S6ST":
|
|
421
|
+
Csulfide = C_S(PT,melt_wf,species,models)
|
|
422
|
+
fO2 = f_O2(PT,melt_wf,species,models)
|
|
423
|
+
S6ST_ = melt_wf["S6ST"]
|
|
424
|
+
S = overtotal2ratio(S6ST_)
|
|
425
|
+
Csulfate = (S*Csulfide)/(fO2**2)
|
|
426
|
+
elif model == "Hawaii":
|
|
427
|
+
#Csulfate = gp.exp(30.4) # Using Brounce et al. (2017) dataset at 1200 'C
|
|
428
|
+
Csulfate = math.exp(slope*(1./T) -48.)
|
|
429
|
+
elif model == "Etna":
|
|
430
|
+
Csulfate = math.exp(slope*(1./T) -50.15)
|
|
431
|
+
elif model == "Fuego":
|
|
432
|
+
Csulfate = math.exp(slope*(1./T) -48.5)
|
|
433
|
+
elif model == "Erta Ale":
|
|
434
|
+
Csulfate = math.exp(slope*(1./T) -45.5)
|
|
435
|
+
elif model == "FR54-S1":
|
|
436
|
+
Csulfate = ((67.e6)*10000.)
|
|
437
|
+
elif model == "JdF": # 1100 'C ONLY
|
|
438
|
+
Csulfate = 10.**17.
|
|
439
|
+
elif model == "Boulliung22nP": # Boullioung & Wood (2022) GCA 336:150-164 [eq5] - corrected!
|
|
440
|
+
# Mole fractions in the melt on cationic lattice (all Fe as FeO) no volatiles
|
|
441
|
+
melt_comp = mg.melt_cation_proportion(melt_wf,species,"no","no")
|
|
442
|
+
logCS6 = -12.948 + ((15602.*melt_comp["Ca"] + 28649.*melt_comp["Na"] - 9596.*melt_comp["Mg"] + 4194.*melt_comp["Al"] +16016.*melt_comp["Mn"] + 29244.)/T) # wt% S
|
|
443
|
+
Csulfate = (10.**logCS6)*10000. # ppm S
|
|
444
|
+
elif model == "Boulliung22wP": # Boullioung & Wood (2022) GCA 336:150-164 [eq5] - corrected!
|
|
445
|
+
# Mole fractions in the melt on cationic lattice (all Fe as FeO) no volatiles
|
|
446
|
+
melt_comp = mg.melt_cation_proportion(melt_wf,species,"no","no")
|
|
447
|
+
logCS6 = -12.659 + ((3692.*melt_comp["Ca"] - 7592.*melt_comp["Si"] - 13736.*melt_comp["Ti"] + 3762.*melt_comp["Al"] + 34483)/T) - (0.1*P*1.5237)/T # wt% S
|
|
448
|
+
Csulfate = (10.**logCS6)*10000. # ppm S
|
|
449
|
+
elif model in ["ONeill22","ONeill22dil"]:
|
|
450
|
+
if model == "ONeill22": # O'Neill & Mavrogenes (2022) GCA 334:368-382 eq[12a]
|
|
451
|
+
melt_comp = mg.melt_cation_proportion(melt_wf,species,"no","yes") # Mole fractions in the melt on cationic lattice (Fe as Fe2 and Fe3) no volatiles
|
|
452
|
+
elif model == "ONeill22dil": # O'Neill & Mavrogenes (2022) GCA 334:368-382 eq[12a]
|
|
453
|
+
melt_comp = mg.melt_cation_proportion(melt_wf,species,"water","yes") # Mole fractions in the melt on cationic lattice (Fe as Fe2 and Fe3) includes water
|
|
454
|
+
lnC = -8.02 + ((21100. + 44000.*melt_comp["Na"] + 18700.*melt_comp["Mg"] + 4300.*melt_comp["Al"] + 44200.*melt_comp["K"] + 35600.*melt_comp["Ca"] + 12600.*melt_comp["Mn"] + 16500.*melt_comp["Fe2"])/T) #CS6+ = [S6+, ppm]/fSO3
|
|
455
|
+
Csulfate = gp.exp(lnC)*KOSg2(PT,models) # ppm S
|
|
456
|
+
|
|
457
|
+
return Csulfate
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
###################################
|
|
462
|
+
### solubility constant for H2S ###
|
|
463
|
+
###################################
|
|
464
|
+
def C_H2S(PT,melt_wf,species,models): # C_H2S = wmH2S/fH2S (ppm H2S, fH2S bar)
|
|
465
|
+
model = models.loc["hydrogen sulfide","option"]
|
|
466
|
+
if model == "basalt":
|
|
467
|
+
K = 10.23 # fitted to basalt data from Moune+ 2009 CMP 157:691–707 and Lesne+ 2015 ChemGeol 418:104–116
|
|
468
|
+
elif model == "basaltic andesite":
|
|
469
|
+
K = 6.82 # fitted to basaltic andesite data from Moune+ 2009 CMP 157:691–707 and Lesne+ 2015 ChemGeol 418:104–116
|
|
470
|
+
return K
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
########################################
|
|
475
|
+
### solubility constant for hydrogen ###
|
|
476
|
+
########################################
|
|
477
|
+
def C_H2(PT,melt_wf,species,models): # C_H2 = wmH2/fH2 (wtppm)
|
|
478
|
+
# Hirchmann et al. (2012) EPSL 345-348:38-48
|
|
479
|
+
model = models.loc["hydrogen","option"]
|
|
480
|
+
R = 83.144598 # bar cm3 /mol /K
|
|
481
|
+
P = PT['P'] # pressure in bars
|
|
482
|
+
T = PT['T'] + 273.15 # T in Kelvin SHOULD BE T0
|
|
483
|
+
P0 = 100.*0.01 # kPa to bars
|
|
484
|
+
if model == "basalt":
|
|
485
|
+
#lnK0 = -11.4 # T0 = 1400 'C, P0 = 100 kPa for mole fraction H2
|
|
486
|
+
lnK0 = -0.9624 # for ppm H2 (fitted in excel)
|
|
487
|
+
DV = 10.6 # cm3/mol
|
|
488
|
+
elif model == "andesite":
|
|
489
|
+
#lnK0 = -10.6 # T0 = 1400 'C, P0 = 100 kPa for mole fraction H2
|
|
490
|
+
lnK0 = -0.1296 # for ppm H2 (fitted in excel)
|
|
491
|
+
DV = 11.3 # cm3/mol
|
|
492
|
+
lnK = lnK0 - (DV*(P-P0))/(R*T) # = ln(XH2/fH2) in ppm/bar
|
|
493
|
+
C = gp.exp(lnK)
|
|
494
|
+
return C
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
######################################
|
|
499
|
+
### solubility constant for methane ##
|
|
500
|
+
######################################
|
|
501
|
+
def C_CH4(PT,melt_wf,species,models): # C_CH4 = wmCH4/fCH4 (ppm)
|
|
502
|
+
model = models.loc["methane","option"]
|
|
503
|
+
if model == "Ardia13": # Ardia et al. (2013) GCA 114:52-71
|
|
504
|
+
R = 83.144598 # bar cm3 /mol /K
|
|
505
|
+
P = PT['P'] # pressure in bars
|
|
506
|
+
T = PT['T'] + 273.15 # T in Kelvin SHOULD BE T0
|
|
507
|
+
P0 = 100.*0.01 # kPa to bars
|
|
508
|
+
lnK0 = 4.93 # ppm CH4
|
|
509
|
+
#lnK0 = -7.63 # mole fraction CH4
|
|
510
|
+
DV = 26.85 # cm3/mol
|
|
511
|
+
lnK = lnK0 - (DV*(P-P0))/(R*T)
|
|
512
|
+
K_ = gp.exp(lnK) # for fCH4 in GPa
|
|
513
|
+
K = 0.0001*K_ # for fCH4 in bars
|
|
514
|
+
return K
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
#################################
|
|
519
|
+
### solubility constant for CO ##
|
|
520
|
+
#################################
|
|
521
|
+
def C_CO(PT,melt_wf,species,models): # C_CO = wmCO/fCO (ppm)
|
|
522
|
+
model = models.loc["carbon monoxide","option"]
|
|
523
|
+
if model == "basalt": # from fitting Armstrong et al. (2015) GCA 171:283-302; Stanley+2014, and Wetzel+13 thermodynamically
|
|
524
|
+
R = 83.144598 # bar cm3 /mol /K
|
|
525
|
+
P = PT['P'] # pressure in bars
|
|
526
|
+
T = PT['T'] +273.15 # T in Kelvin
|
|
527
|
+
P0 = 1. # in bars
|
|
528
|
+
lnK0 = -2.11 # ppm CO
|
|
529
|
+
DV = 15.20 # cm3/mol
|
|
530
|
+
lnK = lnK0 - (DV*(P-P0))/(R*T)
|
|
531
|
+
K = gp.exp(lnK) # CO(ppm)/fCO(bars)
|
|
532
|
+
return K
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
#################################
|
|
536
|
+
### solubility constant for X ###
|
|
537
|
+
#################################
|
|
538
|
+
def C_X(PT,melt_wf,species,models): # C_X = wmX/fX (ppm)
|
|
539
|
+
species = models.loc["species X","option"]
|
|
540
|
+
model = models.loc["species X solubility","option"]
|
|
541
|
+
if species == "Ar":
|
|
542
|
+
if model == "Iacono-Marziano10_Ar_basalt": # Iacono-Marziano et al. (2010) Chemical Geology 279(3–4):145-157
|
|
543
|
+
K = 0.0799 # fitted assuming Ar is an ideal gas... i.e. yAr = 1.
|
|
544
|
+
elif model == "Iacono-Marziano10_Ar_rhyolite": # Iacono-Marziano et al. (2010) Chemical Geology 279(3–4):145-157
|
|
545
|
+
K = 0.4400 # fitted assuming Ar is an ideal gas... i.e. yAr = 1.
|
|
546
|
+
elif model == "test":
|
|
547
|
+
#K = 40. # similar to H2O
|
|
548
|
+
#K = 6. # similar to S @ DFMQ+1.25
|
|
549
|
+
#K = 21. # similar to S @ DFMQ+3
|
|
550
|
+
#K = 155 # similar to S @ DFMQ0
|
|
551
|
+
#K = 918005 # similar to S @DFMQ-3
|
|
552
|
+
#K = 10.23 # similar to H2S
|
|
553
|
+
#K = 0.51 # similar to CO32-
|
|
554
|
+
#K = 1.37 # degassed at a similar depth to H2OT at 3wt%
|
|
555
|
+
#K = 100.
|
|
556
|
+
K = 35.
|
|
557
|
+
if species == "Ne":
|
|
558
|
+
if model == "Iacono-Marziano10_Ne_basalt": # Iacono-Marziano et al. (2010) Chemical Geology 279(3–4):145-157
|
|
559
|
+
K = 0.1504 # fitted assuming Ne is an ideal gas... i.e. yNe = 1.
|
|
560
|
+
elif model == "Iacono-Marziano10_Ne_rhyolite": # Iacono-Marziano et al. (2010) Chemical Geology 279(3–4):145-157
|
|
561
|
+
K = 0.8464 # fitted assuming Ne is an ideal gas... i.e. yNe = 1.
|
|
562
|
+
return K
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
#################################################################################################################################
|
|
566
|
+
################################################ solid/liquid volatile saturation ###############################################
|
|
567
|
+
#################################################################################################################################
|
|
568
|
+
|
|
569
|
+
################################################
|
|
570
|
+
### sulfate content at anhydrite saturation ###
|
|
571
|
+
################################################
|
|
572
|
+
def SCAS(PT,melt_wf,species,models):
|
|
573
|
+
model = models.loc["SCAS","option"]
|
|
574
|
+
T = PT['T'] +273.15
|
|
575
|
+
|
|
576
|
+
comp = mg.melt_pysulfsat(melt_wf,species)
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
if model == "Chowdhury18": # sulfate content (ppm) at anhydrite saturation from Chowdhury & Dasgupta (2018) [T in K]
|
|
580
|
+
# mole fraction melt composition including water but all Fe as FeOT
|
|
581
|
+
melt_comp = mg.melt_mole_fraction(melt_wf,species,models,"water","no")
|
|
582
|
+
tot = 100.*melt_comp["mol_tot"]
|
|
583
|
+
a = -13.23
|
|
584
|
+
b = -0.50
|
|
585
|
+
dSi = 3.02
|
|
586
|
+
dCa = 36.70
|
|
587
|
+
dMg = 2.84
|
|
588
|
+
dFe = 10.14
|
|
589
|
+
dAl = 44.28
|
|
590
|
+
dNa = 26.27
|
|
591
|
+
dK = -25.77
|
|
592
|
+
e = 0.09
|
|
593
|
+
f = 0.54
|
|
594
|
+
wm_H2OT = 100.*melt_wf['H2OT']
|
|
595
|
+
dX = dSi*melt_comp["SiO2"] + dCa*melt_comp["CaO"] + dMg*melt_comp["MgO"] + dFe*melt_comp["FeOT"] + dAl*melt_comp["Al2O3"] + dNa*melt_comp["Na2O"] + dK*melt_comp["K2O"]
|
|
596
|
+
lnxm_SO4 = a + b*((10.0**4.0)/T) + dX + e*wm_H2OT - f*gp.log(melt_comp["CaO"])
|
|
597
|
+
xm_SO4 = gp.exp(lnxm_SO4)
|
|
598
|
+
Xm_SO4 = xm_SO4*(xm_SO4 + tot)
|
|
599
|
+
S6CAS = Xm_SO4*species.loc["S","M"]*10000.0
|
|
600
|
+
|
|
601
|
+
elif model == "Zajacz19":
|
|
602
|
+
# mole fraction melt composition including water but all Fe as FeOT
|
|
603
|
+
melt_comp = mg.melt_mole_fraction(melt_wf,species,models,"water","no")
|
|
604
|
+
tot = 100.*melt_comp["mol_tot"]
|
|
605
|
+
if melt_comp["Na2O"] + melt_comp["K2O"] + melt_comp["CaO"] >= melt_comp["Al2O3"]:
|
|
606
|
+
P_Rhyo = 3.11*(melt_comp["Na2O"]+melt_comp["K2O"]+melt_comp["CaO"]-melt_comp["Al2O3"])
|
|
607
|
+
else:
|
|
608
|
+
P_Rhyo = 1.54*(melt_comp["Al2O3"]-(melt_comp["Na2O"]+melt_comp["K2O"]+melt_comp["CaO"]))
|
|
609
|
+
NBOT = (2.*melt_comp["Na2O"]+2.*melt_comp["K2O"]+2.*(melt_comp["CaO"]+melt_comp["MgO"]+melt_comp["FeOT"])-melt_comp["Al2O3"]*2.)/(melt_comp["SiO2"]+2.*melt_comp["Al2O3"]) # according to spreadsheet not paper
|
|
610
|
+
P_T = gp.exp(-7890./T)
|
|
611
|
+
P_H2O = melt_comp["H2O"]*(2.09 - 1.65*NBOT) + 0.42*NBOT + 0.23
|
|
612
|
+
P_C = ((P_Rhyo + 251.*melt_comp["CaO"]**2. + 57.*melt_comp["MgO"]**2. + 154.*melt_comp["FeOT"]**2.)/(2.*melt_comp["Al2O3"] + melt_comp["SiO2"]))/(1. + 4.8*NBOT)
|
|
613
|
+
Ksm_SPAnh = gp.exp(1.226*gp.log(P_C*P_T*P_H2O) + 0.079)
|
|
614
|
+
Xsm_S = Ksm_SPAnh/melt_comp["CaO"]
|
|
615
|
+
S6CAS = Xsm_S*tot*32.07*10000.
|
|
616
|
+
|
|
617
|
+
elif model == "Liu23": # Liu et al. (2023) GCA 349:135-145 eq. 4
|
|
618
|
+
melt_comp = mg.melt_mole_fraction(melt_wf,species,models,"no","no")
|
|
619
|
+
NBOT = (2.*melt_comp["Na2O"]+2.*melt_comp["K2O"]+2.*(melt_comp["CaO"]+melt_comp["MgO"]+melt_comp["FeOT"])-melt_comp["Al2O3"]*2.)/(melt_comp["SiO2"]+2.*melt_comp["Al2O3"])
|
|
620
|
+
melt_comp = mg.melt_mole_fraction(melt_wf,species,models,"water","no")
|
|
621
|
+
lnSCAS = 12.185 - (8541./T) + (1.409*NBOT) + 9.984*melt_comp["CaO"] + melt_wf["H2OT"]*100.
|
|
622
|
+
S6CAS = gp.exp(lnSCAS)
|
|
623
|
+
|
|
624
|
+
elif model == "pss_CD2019": # Chowdhury & Dasgupta (2019) using PySulfSat by Wieser and Gleeson (2023)
|
|
625
|
+
output = ss.calculate_CD2019_SCAS(df=comp, T_K=T, H2O_Liq=float(100.*melt_wf['H2OT']), Fe3Fet_Liq=None, P_kbar=None)
|
|
626
|
+
S6CAS = float(output["SCAS6_ppm"])
|
|
627
|
+
elif model == "pss_ZT2022": # Zajacz and Tsay (2022) using PySulfSat by Wieser and Gleeson (2023)
|
|
628
|
+
output = ss.calculate_ZT2022_SCAS(df=comp, T_K=T, H2O_Liq=float(100.*melt_wf['H2OT']), Fe3Fet_Liq=None, P_kbar=None)
|
|
629
|
+
S6CAS = float(output["SCAS6_ppm"])
|
|
630
|
+
#elif model == "pss_MK2015": # NOT WORKING: Masotta and Kepler (2015) using PySulfSat by Wieser and Gleeson (2023)
|
|
631
|
+
# output = ss.calculate_MK2015_SCAS(df=comp, T_K=T, H2O_Liq=float(100.*melt_wf['H2OT']), Fe3Fet_Liq=None, P_kbar=None)
|
|
632
|
+
# S6CAS = float(output["SCAS6_ppm"])
|
|
633
|
+
|
|
634
|
+
return S6CAS
|
|
635
|
+
|
|
636
|
+
###############################################
|
|
637
|
+
### sulfide content at sulfide saturation ###
|
|
638
|
+
###############################################
|
|
639
|
+
def SCSS(PT,melt_wf,species,models): # sulfide content (ppm) at sulfide saturation from O'Neill (2020) [P in bar,T in K]
|
|
640
|
+
model = models.loc["SCSS","option"]
|
|
641
|
+
P_bar = PT['P']
|
|
642
|
+
T = PT['T'] + 273.15
|
|
643
|
+
Fe3FeT = melt_wf["Fe3FeT"]
|
|
644
|
+
comp = mg.melt_pysulfsat(melt_wf,species)
|
|
645
|
+
|
|
646
|
+
if model in ["ONeill21","ONeill21dil","ONeill21hyd"]:
|
|
647
|
+
R = 8.31441
|
|
648
|
+
P = (1.0e-4)*P_bar # pressure in GPa
|
|
649
|
+
D = (137778.0 - 91.66*T + 8.474*T*gp.log(T)) # J/mol
|
|
650
|
+
sulfide_comp = 1.0 # assumes the sulfide is pure FeS (no Ni, Cu, etc.)
|
|
651
|
+
if model == "ONeill21":
|
|
652
|
+
# Mole fractions in the melt on cationic lattice (Fe2 and Fe3) no volatiles
|
|
653
|
+
melt_comp = mg.melt_cation_proportion(melt_wf,species,"no","yes")
|
|
654
|
+
elif model == "ONeill21dil":
|
|
655
|
+
# Mole fractions in the melt on cationic lattice (Fe2 and Fe3) and water
|
|
656
|
+
melt_comp = mg.melt_cation_proportion(melt_wf,species,"water","yes")
|
|
657
|
+
elif model == "ONeill21hyd":
|
|
658
|
+
# Mole fractions in the melt on cationic lattice (Fe2 and Fe3) and water
|
|
659
|
+
melt_comp = mg.melt_cation_proportion(melt_wf,species,"water","yes")
|
|
660
|
+
lnaFeS = gp.log((1.0 - melt_comp["Fe2"])*sulfide_comp)
|
|
661
|
+
lnyFe2 = (((1.0-melt_comp["Fe2"])**2.0)*(28870.0 - 14710.0*melt_comp["Mg"] + 1960.0*melt_comp["Ca"] + 43300.0*melt_comp["Na"] + 95380.0*melt_comp["K"] - 76880.0*melt_comp["Ti"]) + (1.0-melt_comp["Fe2"])*(-62190.0*melt_comp["Si"] + 31520.0*melt_comp["Si"]**2.0))/(R*T)
|
|
662
|
+
lnS = D/(R*T) + gp.log(C_S(PT,melt_wf,species,models)) - gp.log(melt_comp["Fe2"]) - lnyFe2 + lnaFeS + (-291.0*P + 351.0*gp.erf(P))/T
|
|
663
|
+
SCSS = gp.exp(lnS)
|
|
664
|
+
|
|
665
|
+
elif model == "Liu07":
|
|
666
|
+
# Mole fractions in the melt on cationic lattice (Fe2 and Fe3) and water
|
|
667
|
+
melt_comp = mg.melt_cation_proportion(melt_wf,species,"water","yes")
|
|
668
|
+
MFM = (melt_comp["Na"]+melt_comp["K"]+2.*(melt_comp["Ca"]+melt_comp["Mg"]+melt_comp["Fe2"]))/(melt_comp["Si"]*(melt_comp["Al"]+melt_comp["Fe3"]))
|
|
669
|
+
lnS = 11.35251 - (4454.6/T) - 0.03190*(PT["P"]/T) + 0.71006*gp.log(MFM) - 1.98063*(MFM*melt_comp["H"]) + 0.21867*gp.log(melt_comp["H"]) + 0.36192*gp.log(melt_comp["Fe2"])
|
|
670
|
+
SCSS = gp.exp(lnS)
|
|
671
|
+
|
|
672
|
+
elif model == "Fortin15":
|
|
673
|
+
# Mole fractions in the melt on cationic lattice (all Fe as FeOT) and water
|
|
674
|
+
melt_comp = mg.melt_cation_proportion(melt_wf,species,"water","no")
|
|
675
|
+
lnS = 34.784 - (5772.3/T) - 346.54*((0.0001*PT["P"])/T) - 20.393*melt_comp["H"] - 25.499*melt_comp["Si"] - 18.344*melt_comp["Ti"] - 27.381*melt_comp["Al"] - 17.275*melt_comp["Fe"] - 22.398*melt_comp["Mg"] - 20.378*melt_comp["Ca"] - 18.954*melt_comp["Na"] - 32.195*melt_comp["K"]
|
|
676
|
+
SCSS = gp.exp(lnS)
|
|
677
|
+
|
|
678
|
+
elif model == "Liu21":
|
|
679
|
+
XFeS = 1.
|
|
680
|
+
H2O = melt_wf["H2OT"]*100.
|
|
681
|
+
SCSS = (XFeS*gp.exp(13.88 - (9744./T) - (328.*(0.0001*PT["P"])/T))) + 104.*H2O
|
|
682
|
+
|
|
683
|
+
elif model == "pss_LiZhang2022": # NOT WORKING Li and Zhang (2022) using PySulfSat by Wieser and Gleeson (2023) - assuming pure FeS
|
|
684
|
+
output = ss.calculate_LiZhang2022_SCSS(df=comp, T_K=T, P_kbar=(P_bar/1000.), H2O_Liq=float(100.*melt_wf['H2OT']), Fe_FeNiCu_Sulf=1., Cu_FeNiCu_Sulf=0., Ni_FeNiCu_Sulf=0., Fe3Fet_Liq=Fe3FeT, logfo2=None,Ni_Liq=None, Cu_Liq=None, Ni_Sulf_init=5, Cu_Sulf_init=5, Fe_Sulf=None, Cu_Sulf=None, Ni_Sulf=None, T_K_transition=True,highT=False, lowT=False)
|
|
685
|
+
SCSS = float(output["SCSS_Tot"])
|
|
686
|
+
elif model == "pss_F2015": # Fortin et al. (2015) using PySulfSat by Wieser and Gleeson (2023)
|
|
687
|
+
output = ss.calculate_F2015_SCSS(df=comp, T_K=T, P_kbar=(P_bar/1000.), H2O_Liq=float(100.*melt_wf['H2OT']), Fe3Fet_Liq=None,Fe_FeNiCu_Sulf=None)
|
|
688
|
+
SCSS = float(output["SCSS2_ppm"])
|
|
689
|
+
elif model == "pss_Liu2021": # Liu et al. (2021) using PySulfSat by Wieser and Gleeson (2023) - assuming pure FeS
|
|
690
|
+
output = ss.calculate_Liu2021_SCSS(df=comp, T_K=T, P_kbar=(P_bar/1000.), Fe_FeNiCu_Sulf=1., H2O_Liq=float(100.*melt_wf['H2OT']), Cu_FeNiCu_Sulf=0., Ni_FeNiCu_Sulf=0.,
|
|
691
|
+
Ni_Liq=None, Cu_Liq=None, Fe_Sulf=None, Cu_Sulf=None, Ni_Sulf=None, Ni_Sulf_init=5, Cu_Sulf_init=5, Fe3Fet_Liq=Fe3FeT)
|
|
692
|
+
SCSS = float(output["SCSS2_ppm"])
|
|
693
|
+
elif model == "pss_OM2022": # O'Neill & Mavrogenes (2022) using PySulfSat by Wieser and Gleeson (2023) - assuming pure FeS
|
|
694
|
+
output = ss.calculate_OM2022_SCSS(df=comp, T_K=T, P_kbar=(P_bar/1000.), Fe3Fet_Liq=Fe3FeT, Fe_FeNiCu_Sulf=1., Cu_FeNiCu_Sulf=0., Ni_FeNiCu_Sulf=0., Fe_Sulf=None, Ni_Sulf=None, Cu_Sulf=None, Ni_Liq=None, Cu_Liq=None, Ni_Sulf_init=5, Cu_Sulf_init=5)
|
|
695
|
+
SCSS = float(output["SCSS2_ppm"])
|
|
696
|
+
elif model == "pss_O2021": # O'Neill (2021) using PySulfSat by Wieser and Gleeson (2023) - assuming pure FeS
|
|
697
|
+
output = ss.calculate_O2021_SCSS(df=comp, T_K=T, P_kbar=(P_bar/1000.), Fe3Fet_Liq=Fe3FeT, Fe_FeNiCu_Sulf=1., Cu_FeNiCu_Sulf=0., Ni_FeNiCu_Sulf=0.,Fe_Sulf=None, Ni_Sulf=None, Cu_Sulf=None,Ni_Liq=None, Cu_Liq=None, Ni_Sulf_init=5, Cu_Sulf_init=5)
|
|
698
|
+
SCSS = float(output["SCSS2_ppm"])
|
|
699
|
+
elif model == "pss_S2017": # Smythe et al. (2017) using PySulfSat by Wieser and Gleeson (2023) - assuming pure FeS
|
|
700
|
+
output = ss.calculate_S2017_SCSS(df=comp, T_K=T, P_kbar=(P_bar/1000.), Fe3Fet_Liq=Fe3FeT, Fe_FeNiCu_Sulf=0.999999, Cu_FeNiCu_Sulf=0.000001, Ni_FeNiCu_Sulf=0.,Fe_Sulf=None, Ni_Sulf=None, Cu_Sulf=None, Ni_Liq=None, Cu_Liq=None, H2O_Liq=float(100.*melt_wf['H2OT']),Ni_Sulf_init=5, Cu_Sulf_init=5)
|
|
701
|
+
SCSS = float(output["SCSS2_ppm_ideal_Smythe2017"])
|
|
702
|
+
return SCSS
|
|
703
|
+
|
|
704
|
+
#################################################################################################################################
|
|
705
|
+
#################################### EQUILIBRIUM CONSTANTS FOR HOMOGENEOUS VAPOR EQUILIBRIA #####################################
|
|
706
|
+
#################################################################################################################################
|
|
707
|
+
|
|
708
|
+
# H2 + 0.5O2 = H2O
|
|
709
|
+
# K = fH2O/(fH2*(fO2)^0.5)
|
|
710
|
+
def KHOg(PT,models):
|
|
711
|
+
T_K = PT['T']+273.15
|
|
712
|
+
if models.loc["KHOg","option"] == "KO97":
|
|
713
|
+
K = 10.**((12510.0/T_K)-0.979*(gp.log10(T_K))+0.483)
|
|
714
|
+
return K
|
|
715
|
+
|
|
716
|
+
# H2O + 0.5S2 = H2S + 0.5O2
|
|
717
|
+
# K = (fH2S*(fO2)^0.5)/((fS2^0.5)*fH2O)
|
|
718
|
+
def KHOSg(PT,models):
|
|
719
|
+
T_K = PT['T']+273.15
|
|
720
|
+
if models.loc["KHOSg","option"] == "KO97": # Kerrick & Ohmoto (1997)
|
|
721
|
+
K = 10.**((-8117.0/T_K)+0.188*gp.log10(T_K)-0.352)
|
|
722
|
+
elif models.loc["KHOSg","option"] == "noH2S": # H2S doesn't form in the gas...
|
|
723
|
+
K = 0.
|
|
724
|
+
return K
|
|
725
|
+
|
|
726
|
+
# 0.5S2 + O2 = SO2
|
|
727
|
+
# K = fSO2/((fS2^0.5)*fO2)
|
|
728
|
+
def KOSg(PT,models):
|
|
729
|
+
T_K = PT['T']+273.15
|
|
730
|
+
if models.loc["KOSg","option"] == "KO97": # Kerrick & Ohmoto (1997)
|
|
731
|
+
K = 10.**((18929.0/T_K)-3.783)
|
|
732
|
+
return K
|
|
733
|
+
|
|
734
|
+
# 0.5S2 + 1.5O2 = SO3
|
|
735
|
+
# K = fSO3/((fS2^0.5)*(fO2^1.5)
|
|
736
|
+
def KOSg2(PT,models):
|
|
737
|
+
T_K = PT['T']+273.15
|
|
738
|
+
if models.loc["KOSg2","option"] == "OM22": # O'Neill+Mavrogenes2022 from JANF
|
|
739
|
+
lnK = (55921./T_K) - 25.07 + 0.6465*gp.log(T_K)
|
|
740
|
+
K = gp.exp(lnK)
|
|
741
|
+
return K
|
|
742
|
+
|
|
743
|
+
# CO + 0.5O = CO2
|
|
744
|
+
# K = fCO2/(fCO*(fO2^0.5))
|
|
745
|
+
def KCOg(PT,models):
|
|
746
|
+
T_K = PT['T']+273.15
|
|
747
|
+
if models.loc["KCOg","option"] == "KO97": # Kerrick & Ohmoto (1997)
|
|
748
|
+
K = 10.**((14751.0/T_K)-4.535)
|
|
749
|
+
return K
|
|
750
|
+
|
|
751
|
+
# CH4 + 2O2 = CO2 + 2H2O
|
|
752
|
+
# K = (fCO2*(fH2O^2))/(fCH4*(fO2^2))
|
|
753
|
+
def KCOHg(PT,models):
|
|
754
|
+
T_K = PT['T']+273.15
|
|
755
|
+
if models.loc["KCOHg","option"] == "KO97": # Kerrick & Ohmoto (1997)
|
|
756
|
+
K = 10.**((41997.0/T_K)+0.719*gp.log10(T_K)-2.404)
|
|
757
|
+
return K
|
|
758
|
+
|
|
759
|
+
def KOCSg(PT,models): # OCS - depends on system
|
|
760
|
+
T = PT['T']+273.15
|
|
761
|
+
if models.loc["carbonylsulfide","option"] == "COHS":
|
|
762
|
+
# OCS + H2O = CO2 + H2S
|
|
763
|
+
# K = (fCO2*fH2S)/(fOCS*fH2O)
|
|
764
|
+
if models.loc["KOCSg","option"] == "EVo":
|
|
765
|
+
K = gp.exp(0.482 + (16.166e-2/T) + 0.081e-3*T - (5.715e-3/T**2) - 2.224e-1*gp.log(T))
|
|
766
|
+
return K
|
|
767
|
+
if models.loc["carbonylsulfide","option"] == "COS":
|
|
768
|
+
# 2CO2 + OCS = 3CO + SO2 -
|
|
769
|
+
# K = (fCO^3*fSO2)/(fCO2^2*fOCS)
|
|
770
|
+
if models.loc["KOCSg","option"] == "Moussallam19": # Moussallam et al. (2019) EPSL 520:260-267
|
|
771
|
+
K = 10.**(9.24403 - (15386.45/T)) # P and f in bars, T in K
|
|
772
|
+
return K
|
|
773
|
+
|
|
774
|
+
# Cgraphite + O2 = CO2
|
|
775
|
+
def KCOs(PT,models):
|
|
776
|
+
T_K = PT['T']+273.15
|
|
777
|
+
P = PT['P']
|
|
778
|
+
if models.loc["KCOs","option"] == "Holloway92": # Holloway et al. (1992) Eur J. Mineral. 4:105-114 equation (3) KI
|
|
779
|
+
a = 40.07639
|
|
780
|
+
b = -2.5392e-2
|
|
781
|
+
c = 5.27096e-6
|
|
782
|
+
d = 0.0267
|
|
783
|
+
log10K = a + (b*T_K) + (c*T_K**2) + ((P-1)/T_K)
|
|
784
|
+
K = 10.**log10K
|
|
785
|
+
return K
|
|
786
|
+
|
|
787
|
+
#################################################################################################################################
|
|
788
|
+
##################################### EQUILIBRIUM CONSTANTS FOR HOMOGENEOUS MELT EQUILIBRIA #####################################
|
|
789
|
+
#################################################################################################################################
|
|
790
|
+
|
|
791
|
+
# H2Omol + O = 2OH
|
|
792
|
+
# K = xOH*2/(xH2Omol*xO)
|
|
793
|
+
def KHOm(PT,melt_wf,species,models):
|
|
794
|
+
Hspeccomp = models.loc["Hspeccomp","option"]
|
|
795
|
+
T_K = PT['T']+273.15
|
|
796
|
+
|
|
797
|
+
if Hspeccomp == "rhyolite": # Zhang (1999) Reviews in Geophysics 37(4):493-516
|
|
798
|
+
a = -3120.0
|
|
799
|
+
b = 1.89
|
|
800
|
+
K = gp.exp((a/T_K) + b)
|
|
801
|
+
elif Hspeccomp == "alkali basalt": # average of eqn-15-17 from Lesne et al. (2010) CMP 162:133-151
|
|
802
|
+
a = -8348.0 # VES-9 = -8033.0, ETN-1 = -8300.0, and PST-9 = -8710.0
|
|
803
|
+
b = 7.8108 # VES-9 = 7.4222, ETN-1 = 7.4859, and PEST-9 = 8.5244
|
|
804
|
+
K = gp.exp((a/T_K) + b)
|
|
805
|
+
elif Hspeccomp == "PST-9": # Lesne et al. (2010) CMP 162:133-151 eqn 15
|
|
806
|
+
a = -8710.0
|
|
807
|
+
b = 8.5244
|
|
808
|
+
K = gp.exp((a/T_K) + b)
|
|
809
|
+
elif Hspeccomp == "VES-9": # Lesne et al. (2010) CMP 162:133-151 eqn 16
|
|
810
|
+
a = -8033.0
|
|
811
|
+
b = 7.4222
|
|
812
|
+
K = gp.exp((a/T_K) + b)
|
|
813
|
+
elif Hspeccomp == "ETN-1": # Lesne et al. (2010) CMP 162:133-151 eqn 17
|
|
814
|
+
a = -8300.0
|
|
815
|
+
b = 7.4859
|
|
816
|
+
K = gp.exp((a/T_K) + b)
|
|
817
|
+
elif Hspeccomp == "andesite": # eqn-7 from Botcharnikov et al. (2006) Chem. Geol. 229(1-3)125-143
|
|
818
|
+
a = -3650.0
|
|
819
|
+
b = 2.99
|
|
820
|
+
K = gp.exp((a/T_K) + b)
|
|
821
|
+
elif Hspeccomp == "MORB": # fit to Dixon et al. (1995) data digitised from Lesne et al. (2010) CMP 162:133-151
|
|
822
|
+
a = -2204.99
|
|
823
|
+
b = 1.2600
|
|
824
|
+
K = gp.exp((a/T_K) + b)
|
|
825
|
+
elif Hspeccomp == "albite": # Silver & Stolper (1989) J.Pet 30(3)667-709
|
|
826
|
+
K = 0.17
|
|
827
|
+
return K
|
|
828
|
+
|
|
829
|
+
def KregH2O(PT,melt_wf,species,models):
|
|
830
|
+
if Hspeccomp == "MORB": # Dixon et al. (1995)
|
|
831
|
+
A = 0.403
|
|
832
|
+
B = 15.333
|
|
833
|
+
C = 10.894
|
|
834
|
+
elif Hspeccomp == "alkali basalt XT": # No T-dependence, hence its the speciation frozen in the glass. Eqn 7-10 from Lesne et al. (2010) CMP 162:133-151 (eqn 7 is wrong)
|
|
835
|
+
# wt% normalised including H2O, all Fe as FeOT
|
|
836
|
+
melt_comp = melt_normalise_wf(melt_wf,species,"volatiles","Fe speciation")
|
|
837
|
+
Na = melt_comp["Na2O"]*100.
|
|
838
|
+
K = melt_comp["K2O"]*100.
|
|
839
|
+
A = 0.5761*(Na+K) - 0.2884 # eqn-8
|
|
840
|
+
B = -8.9589*(Na+K) + 24.65 # eqn-9
|
|
841
|
+
C = 1.7013*(Na+K) + 9.6481 # eqn-1
|
|
842
|
+
elif Hspeccomp == "alkali basalt": # Includes T-dependence, hence speciation in the melt. Eqn 24-27 from Lesne et al. (2010) CMP 162:133-151
|
|
843
|
+
lnK = ((-2704.4/T_K) + 0.641)
|
|
844
|
+
A = lnK + 49016.0/(R*T_K)
|
|
845
|
+
B = -2153326.51/(R*T_K)
|
|
846
|
+
C = 1.965495217/(R*T_K)
|
|
847
|
+
elif Hspeccomp == "VES-9": # Lesne et al. (2011) 162:133-151 Table 5
|
|
848
|
+
A = 3.139
|
|
849
|
+
B = -29.555
|
|
850
|
+
C = 20.535
|
|
851
|
+
elif Hspeccomp == "ETN-1": # Lesne et al. (2011) 162:133-151 Table 5
|
|
852
|
+
A = 4.128
|
|
853
|
+
B = -45.905
|
|
854
|
+
C = 21.311
|
|
855
|
+
elif Hspeccomp == "PST-9": # Lesne et al. (2011) 162:133-151 Table 5
|
|
856
|
+
A = 2.6
|
|
857
|
+
B = -22.476
|
|
858
|
+
C = 22.295
|
|
859
|
+
elif Hspeccomp == "albite": # Silver & Stolper (1989) J.Pet 30(3)667-709
|
|
860
|
+
A = 0.403
|
|
861
|
+
B = 15.333
|
|
862
|
+
C = 10.894
|
|
863
|
+
|
|
864
|
+
# CO2 + O = CO3
|
|
865
|
+
def KCOm(PT,melt_wf,species,models): # K =
|
|
866
|
+
T_K = PT['T']+273.15
|
|
867
|
+
Cspeccomp = models.loc["Cspeccomp","option"]
|
|
868
|
+
if Cspeccomp == "andesite": # eqn-8 from Botcharnikov et al. (2006) Chem. Geol. 229(1-3)125-143
|
|
869
|
+
a = 8665.0
|
|
870
|
+
b = -5.11
|
|
871
|
+
value = gp.exp((a/T_K) + b)
|
|
872
|
+
elif Cspeccomp == "dacite": # from Botcharnikov et al. (2006) Chem. Geol. 229(1-3)125-143
|
|
873
|
+
a = 9787.0
|
|
874
|
+
b = -7.69
|
|
875
|
+
value = gp.exp((a/T_K) + b)
|
|
876
|
+
elif Cspeccomp == "basalt": # all oxidised carbon is CO32-
|
|
877
|
+
value = "infinite"
|
|
878
|
+
elif Cspeccomp == "rhyolite": # all oxidised carbon is CO2,mol
|
|
879
|
+
value = 0.
|
|
880
|
+
return value
|
|
881
|
+
|
|
882
|
+
|
|
883
|
+
#################################################################################################################################
|
|
884
|
+
##################################################### FUGACITY COEFFICIENTS #####################################################
|
|
885
|
+
#################################################################################################################################
|
|
886
|
+
|
|
887
|
+
# all fugacity coefficients are assumed to equal 1 below 1 bar.
|
|
888
|
+
|
|
889
|
+
##########################################
|
|
890
|
+
### CORK using Holland & Powell (1991) ###
|
|
891
|
+
##########################################
|
|
892
|
+
|
|
893
|
+
def CORK(PT,p0,a,b,c,d):
|
|
894
|
+
P = PT['P']
|
|
895
|
+
T_K = PT['T']+273.15
|
|
896
|
+
def MRK(P_kb,VMRK,R,T_K,a,b): # MRK volume equation rearranged to equal 0
|
|
897
|
+
return P_kb*pow(VMRK,3.0) - R*T_K*pow(VMRK,2.0) - (b*R*T_K + pow(b,2.0)*P_kb - a*pow(T_K,-0.5))*VMRK - (a*b)*pow(T_K,-0.5)
|
|
898
|
+
|
|
899
|
+
def dMRK(P_kb,VMRK,R,T_K,a,b): # derivative of above
|
|
900
|
+
return 3.0*P_kb*pow(VMRK,2.0) - 2.0*R*T_K*VMRK - (b*R*T_K + pow(b,2.0)*P_kb - a*pow(T_K,-0.5))
|
|
901
|
+
|
|
902
|
+
def dVMRK(MRK,P_kb,VMRK,R,T_K,a,b):
|
|
903
|
+
return abs(0-MRK(P_kb,VMRK,R,T_K,a,b))
|
|
904
|
+
|
|
905
|
+
def NR_VMRK(MRK, dMRK, VMRK0, e1, P_kb,R,T_K,a,b):
|
|
906
|
+
delta1 = dVMRK(MRK,P_kb,VMRK0,R,T_K,a,b)
|
|
907
|
+
while delta1 > e1:
|
|
908
|
+
VMRK0 = VMRK0 - MRK(P_kb,VMRK0,R,T_K,a,b)/dMRK(P_kb,VMRK0,R,T_K,a,b)
|
|
909
|
+
delta1 = dVMRK(MRK,P_kb,VMRK0,R,T_K,a,b)
|
|
910
|
+
return VMRK0
|
|
911
|
+
|
|
912
|
+
R = 8.314e-3 # in kJ/mol/K
|
|
913
|
+
P_kb = P/1000.0
|
|
914
|
+
|
|
915
|
+
Vi = ((R*T_K)/P_kb) + b
|
|
916
|
+
|
|
917
|
+
VMRK = NR_VMRK(MRK, dMRK, Vi, 1E20, P_kb,R,T_K,a,b)
|
|
918
|
+
|
|
919
|
+
if P_kb > p0:
|
|
920
|
+
V = VMRK + c*pow((P_kb-p0),0.5) + d*(P_kb-p0)
|
|
921
|
+
ln_y_virial = (1/(R*T_K))*((2./3.)*c*pow((P_kb-p0),1.5) + (d/2.0)*pow((P_kb-p0),2.0))
|
|
922
|
+
else:
|
|
923
|
+
V = VMRK
|
|
924
|
+
ln_y_virial = 0.0
|
|
925
|
+
|
|
926
|
+
z = (P_kb*V)/(R*T_K)
|
|
927
|
+
A = a/(b*R*pow(T_K,1.5))
|
|
928
|
+
B = (b*P_kb)/(R*T_K)
|
|
929
|
+
|
|
930
|
+
ln_y = z - 1.0 - gp.log(z-B) - A*gp.log(1.0 + (B/z)) + ln_y_virial
|
|
931
|
+
return gp.exp(ln_y)
|
|
932
|
+
|
|
933
|
+
###########################
|
|
934
|
+
### Shi & Saxena (1992) ###
|
|
935
|
+
###########################
|
|
936
|
+
|
|
937
|
+
def lny_SS(PT,Pcr,Tcr):
|
|
938
|
+
P = PT['P']
|
|
939
|
+
T_K = PT['T']+273.15
|
|
940
|
+
Tr = T_K/Tcr
|
|
941
|
+
A, B, C, D, P0, integral0 = Q_SS(PT,Tr,Pcr)
|
|
942
|
+
Pr = P/Pcr
|
|
943
|
+
P0r = P0/Pcr
|
|
944
|
+
integral = A*gp.log(Pr/P0r) + B*(Pr - P0r) + (C/2.0)*(pow(Pr,2.0) - pow(P0r,2.0)) + (D/3.0)*(pow(Pr,3.0) - pow(P0r,3.0))
|
|
945
|
+
integral_total = integral + integral0
|
|
946
|
+
return integral_total
|
|
947
|
+
|
|
948
|
+
def Q_SS(PT,Tr,Pcr):
|
|
949
|
+
P = PT['P']
|
|
950
|
+
def Q1000(Pcr):
|
|
951
|
+
Pr_ = 1000.0/Pcr
|
|
952
|
+
P0r_ = 1.0/Pcr
|
|
953
|
+
A0 = 1.0
|
|
954
|
+
B0 = 0.9827e-1*pow(Tr,-1.0) + -0.2709*pow(Tr,-3.0)
|
|
955
|
+
C0 = -0.1030e-2*pow(Tr,-1.5) + 0.1427e-1*pow(Tr,-4.0)
|
|
956
|
+
D0 = 0.0
|
|
957
|
+
return A0*gp.log(Pr_/P0r_) + B0*(Pr_ - P0r_) + (C0/2.0)*(pow(Pr_,2.0) - pow(P0r_,2.0)) + (D0/3.0)*(pow(Pr_,3.0) - pow(P0r_,3.0))
|
|
958
|
+
def Q5000(Pcr):
|
|
959
|
+
Pr_ = 5000.0/Pcr
|
|
960
|
+
P0r_ = 1000.0/Pcr
|
|
961
|
+
A0 = 1.0 + -5.917e-1*pow(Tr,-2.0)
|
|
962
|
+
B0 = 9.122e-2*pow(Tr,-1.0)
|
|
963
|
+
C0 = -1.416e-4*pow(Tr,-2.0) + -2.835e-6*gp.log(Tr)
|
|
964
|
+
D0 = 0.0
|
|
965
|
+
return A0*gp.log(Pr_/P0r_) + B0*(Pr_ - P0r_) + (C0/2.0)*(pow(Pr_,2.0) - pow(P0r_,2.0)) + (D0/3.0)*(pow(Pr_,3.0) - pow(P0r_,3.0))
|
|
966
|
+
if P > 5000.0:
|
|
967
|
+
A = 2.0614 + -2.235*pow(Tr,-2.0) + -3.941e-1*gp.log(Tr)
|
|
968
|
+
B = 5.513e-2*pow(Tr,-1.0) + 3.934e-2*pow(Tr,-2.0)
|
|
969
|
+
C = -1.894e-6*pow(Tr,-1.0) + -1.109e-5*pow(Tr,-2.0) + -2.189e-5*pow(Tr,-3.0)
|
|
970
|
+
D = 5.053e-11*pow(Tr,-1.0) + -6.303e-21*pow(Tr,3.0)
|
|
971
|
+
P0 = 5000.0
|
|
972
|
+
integral0 = Q1000(Pcr) + Q5000(Pcr)
|
|
973
|
+
return A, B, C, D, P0, integral0
|
|
974
|
+
elif P == 5000.0:
|
|
975
|
+
A = 0
|
|
976
|
+
B = 0
|
|
977
|
+
C = 0
|
|
978
|
+
D = 0
|
|
979
|
+
P0 = 5000.0
|
|
980
|
+
integral0 = Q1000(Pcr) + Q5000(Pcr)
|
|
981
|
+
return A, B, C, D, P0, integral0
|
|
982
|
+
elif P > 1000.0 and P < 5000.0:
|
|
983
|
+
A = 1.0 + -5.917e-1*pow(Tr,-2.0)
|
|
984
|
+
B = 9.122e-2*pow(Tr,-1.0)
|
|
985
|
+
C = -1.416e-4*pow(Tr,-2.0) + -2.835e-6*gp.log(Tr)
|
|
986
|
+
D = 0.0
|
|
987
|
+
P0 = 1000.0
|
|
988
|
+
integral0 = Q1000(Pcr)
|
|
989
|
+
return A, B, C, D, P0, integral0
|
|
990
|
+
elif P == 1000.0:
|
|
991
|
+
A = 0
|
|
992
|
+
B = 0
|
|
993
|
+
C = 0
|
|
994
|
+
D = 0.0
|
|
995
|
+
P0 = 1000.0
|
|
996
|
+
integral0 = Q1000(Pcr)
|
|
997
|
+
return A, B, C, D, P0, integral0
|
|
998
|
+
else:
|
|
999
|
+
A = 1.0
|
|
1000
|
+
B = 0.9827e-1*pow(Tr,-1.0) + -0.2709*pow(Tr,-3.0)
|
|
1001
|
+
C = -0.1030e-2*pow(Tr,-1.5) + 0.1427e-1*pow(Tr,-4.0)
|
|
1002
|
+
D = 0.0
|
|
1003
|
+
P0 = 1.0
|
|
1004
|
+
integral0 = 0.0
|
|
1005
|
+
return A, B, C, D, P0, integral0
|
|
1006
|
+
|
|
1007
|
+
def y_SS(gas_species,PT,species,models):
|
|
1008
|
+
P = PT['P']
|
|
1009
|
+
T_K = PT['T']+273.15
|
|
1010
|
+
ideal_gas = models.loc["ideal_gas","option"]
|
|
1011
|
+
if ideal_gas == "yes":
|
|
1012
|
+
return 1.0
|
|
1013
|
+
elif P < 1.: # ideal gas below 1 bar
|
|
1014
|
+
return 1.
|
|
1015
|
+
else:
|
|
1016
|
+
Tcr = species.loc[gas_species,"Tcr"]
|
|
1017
|
+
Pcr = species.loc[gas_species,"Pcr"]
|
|
1018
|
+
return gp.exp(lny_SS(PT,Pcr,Tcr))/P
|
|
1019
|
+
|
|
1020
|
+
##############################
|
|
1021
|
+
### for each vapor species ###
|
|
1022
|
+
##############################
|
|
1023
|
+
|
|
1024
|
+
def y_H2(PT,species,models):
|
|
1025
|
+
P = PT['P']
|
|
1026
|
+
T_K = PT['T']+273.15
|
|
1027
|
+
ideal_gas = models.loc["ideal_gas","option"]
|
|
1028
|
+
if ideal_gas == "yes":
|
|
1029
|
+
return 1.0
|
|
1030
|
+
elif P < 1.: # ideal gas below 1 bar
|
|
1031
|
+
return 1.
|
|
1032
|
+
elif models.loc["y_H2","option"] == "SW64": # Shaw & Wones (1964)
|
|
1033
|
+
SW1 = gp.exp(-3.8402*pow(T_K,0.125)+0.5410)
|
|
1034
|
+
SW2 = gp.exp(-0.1263*pow(T_K,0.5)-15.980)
|
|
1035
|
+
SW3 = 300*gp.exp((-0.011901*T_K)-5.941) # NB used a value of -0.011901 instead of -0.11901 as reported to match data in Table 2
|
|
1036
|
+
P_atm = 0.986923*P
|
|
1037
|
+
ln_y = SW1*P_atm - SW2*pow(P_atm,2.0) + SW3*gp.exp((-P_atm/300.0)-1.0)
|
|
1038
|
+
return gp.exp(ln_y)
|
|
1039
|
+
elif models.loc["y_H2","option"] == "SS92": # Shi & Saxena (1992) NOT WORKING
|
|
1040
|
+
Tcr = 33.25 # critical temperature in K
|
|
1041
|
+
Pcr = 12.9696 # critical temperature in bar
|
|
1042
|
+
Tr = T_K/Tcr
|
|
1043
|
+
# Q for 1-1000 bar
|
|
1044
|
+
Q1_A_LP, Q2_A_LP, Q3_A_LP, Q4_A_LP, Q5_A_LP = 1., 0., 0., 0., 0.
|
|
1045
|
+
Q1_B_LP, Q2_B_LP, Q3_B_LP, Q4_B_LP, Q5_B_LP = 0., 0.9827e-1, 0., -0.2709, 0.
|
|
1046
|
+
Q1_C_LP, Q2_C_LP, Q3_C_LP, Q4_C_LP, Q5_C_LP = 0., 0., -0.1030e-2, 0., 0.1427e-1
|
|
1047
|
+
# Q for 1000-10000 bar
|
|
1048
|
+
Q1_A_HP, Q2_A_HP, Q3_A_HP, Q4_A_HP, Q5_A_HP, Q6_A_HP, Q7_A_HP, Q8_A_HP = 2.2615, 0., -6.8712e1, 0., -1.0573e4, 0., 0., -1.6936e-1
|
|
1049
|
+
Q1_B_HP, Q2_B_HP, Q3_B_HP, Q4_B_HP, Q5_B_HP, Q6_B_HP, Q7_B_HP, Q8_B_HP = -2.6707e-4, 0., 2.0173e-1, 0., 4.5759, 0., 0., 3.1452e-5
|
|
1050
|
+
Q1_C_HP, Q2_C_HP, Q3_C_HP, Q4_C_HP, Q5_C_HP, Q6_C_HP, Q7_C_HP, Q8_C_HP = -2.3376e-9, 0., 3.4091e-7, 0., -1.4188e-3, 0., 0., 3.0117e-10
|
|
1051
|
+
Q1_D_HP, Q2_D_HP, Q3_D_HP, Q4_D_HP, Q5_D_HP, Q6_D_HP, Q7_D_HP, Q8_D_HP = -3.2606e-15, 0., 2.4402e-12, 0., -2.4027e-9, 0., 0., 0.
|
|
1052
|
+
if P < 1000.:
|
|
1053
|
+
A = Q1_A_LP + Q2_A_LP*Tr**(-1.) + Q3_A_LP*Tr**(-1.5) + Q4_A_LP*Tr**(-3.) + Q5_A_LP*Tr**(-4.)
|
|
1054
|
+
B = Q1_B_LP + Q2_B_LP*Tr**(-1.) + Q3_B_LP*Tr**(-1.5) + Q4_B_LP*Tr**(-3.) + Q5_B_LP*Tr**(-4.)
|
|
1055
|
+
C = Q1_C_LP + Q2_C_LP*Tr**(-1.) + Q3_C_LP*Tr**(-1.5) + Q4_C_LP*Tr**(-3.) + Q5_C_LP*Tr**(-4.)
|
|
1056
|
+
D = 0.0
|
|
1057
|
+
P0 = 1.0
|
|
1058
|
+
integral0 = 0.
|
|
1059
|
+
elif P == 1000.:
|
|
1060
|
+
A = 0.0
|
|
1061
|
+
B = 0.0
|
|
1062
|
+
C = 0.0
|
|
1063
|
+
D = 0.0
|
|
1064
|
+
P0 = 1000.0
|
|
1065
|
+
Pr_ = 1000.0/Pcr
|
|
1066
|
+
P0r_ = 1.0/Pcr
|
|
1067
|
+
A0 = Q1_A_LP + Q2_A_LP*Tr + Q3_A_LP*Tr**(-1.) + Q4_A_LP*Tr**2. + Q5_A_LP*Tr**(-2.)
|
|
1068
|
+
B0 = Q1_B_LP + Q2_B_LP*Tr + Q3_B_LP*Tr**(-1.) + Q4_B_LP*Tr**2. + Q5_B_LP*Tr**(-2.)
|
|
1069
|
+
C0 = Q1_C_LP + Q2_C_LP*Tr + Q3_C_LP*Tr**(-1.) + Q4_C_LP*Tr**2. + Q5_C_LP*Tr**(-2.)
|
|
1070
|
+
D0 = 0.0
|
|
1071
|
+
integral0 = A0*gp.log(Pr_/P0r_) + B0*(Pr_ - P0r_) + (C0/2.0)*(pow(Pr_,2.0) - pow(P0r_,2.0)) + (D0/3.0)*(pow(Pr_,3.0) - pow(P0r_,3.0))
|
|
1072
|
+
elif P > 1000.:
|
|
1073
|
+
A = Q1_A_HP + Q2_A_HP*Tr + Q3_A_HP*Tr**(-1.) + Q4_A_HP*Tr**2. + Q5_A_HP*Tr**(-2.) + Q6_A_HP*Tr**3. + Q7_A_HP*Tr**(-3.0) + Q8_A_HP*gp.log(Tr)
|
|
1074
|
+
B = Q1_B_HP + Q2_B_HP*Tr + Q3_B_HP*Tr**(-1.) + Q4_B_HP*Tr**2. + Q5_B_HP*Tr**(-2.) + Q6_B_HP*Tr**3. + Q7_B_HP*Tr**(-3.0) + Q8_B_HP*gp.log(Tr)
|
|
1075
|
+
C = Q1_C_HP + Q2_C_HP*Tr + Q3_C_HP*Tr**(-1.) + Q4_C_HP*Tr**2. + Q5_C_HP*Tr**(-2.) + Q6_C_HP*Tr**3. + Q7_C_HP*Tr**(-3.0) + Q8_C_HP*gp.log(Tr)
|
|
1076
|
+
D = Q1_D_HP + Q2_D_HP*Tr + Q3_D_HP*Tr**(-1.) + Q4_D_HP*Tr**2. + Q5_D_HP*Tr**(-2.) + Q6_D_HP*Tr**3. + Q7_D_HP*Tr**(-3.0) + Q8_D_HP*gp.log(Tr)
|
|
1077
|
+
P0 = 1000.0
|
|
1078
|
+
Pr_ = 1000.0/Pcr
|
|
1079
|
+
P0r_ = 1.0/Pcr
|
|
1080
|
+
A0 = Q1_A_LP + Q2_A_LP*Tr + Q3_A_LP*Tr**(-1.) + Q4_A_LP*Tr**2. + Q5_A_LP*Tr**(-2.)
|
|
1081
|
+
B0 = Q1_B_LP + Q2_B_LP*Tr + Q3_B_LP*Tr**(-1.) + Q4_B_LP*Tr**2. + Q5_B_LP*Tr**(-2.)
|
|
1082
|
+
C0 = Q1_C_LP + Q2_C_LP*Tr + Q3_C_LP*Tr**(-1.) + Q4_C_LP*Tr**2. + Q5_C_LP*Tr**(-2.)
|
|
1083
|
+
D0 = 0.0
|
|
1084
|
+
integral0 = A0*gp.log(Pr_/P0r_) + B0*(Pr_ - P0r_) + (C0/2.0)*(pow(Pr_,2.0) - pow(P0r_,2.0)) + (D0/3.0)*(pow(Pr_,3.0) - pow(P0r_,3.0))
|
|
1085
|
+
P0r = P0/Pcr
|
|
1086
|
+
Pr = P/Pcr
|
|
1087
|
+
integral = A*gp.log(Pr/P0r) + B*(Pr - P0r) + (C/2.0)*(pow(Pr,2.0) - pow(P0r,2.0)) + (D/3.0)*(pow(Pr,3.0) - pow(P0r,3.0))
|
|
1088
|
+
return gp.exp(integral + integral0)/P
|
|
1089
|
+
|
|
1090
|
+
def y_H2O(PT,species,models):
|
|
1091
|
+
P = PT['P']
|
|
1092
|
+
T_K = PT['T']+273.15
|
|
1093
|
+
ideal_gas = models.loc["ideal_gas","option"]
|
|
1094
|
+
if ideal_gas == "yes":
|
|
1095
|
+
return 1.
|
|
1096
|
+
elif P < 1.: # ideal gas below 1 bar
|
|
1097
|
+
return 1.
|
|
1098
|
+
if models.loc["y_H2O","option"] == "HP91":
|
|
1099
|
+
# (T > 673 K only) - using Holland & Powell (1991) CORK
|
|
1100
|
+
p0 = 2.00 # in kb
|
|
1101
|
+
a = 1113.4 + -0.22291*(T_K - 673.0) + -3.8022e-4*pow((T_K-673.0),2.0) + 1.7791e-7*pow((T_K-673.0),3.0)
|
|
1102
|
+
b = 1.465
|
|
1103
|
+
c = -3.025650e-2 + -5.343144e-6*T_K
|
|
1104
|
+
d = -3.2297554e-3 + 2.2215221e-6*T_K
|
|
1105
|
+
y = CORK(PT,p0,a,b,c,d)
|
|
1106
|
+
return y
|
|
1107
|
+
|
|
1108
|
+
def y_CO2(PT,species,models):
|
|
1109
|
+
P = PT['P']
|
|
1110
|
+
T_K = PT['T']+273.15
|
|
1111
|
+
ideal_gas = models.loc["ideal_gas","option"]
|
|
1112
|
+
if ideal_gas == "yes":
|
|
1113
|
+
return 1.0
|
|
1114
|
+
elif P < 1.: # ideal gas below 1 bar
|
|
1115
|
+
return 1.
|
|
1116
|
+
else:
|
|
1117
|
+
if models.loc["y_CO2","option"] == "HP91": # use Holland & Powell (1991)
|
|
1118
|
+
p0 = 5.00 # in kb
|
|
1119
|
+
a = 741.2 + -0.10891*(T_K) + -3.4203e-4*pow(T_K,2.0)
|
|
1120
|
+
b = 3.057
|
|
1121
|
+
c = -2.26924e-1 + -7.73793e-5*T_K
|
|
1122
|
+
d = 1.33790e-2 + -1.1740e-5*T_K
|
|
1123
|
+
y = CORK(PT,p0,a,b,c,d)
|
|
1124
|
+
elif models.loc["y_CO2","option"] == "SS92": # use Shi & Saxena (1992)
|
|
1125
|
+
gas_species = "CO2"
|
|
1126
|
+
y = y_SS(gas_species,PT,species,models)
|
|
1127
|
+
return y
|
|
1128
|
+
|
|
1129
|
+
def y_O2(PT,species,models):
|
|
1130
|
+
if models.loc["y_O2","option"] == "SS92":
|
|
1131
|
+
gas_species = "O2"
|
|
1132
|
+
y = y_SS(gas_species,PT,species,models)
|
|
1133
|
+
return y
|
|
1134
|
+
|
|
1135
|
+
def y_S2(PT,species,models):
|
|
1136
|
+
if models.loc["y_S2","option"] == "SS92":
|
|
1137
|
+
gas_species = "S2"
|
|
1138
|
+
y = y_SS(gas_species,PT,species,models)
|
|
1139
|
+
return y
|
|
1140
|
+
|
|
1141
|
+
def y_CO(PT,species,models):
|
|
1142
|
+
if models.loc["y_CO","option"] == "SS92":
|
|
1143
|
+
gas_species = "CO"
|
|
1144
|
+
y = y_SS(gas_species,PT,species,models)
|
|
1145
|
+
return y
|
|
1146
|
+
|
|
1147
|
+
def y_CH4(PT,species,models):
|
|
1148
|
+
if models.loc["y_CH4","option"] == "SS92":
|
|
1149
|
+
gas_species = "CH4"
|
|
1150
|
+
y = y_SS(gas_species,PT,species,models)
|
|
1151
|
+
return y
|
|
1152
|
+
|
|
1153
|
+
def y_OCS(PT,species,models):
|
|
1154
|
+
if models.loc["y_OCS","option"] == "SS92":
|
|
1155
|
+
gas_species = "OCS"
|
|
1156
|
+
y = y_SS(gas_species,PT,species,models)
|
|
1157
|
+
return y
|
|
1158
|
+
|
|
1159
|
+
def y_X(PT,species,models): # species X fugacity coefficient
|
|
1160
|
+
if models.loc["y_X","option"] == "ideal": # ideal gas
|
|
1161
|
+
y = 1.
|
|
1162
|
+
return y
|
|
1163
|
+
|
|
1164
|
+
#################################################################################
|
|
1165
|
+
### SO2 and H2S from Shi & Saxena (1992) with option to modify below 500 bars ###
|
|
1166
|
+
#################################################################################
|
|
1167
|
+
|
|
1168
|
+
def y_SO2(PT,species,models):
|
|
1169
|
+
P = PT['P']
|
|
1170
|
+
T_K = PT['T']+273.15
|
|
1171
|
+
ideal_gas = models.loc["ideal_gas","option"]
|
|
1172
|
+
gas_species = "SO2"
|
|
1173
|
+
if ideal_gas == "yes":
|
|
1174
|
+
return 1.
|
|
1175
|
+
elif P < 1.: # ideal gas below 1 bar
|
|
1176
|
+
return 1.
|
|
1177
|
+
else: # 1-10000 bar
|
|
1178
|
+
Tcr = species.loc[gas_species,"Tcr"] # critical temperature in K
|
|
1179
|
+
Pcr = species.loc[gas_species,"Pcr"] # critical temperature in bar
|
|
1180
|
+
P0 = 1.0
|
|
1181
|
+
P0r = P0/Pcr
|
|
1182
|
+
Tr = T_K/Tcr
|
|
1183
|
+
Q1_A, Q2_A, Q3_A, Q4_A, Q5_A, Q6_A, Q7_A, Q8_A = 0.92854, 0.43269e-1, -0.24671, 0., 0.24999, 0., -0.53182, -0.16461e-1
|
|
1184
|
+
Q1_B, Q2_B, Q3_B, Q4_B, Q5_B, Q6_B, Q7_B, Q8_B = 0.84866e-3, -0.18379e-2, 0.66787e-1, 0., -0.29427e-1, 0., 0.29003e-1, 0.54808e-2
|
|
1185
|
+
Q1_C, Q2_C, Q3_C, Q4_C, Q5_C, Q6_C, Q7_C, Q8_C = -0.35456e-3, 0.23316e-4, 0.94159e-3, 0., -0.81653e-3, 0., 0.23154e-3, 0.55542e-4
|
|
1186
|
+
A = Q1_A + Q2_A*Tr + Q3_A*Tr**(-1.) + Q4_A*Tr**2. + Q5_A*Tr**(-2.) + Q6_A*Tr**3. + Q7_A*Tr**(-3.0) + Q8_A*gp.log(Tr)
|
|
1187
|
+
B = Q1_B + Q2_B*Tr + Q3_B*Tr**(-1.) + Q4_B*Tr**2. + Q5_B*Tr**(-2.) + Q6_B*Tr**3. + Q7_B*Tr**(-3.0) + Q8_B*gp.log(Tr)
|
|
1188
|
+
C = Q1_C + Q2_C*Tr + Q3_C*Tr**(-1.) + Q4_C*Tr**2. + Q5_C*Tr**(-2.) + Q6_C*Tr**3. + Q7_C*Tr**(-3.0) + Q8_C*gp.log(Tr)
|
|
1189
|
+
D = 0.0
|
|
1190
|
+
if P >= 500.: # above 500 bar using Shi and Saxena (1992) as is
|
|
1191
|
+
Pr = P/Pcr
|
|
1192
|
+
integral = A*gp.log(Pr/P0r) + B*(Pr - P0r) + (C/2.0)*(pow(Pr,2.0) - pow(P0r,2.0)) + (D/3.0)*(pow(Pr,3.0) - pow(P0r,3.0))
|
|
1193
|
+
y = (gp.exp(integral))/P
|
|
1194
|
+
elif models.loc["y_SO2","option"] == "SS92": # as is Shi and Saxena (1992)
|
|
1195
|
+
Pr = P/Pcr
|
|
1196
|
+
integral = A*gp.log(Pr/P0r) + B*(Pr - P0r) + (C/2.0)*(pow(Pr,2.0) - pow(P0r,2.0)) + (D/3.0)*(pow(Pr,3.0) - pow(P0r,3.0))
|
|
1197
|
+
y = (gp.exp(integral))/P
|
|
1198
|
+
elif models.loc["y_SO2","option"] == "SS92_modified": # below 500 bar linear fit between the value at 500 bar and y = 1 at 1 bar to avoid weird behaviour...
|
|
1199
|
+
Pr = 500./Pcr # calculate y at 500 bar
|
|
1200
|
+
integral = A*gp.log(Pr/P0r) + B*(Pr - P0r) + (C/2.0)*(pow(Pr,2.0) - pow(P0r,2.0)) + (D/3.0)*(pow(Pr,3.0) - pow(P0r,3.0))
|
|
1201
|
+
y_500 = (gp.exp(integral))/500.
|
|
1202
|
+
y = ((y_500 - 1.)*(P/500.)) + 1. # linear extrapolation to P of interest
|
|
1203
|
+
return y
|
|
1204
|
+
|
|
1205
|
+
def y_H2S(PT,species,models):
|
|
1206
|
+
P = PT['P']
|
|
1207
|
+
T_K = PT['T']+273.15
|
|
1208
|
+
ideal_gas = models.loc["ideal_gas","option"]
|
|
1209
|
+
gas_species = "H2S"
|
|
1210
|
+
if ideal_gas == "yes":
|
|
1211
|
+
return 1.0
|
|
1212
|
+
elif ideal_gas == "no":
|
|
1213
|
+
Tcr = species.loc[gas_species,"Tcr"] # critical temperature in K
|
|
1214
|
+
Pcr = species.loc[gas_species,"Pcr"] # critical temperature in bar
|
|
1215
|
+
Tr = T_K/Tcr
|
|
1216
|
+
# Q for 1-500 bar
|
|
1217
|
+
Q1_A_LP, Q2_A_LP, Q3_A_LP, Q4_A_LP, Q5_A_LP, Q6_A_LP, Q7_A_LP, Q8_A_LP = 0.14721e1, 0.11177e1, 0.39657e1, 0., -0.10028e2, 0., 0.45484e1, -0.382e1
|
|
1218
|
+
Q1_B_LP, Q2_B_LP, Q3_B_LP, Q4_B_LP, Q5_B_LP, Q6_B_LP, Q7_B_LP, Q8_B_LP = 0.16066, 0.10887, 0.29014, 0., -0.99593, 0., -0.18627, -0.45515
|
|
1219
|
+
Q1_C_LP, Q2_C_LP, Q3_C_LP, Q4_C_LP, Q5_C_LP, Q6_C_LP, Q7_C_LP, Q8_C_LP = -0.28933, -0.70522e-1, 0.39828, 0., -0.50533e-1, 0., 0.1176, 0.33972
|
|
1220
|
+
# Q for 500-10000 bar
|
|
1221
|
+
Q1_A_HP, Q2_A_HP, Q3_A_HP, Q4_A_HP, Q5_A_HP, Q6_A_HP, Q7_A_HP, Q8_A_HP = 0.59941, -0.1557e-2, 0.4525e-1, 0., 0.36687, 0., -0.79248, 0.26058
|
|
1222
|
+
Q1_B_HP, Q2_B_HP, Q3_B_HP, Q4_B_HP, Q5_B_HP, Q6_B_HP, Q7_B_HP, Q8_B_HP = 0.22545e-1, 0.17473e-2, 0.48253e-1, 0., -0.1989e-1, 0., 0.32794e-1, -0.10985e-1
|
|
1223
|
+
Q1_C_HP, Q2_C_HP, Q3_C_HP, Q4_C_HP, Q5_C_HP, Q6_C_HP, Q7_C_HP, Q8_C_HP = 0.57375e-3, -0.20944e-5, -0.11894e-2, 0., 0.14661e-2, 0., -0.75605e-3, -0.27985e-3
|
|
1224
|
+
if P < 1.:
|
|
1225
|
+
return 1. # ideal gas below 1 bar
|
|
1226
|
+
elif P < 500.:
|
|
1227
|
+
if models.loc["y_H2S","option"] == "SS92": # as is Shi and Saxena (1992)
|
|
1228
|
+
A = Q1_A_LP + Q2_A_LP*Tr + Q3_A_LP*Tr**(-1.) + Q4_A_LP*Tr**2. + Q5_A_LP*Tr**(-2.) + Q6_A_LP*Tr**3. + Q7_A_LP*Tr**(-3.0) + Q8_A_LP*gp.log(Tr)
|
|
1229
|
+
B = Q1_B_LP + Q2_B_LP*Tr + Q3_B_LP*Tr**(-1.) + Q4_B_LP*Tr**2. + Q5_B_LP*Tr**(-2.) + Q6_B_LP*Tr**3. + Q7_B_LP*Tr**(-3.0) + Q8_B_LP*gp.log(Tr)
|
|
1230
|
+
C = Q1_C_LP + Q2_C_LP*Tr + Q3_C_LP*Tr**(-1.) + Q4_C_LP*Tr**2. + Q5_C_LP*Tr**(-2.) + Q6_C_LP*Tr**3. + Q7_C_LP*Tr**(-3.0) + Q8_C_LP*gp.log(Tr)
|
|
1231
|
+
D = 0.0
|
|
1232
|
+
P0 = 1.0
|
|
1233
|
+
integral0 = 0.
|
|
1234
|
+
elif models.loc["y_SO2","option"] == "SS92_modified": # below 500 bar linear fit between the value at 500 bar and y = 1 at 1 bar to avoid weird behaviour...
|
|
1235
|
+
P0 = 500.0 # calculate y at 500 bars
|
|
1236
|
+
Pr_ = 500.0/Pcr
|
|
1237
|
+
P0r_ = 1.0/Pcr
|
|
1238
|
+
A0 = Q1_A_LP + Q2_A_LP*Tr + Q3_A_LP*Tr**(-1.) + Q4_A_LP*Tr**2. + Q5_A_LP*Tr**(-2.) + Q6_A_LP*Tr**3. + Q7_A_LP*Tr**(-3.0) + Q8_A_LP*gp.log(Tr)
|
|
1239
|
+
B0 = Q1_B_LP + Q2_B_LP*Tr + Q3_B_LP*Tr**(-1.) + Q4_B_LP*Tr**2. + Q5_B_LP*Tr**(-2.) + Q6_B_LP*Tr**3. + Q7_B_LP*Tr**(-3.0) + Q8_B_LP*gp.log(Tr)
|
|
1240
|
+
C0 = Q1_C_LP + Q2_C_LP*Tr + Q3_C_LP*Tr**(-1.) + Q4_C_LP*Tr**2. + Q5_C_LP*Tr**(-2.) + Q6_C_LP*Tr**3. + Q7_C_LP*Tr**(-3.0) + Q8_C_LP*gp.log(Tr)
|
|
1241
|
+
D0 = 0.0
|
|
1242
|
+
integral0 = A0*gp.log(Pr_/P0r_) + B0*(Pr_ - P0r_) + (C0/2.0)*(pow(Pr_,2.0) - pow(P0r_,2.0)) + (D0/3.0)*(pow(Pr_,3.0) - pow(P0r_,3.0))
|
|
1243
|
+
y_500 = gp.exp(integral0)/500.
|
|
1244
|
+
y = ((y_500 - 1.)*(P/500.)) + 1. # linear extrapolation to P of interest
|
|
1245
|
+
return y
|
|
1246
|
+
elif P == 500.:
|
|
1247
|
+
A = 0.0
|
|
1248
|
+
B = 0.0
|
|
1249
|
+
C = 0.0
|
|
1250
|
+
D = 0.0
|
|
1251
|
+
P0 = 500.0
|
|
1252
|
+
Pr_ = 500.0/Pcr
|
|
1253
|
+
P0r_ = 1.0/Pcr
|
|
1254
|
+
A0 = Q1_A_LP + Q2_A_LP*Tr + Q3_A_LP*Tr**(-1.) + Q4_A_LP*Tr**2. + Q5_A_LP*Tr**(-2.) + Q6_A_LP*Tr**3. + Q7_A_LP*Tr**(-3.0) + Q8_A_LP*gp.log(Tr)
|
|
1255
|
+
B0 = Q1_B_LP + Q2_B_LP*Tr + Q3_B_LP*Tr**(-1.) + Q4_B_LP*Tr**2. + Q5_B_LP*Tr**(-2.) + Q6_B_LP*Tr**3. + Q7_B_LP*Tr**(-3.0) + Q8_B_LP*gp.log(Tr)
|
|
1256
|
+
C0 = Q1_C_LP + Q2_C_LP*Tr + Q3_C_LP*Tr**(-1.) + Q4_C_LP*Tr**2. + Q5_C_LP*Tr**(-2.) + Q6_C_LP*Tr**3. + Q7_C_LP*Tr**(-3.0) + Q8_C_LP*gp.log(Tr)
|
|
1257
|
+
D0 = 0.0
|
|
1258
|
+
integral0 = A0*gp.log(Pr_/P0r_) + B0*(Pr_ - P0r_) + (C0/2.0)*(pow(Pr_,2.0) - pow(P0r_,2.0)) + (D0/3.0)*(pow(Pr_,3.0) - pow(P0r_,3.0))
|
|
1259
|
+
elif P > 500.:
|
|
1260
|
+
A = Q1_A_HP + Q2_A_HP*Tr + Q3_A_HP*Tr**(-1.) + Q4_A_HP*Tr**2. + Q5_A_HP*Tr**(-2.) + Q6_A_HP*Tr**3. + Q7_A_HP*Tr**(-3.0) + Q8_A_HP*gp.log(Tr)
|
|
1261
|
+
B = Q1_B_HP + Q2_B_HP*Tr + Q3_B_HP*Tr**(-1.) + Q4_B_HP*Tr**2. + Q5_B_HP*Tr**(-2.) + Q6_B_HP*Tr**3. + Q7_B_HP*Tr**(-3.0) + Q8_B_HP*gp.log(Tr)
|
|
1262
|
+
C = Q1_C_HP + Q2_C_HP*Tr + Q3_C_HP*Tr**(-1.) + Q4_C_HP*Tr**2. + Q5_C_HP*Tr**(-2.) + Q6_C_HP*Tr**3. + Q7_C_HP*Tr**(-3.0) + Q8_C_HP*gp.log(Tr)
|
|
1263
|
+
D = 0.0
|
|
1264
|
+
P0 = 500.0
|
|
1265
|
+
Pr_ = 500.0/Pcr
|
|
1266
|
+
P0r_ = 1.0/Pcr
|
|
1267
|
+
A0 = Q1_A_LP + Q2_A_LP*Tr + Q3_A_LP*Tr**(-1.) + Q4_A_LP*Tr**2. + Q5_A_LP*Tr**(-2.) + Q6_A_LP*Tr**3. + Q7_A_LP*Tr**(-3.0) + Q8_A_LP*gp.log(Tr)
|
|
1268
|
+
B0 = Q1_B_LP + Q2_B_LP*Tr + Q3_B_LP*Tr**(-1.) + Q4_B_LP*Tr**2. + Q5_B_LP*Tr**(-2.) + Q6_B_LP*Tr**3. + Q7_B_LP*Tr**(-3.0) + Q8_B_LP*gp.log(Tr)
|
|
1269
|
+
C0 = Q1_C_LP + Q2_C_LP*Tr + Q3_C_LP*Tr**(-1.) + Q4_C_LP*Tr**2. + Q5_C_LP*Tr**(-2.) + Q6_C_LP*Tr**3. + Q7_C_LP*Tr**(-3.0) + Q8_C_LP*gp.log(Tr)
|
|
1270
|
+
D0 = 0.0
|
|
1271
|
+
integral0 = A0*gp.log(Pr_/P0r_) + B0*(Pr_ - P0r_) + (C0/2.0)*(pow(Pr_,2.0) - pow(P0r_,2.0)) + (D0/3.0)*(pow(Pr_,3.0) - pow(P0r_,3.0))
|
|
1272
|
+
P0r = P0/Pcr
|
|
1273
|
+
Pr = P/Pcr
|
|
1274
|
+
integral = A*gp.log(Pr/P0r) + B*(Pr - P0r) + (C/2.0)*(pow(Pr,2.0) - pow(P0r,2.0)) + (D/3.0)*(pow(Pr,3.0) - pow(P0r,3.0))
|
|
1275
|
+
return gp.exp(integral + integral0)/P
|
|
1276
|
+
|
|
1277
|
+
def y_SO3(PT,species,models):
|
|
1278
|
+
return 1.
|
|
1279
|
+
|
|
1280
|
+
#######################
|
|
1281
|
+
### oxygen fugacity ###
|
|
1282
|
+
#######################
|
|
1283
|
+
|
|
1284
|
+
# buffers
|
|
1285
|
+
def NNO(PT,models):
|
|
1286
|
+
P = PT['P']
|
|
1287
|
+
T_K = PT["T"]+273.15
|
|
1288
|
+
if models.loc["NNObuffer","option"] == "Frost91":
|
|
1289
|
+
buffer = (-24930/T_K + 9.36 + 0.046*(P-1.0)/T_K) # Frost (1991)
|
|
1290
|
+
return buffer
|
|
1291
|
+
|
|
1292
|
+
def FMQ(PT,models):
|
|
1293
|
+
P = PT['P']
|
|
1294
|
+
T_K = PT["T"]+273.15
|
|
1295
|
+
if models.loc["FMQbuffer","option"] == "Frost91":
|
|
1296
|
+
buffer = (-25096.3/T_K + 8.735 + 0.11*(P-1.0)/T_K) # Frost (1991)
|
|
1297
|
+
elif models.loc["FMQbuffer","option"] == "ONeill87":
|
|
1298
|
+
buffer = (8.58 - (25050/T_K)) # O'Neill (1987)
|
|
1299
|
+
return buffer
|
|
1300
|
+
|
|
1301
|
+
|
|
1302
|
+
# terms for different equations
|
|
1303
|
+
|
|
1304
|
+
def FefO2_KC91_Eq7_terms(PT,melt_wf,species,models): # terms for Kress & Carmichael (1991) Equation 7
|
|
1305
|
+
# ln(XFe2O3/XFeO) = alnfO2 + (b/T) + c + sum(dX) + e[1 - (T0/T) = ln(T/T0)] + f(P/T) + g(((T-T0)P)/T) + h(P2/T)
|
|
1306
|
+
# ln(XFe2O3/XFeO) = alnfO2 + B
|
|
1307
|
+
# terms
|
|
1308
|
+
a = 0.196
|
|
1309
|
+
# sum(dX)
|
|
1310
|
+
# mole frations in the melt based on oxide components (all Fe as FeO) with no volatiles
|
|
1311
|
+
melt_comp = mg.melt_mole_fraction(melt_wf,species,models,"no","no")
|
|
1312
|
+
DAl = -2.243
|
|
1313
|
+
DFe = -1.828
|
|
1314
|
+
DCa = 3.201
|
|
1315
|
+
DNa = 5.854
|
|
1316
|
+
DK = 6.215
|
|
1317
|
+
D4X = DAl*melt_comp["Al2O3"] + DFe*melt_comp["FeOT"] + DCa*melt_comp["CaO"] + DNa*melt_comp["Na2O"] + DK*melt_comp["K2O"]
|
|
1318
|
+
# PT term
|
|
1319
|
+
P = PT['P']
|
|
1320
|
+
T_K = PT['T']+273.15
|
|
1321
|
+
b = 1.1492e4 # K
|
|
1322
|
+
c = -6.675
|
|
1323
|
+
e = -3.36
|
|
1324
|
+
f = -7.01e-7 # K/Pa
|
|
1325
|
+
g = -1.54e-10 # /Pa
|
|
1326
|
+
h = 3.85e-17 # K/Pa2
|
|
1327
|
+
T0 = 1673.0 # K
|
|
1328
|
+
P_Pa = P*1.0e5 # converts bars to pascals
|
|
1329
|
+
B = (b/T_K) + c + D4X + e*(1.0 - (T0/T_K) - math.log(T_K/T0)) + f*(P_Pa/T_K) + g*(((T_K-T0)*P_Pa)/T_K) + h*((P_Pa**2.0)/T_K)
|
|
1330
|
+
return a, B
|
|
1331
|
+
|
|
1332
|
+
def FefO2_KC91_EqA_terms(PT,melt_wf,species,models): # terms for Kress & Carmichael (1991) Appendix Equations A1-6
|
|
1333
|
+
# XFeO1.5/XFeO = (KD1*fO2**0.25 + 2y*KD2*KD1**2y*fO2**0.5y)/(1 + (1-2y)KD2*KD1**2y*fO2**0.5y)
|
|
1334
|
+
KD2 = 0.4
|
|
1335
|
+
y = 0.3
|
|
1336
|
+
# compositional term
|
|
1337
|
+
# mole frations in the melt based on oxide components (all Fe as FeO) with no volatiles
|
|
1338
|
+
melt_comp = mg.melt_mole_fraction(melt_wf,species,models,"no","no")
|
|
1339
|
+
DWAl = 39.86e3 #J
|
|
1340
|
+
DWCa = -62.52e3 #J
|
|
1341
|
+
DWNa = -102.0e3 #J
|
|
1342
|
+
DWK = -119.0e3 #J
|
|
1343
|
+
D4X = DWAl*melt_comp["Al2O3"]+DWCa*melt_comp["CaO"]+DWNa*melt_comp["Na2O"]+DWK*melt_comp["K2O"]
|
|
1344
|
+
# KD1
|
|
1345
|
+
T_K = PT['T']+273.15
|
|
1346
|
+
P = PT['P']
|
|
1347
|
+
DH = -106.2e3 #J
|
|
1348
|
+
DS = -55.10 #J/K
|
|
1349
|
+
DCp = 31.86 #J/K
|
|
1350
|
+
DV = 7.42e-6 #m3
|
|
1351
|
+
DVdot = 1.63e-9 #m3/K
|
|
1352
|
+
DVdash = -8.16e-16 #m3/Pa
|
|
1353
|
+
T0 = 1673.0 # K
|
|
1354
|
+
P0 = 1.0e5 # Pa
|
|
1355
|
+
R = 8.3144598 # J/K/mol
|
|
1356
|
+
P_Pa = P*1.0e5
|
|
1357
|
+
KD1 = math.exp((-DH/(R*T_K)) + (DS/R) - (DCp/R)*(1.0 - (T0/T_K) - gp.log(T_K/T0)) - (1.0/(R*T_K))*D4X - ((DV*(P_Pa-P0))/(R*T_K)) - ((DVdot*(T_K-T0)*(P_Pa-P0))/(R*T_K)) - (DVdash/(2.0*R*T_K))*pow((P_Pa-P0),2.0))
|
|
1358
|
+
return KD1, KD2, y
|
|
1359
|
+
|
|
1360
|
+
def FefO2_ONeill18_terms(PT,melt_wf,species,models):
|
|
1361
|
+
# O'Neill et al. (2018) EPSL 504:152-162
|
|
1362
|
+
# 1n(Fe3Fe2) = a*DFMQ + B
|
|
1363
|
+
a = 0.125
|
|
1364
|
+
# mole fractions on a single cation basis in the melt based on oxide components (all Fe as FeO) with no volatiles
|
|
1365
|
+
melt_comp = mg.melt_cation_proportion(melt_wf,species,"volatiles","Fe speciation")
|
|
1366
|
+
B = - 1.36 + 2.4*melt_comp["Ca"] + 2.0*melt_comp["Na"] + 3.7*melt_comp["K"] - 2.4*melt_comp["P"]
|
|
1367
|
+
# FMQ
|
|
1368
|
+
T_K = PT['T']+273.15
|
|
1369
|
+
FMQ = 8.58 - (25050/T_K) # O'Neill (1987)
|
|
1370
|
+
return a, B, FMQ
|
|
1371
|
+
|
|
1372
|
+
def FefO2_Borisov18_terms(PT,melt_wf,species,models):
|
|
1373
|
+
T_K = PT['T']+273.15
|
|
1374
|
+
# Borisov et al. (2018) CMP 173
|
|
1375
|
+
a = 0.207
|
|
1376
|
+
# melt mole fraction with no volatiles and all Fe as FeOT
|
|
1377
|
+
melt_comp = mg.melt_mole_fraction(melt_wf,species,models,"no","no")
|
|
1378
|
+
B = (4633.3/T_K -0.445*melt_comp["SiO2"] - 0.900*melt_comp["TiO2"] + 1.532*melt_comp["MgO"] + 0.314*melt_comp["CaO"] + 2.030*melt_comp["Na2O"] + 3.355*melt_comp["K2O"] - 4.851*melt_comp["P2O5"] - 3.081*melt_comp["SiO2"]*melt_comp["Al2O3"] - 4.370*melt_comp["SiO2"]*melt_comp["MgO"] - 1.852)
|
|
1379
|
+
return a, B
|
|
1380
|
+
|
|
1381
|
+
def fO22Fe3FeT(fO2,PT,melt_wf,species,models): # converting fO2 to Fe3/FeT
|
|
1382
|
+
model = models.loc["fO2","option"]
|
|
1383
|
+
T_K = PT['T']+273.15
|
|
1384
|
+
|
|
1385
|
+
if model == "Kress91":
|
|
1386
|
+
a, PTterm = FefO2_KC91_Eq7_terms(PT,melt_wf,species,models)
|
|
1387
|
+
lnXFe2O3XFeO = a*gp.log(fO2) + PTterm
|
|
1388
|
+
XFe2O3XFeO = gp.exp(lnXFe2O3XFeO)
|
|
1389
|
+
return (2.0*XFe2O3XFeO)/((2.0*XFe2O3XFeO)+1.0)
|
|
1390
|
+
|
|
1391
|
+
elif model == "Kress91A":
|
|
1392
|
+
kd1, KD2, y = FefO2_KC91_EqA_terms(PT,melt_wf,species,models)
|
|
1393
|
+
XFeO15XFeO = ((kd1*fO2**0.25)+(2.0*y*KD2*(kd1**(2.0*y))*(fO2**(0.5*y))))/(1.0 + (1.0 - 2.0*y)*KD2*(kd1**(2.0*y))*(fO2**(0.5*y)))
|
|
1394
|
+
return XFeO15XFeO/(XFeO15XFeO+1.0)
|
|
1395
|
+
|
|
1396
|
+
elif model == "ONeill18": # O'Neill et al. (2018) EPSL 504:152-162
|
|
1397
|
+
a,B,FMQ = FefO2_ONeill18_terms(PT,melt_wf,species,models)
|
|
1398
|
+
DQFM = gp.log10(fO2) - FMQ
|
|
1399
|
+
lnFe3Fe2 = a*DQFM + B
|
|
1400
|
+
Fe3Fe2 = gp.exp(lnFe3Fe2)
|
|
1401
|
+
return Fe3Fe2/(Fe3Fe2 + 1.0)
|
|
1402
|
+
|
|
1403
|
+
elif model == "Borisov18": # Borisov et al. (2018) CMP 173:
|
|
1404
|
+
a,B = FefO2_Borisov18_terms(PT,melt_wf,species,models)
|
|
1405
|
+
Fe3Fe2 = 10.**(a*gp.log10(fO2) + B)
|
|
1406
|
+
return Fe3Fe2/(Fe3Fe2 + 1.0)
|
|
1407
|
+
|
|
1408
|
+
def f_O2(PT,melt_wf,species,models):
|
|
1409
|
+
|
|
1410
|
+
model = models.loc["fO2","option"]
|
|
1411
|
+
|
|
1412
|
+
def KC91(PT,melt_wf,species,models):
|
|
1413
|
+
a, PTterm = FefO2_KC91_Eq7_terms(PT,melt_wf,species,models)
|
|
1414
|
+
F = 0.5*mg.Fe3Fe2(melt_wf) # XFe2O3/XFeO
|
|
1415
|
+
alnfO2 = math.log(F) - PTterm
|
|
1416
|
+
fO2 = math.exp(alnfO2/a)
|
|
1417
|
+
return fO2
|
|
1418
|
+
|
|
1419
|
+
#if model == "yes":
|
|
1420
|
+
# return 10.0**(setup.loc[run,"logfO2"])
|
|
1421
|
+
|
|
1422
|
+
if model == "Kress91":
|
|
1423
|
+
fO2 = KC91(PT,melt_wf,species,models)
|
|
1424
|
+
return fO2
|
|
1425
|
+
|
|
1426
|
+
elif model == "Kress91A":
|
|
1427
|
+
F = mg.Fe3Fe2(melt_wf) # XFeO1.5/XFeO
|
|
1428
|
+
kd1, KD2, y = FefO2_KC91_EqA_terms(PT,melt_wf,species,models)
|
|
1429
|
+
|
|
1430
|
+
def f(y,F,KD2,kd1,x): # KC91A rearranged to equal 0
|
|
1431
|
+
f = ((2.0*y - F + 2.0*y*F)*KD2*kd1**(2.0*y)*x**(0.5*y) + kd1*x**0.25 - F)
|
|
1432
|
+
return f
|
|
1433
|
+
|
|
1434
|
+
def df(y,F,KD2,kd1,x): # derivative of above
|
|
1435
|
+
df = (0.5*y)*(2.0*y - F +2.0*y*F)*KD2*kd1**(2.0*y)*x**((0.5*y)-1.0) + 0.25*kd1*x**-0.75
|
|
1436
|
+
return df
|
|
1437
|
+
|
|
1438
|
+
def dx(x):
|
|
1439
|
+
diff = abs(0-f(y,F,KD2,kd1,x))
|
|
1440
|
+
return diff
|
|
1441
|
+
|
|
1442
|
+
def nr(x0, e1):
|
|
1443
|
+
delta1 = dx(x0)
|
|
1444
|
+
while delta1 > e1:
|
|
1445
|
+
x0 = x0 - f(y,F,KD2,kd1,x0)/df(y,F,KD2,kd1,x0)
|
|
1446
|
+
delta1 = dx(x0)
|
|
1447
|
+
return x0
|
|
1448
|
+
|
|
1449
|
+
x0 = KC91(PT,melt_wf,species,models)
|
|
1450
|
+
|
|
1451
|
+
fO2 = nr(x0, 1.e-15)
|
|
1452
|
+
return fO2
|
|
1453
|
+
|
|
1454
|
+
elif model == "ONeill18": # O'Neill et al. (2018) EPSL 504:152-162
|
|
1455
|
+
F = mg.Fe3Fe2(melt_wf) # Fe3+/Fe2+
|
|
1456
|
+
a,B,FMQ = FefO2_ONeill18_terms(PT,melt_wf,species,models)
|
|
1457
|
+
DQFM = (math.log(F) - B)/a
|
|
1458
|
+
logfO2 = DQFM + FMQ
|
|
1459
|
+
return 10.0**logfO2
|
|
1460
|
+
|
|
1461
|
+
#elif model == "S6ST": # remove?!?!
|
|
1462
|
+
# S6T = melt_wf['S6ST']
|
|
1463
|
+
# S62 = mg.overtotal2ratio(S6T)
|
|
1464
|
+
# fO2 = mg.S6S2_2_fO2(S62,melt_wf,run,PT,setup,species,models)
|
|
1465
|
+
# return fO2
|
|
1466
|
+
|
|
1467
|
+
elif model == "Borisov18": # Borisov et al. (2018) CMP 173
|
|
1468
|
+
F = mg.Fe3Fe2(melt_wf)
|
|
1469
|
+
a,B = FefO2_Borisov18_terms(PT,melt_wf,species,models)
|
|
1470
|
+
fO2 = 10.**((gp.log10(F) - B)/a)
|
|
1471
|
+
return fO2
|
|
1472
|
+
|
|
1473
|
+
def S_Nash19_terms(PT): # Nash et al. 2019
|
|
1474
|
+
T_K = PT['T']+273.15
|
|
1475
|
+
A = 8.
|
|
1476
|
+
B = ((8.7436e6)/pow(T_K,2.0)) - (27703.0/T_K) + 20.273
|
|
1477
|
+
return A, B
|
|
1478
|
+
|
|
1479
|
+
# density of the melt in g/cm3 using DensityX (Iacovino & Till 2019 Volcanica 2(1))
|
|
1480
|
+
def melt_density(PT,melt_wf,species,models):
|
|
1481
|
+
if models.loc["density","option"] == "DensityX":
|
|
1482
|
+
melt_comp = mg.melt_normalise_wf(melt_wf,species,"water","yes")
|
|
1483
|
+
P = PT["P"]
|
|
1484
|
+
T = PT["T"]
|
|
1485
|
+
melt_dx = pd.DataFrame([["sample", melt_comp["SiO2"], melt_comp["TiO2"], melt_comp["Al2O3"], melt_comp["FeO"], melt_comp["Fe2O3"], melt_comp["MgO"], melt_comp["CaO"], melt_comp["Na2O"], melt_comp["K2O"], melt_comp["H2O"],P,T]])
|
|
1486
|
+
melt_dx.columns = ["Sample_ID","SiO2","TiO2","Al2O3","FeO","Fe2O3","MgO","CaO","Na2O","K2O","H2O","P","T"]
|
|
1487
|
+
output = dx.Density(melt_dx)
|
|
1488
|
+
density = output.loc[0,"Density_g_per_cm3"]
|
|
1489
|
+
return density
|
|
1490
|
+
|
|
1491
|
+
#################################################################################################################################
|
|
1492
|
+
################################################# ISOTOPE FRACTIONATION FACTORS #################################################
|
|
1493
|
+
#################################################################################################################################
|
|
1494
|
+
|
|
1495
|
+
# beta factors from Richet et al. (1977) fitted to quadratic equation for 600 < T'C < 1300
|
|
1496
|
+
|
|
1497
|
+
def beta_gas(PT,element,species):
|
|
1498
|
+
t = 1./(PT["T"]+273.15)
|
|
1499
|
+
if element == "S":
|
|
1500
|
+
if species == "SO2":
|
|
1501
|
+
a, b, c = 4872.56428, 0.76400, 0.99975
|
|
1502
|
+
elif species == "S2":
|
|
1503
|
+
a, b, c = 1708.22425, -0.76202, 1.00031
|
|
1504
|
+
elif species == "OCS":
|
|
1505
|
+
a, b, c = 980.75175, 1.74954, 0.99930
|
|
1506
|
+
elif species == "H2S":
|
|
1507
|
+
a, b, c = 935.84901, 1.29355, 0.99969
|
|
1508
|
+
if models.loc["beta_factors","option"] == "Richet77":
|
|
1509
|
+
value = a*t**2 + b*t + c
|
|
1510
|
+
return value
|
|
1511
|
+
|
|
1512
|
+
def alpha_gas(element,A,B,PT):
|
|
1513
|
+
beta_A = beta_gas(PT,element,A)
|
|
1514
|
+
beta_B = beta_gas(PT,element,B)
|
|
1515
|
+
result = beta_A/beta_B
|
|
1516
|
+
return result
|
|
1517
|
+
|
|
1518
|
+
def alpha_H2S_S(PT,models): # Fiege et al. (2015) Chemical Geology equation 8 - H2S fluid and S2- melt
|
|
1519
|
+
if models.loc["alpha_H2S_S","option"] == "Fiege15":
|
|
1520
|
+
T_K = PT["T"] + 273.15
|
|
1521
|
+
lna103 = (10.84*((1000./T_K)**2)) - 2.5
|
|
1522
|
+
a = gp.exp(lna103/1000.)
|
|
1523
|
+
return a
|
|
1524
|
+
|
|
1525
|
+
def alpha_SO2_SO4(PT,models): # Fiege et al. (2015) Chemical Geology equation 9 - SO2 fluid and SO4 melt
|
|
1526
|
+
if models.loc["alpha_SO2_SO4","option"] == "Fiege15":
|
|
1527
|
+
T_K = PT["T"] + 273.15
|
|
1528
|
+
lna103 = (-0.42*((1000./T_K)**3)) - (2.133*((1000./T_K)**3)) - (0.105*(1000./T_K)) - 0.41
|
|
1529
|
+
a = gp.exp(lna103/1000.)
|
|
1530
|
+
return a
|
|
1531
|
+
|
|
1532
|
+
def alpha_A_B(element,A,B,PT,models):
|
|
1533
|
+
if A == "SO2" and B == "H2S":
|
|
1534
|
+
a = alpha_gas(element,A,B,PT)
|