PetThermoTools 0.2.31__py3-none-any.whl → 0.2.33__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.
- PetThermoTools/Barom.py +207 -404
- PetThermoTools/Liq.py +21 -7
- PetThermoTools/MELTS.py +21 -7
- PetThermoTools/Melting.py +3 -2
- PetThermoTools/Path.py +35 -15
- PetThermoTools/Plotting.py +19 -7
- PetThermoTools/_version.py +1 -1
- PetThermoTools-0.2.33.dist-info/LICENSE.txt +16 -0
- {PetThermoTools-0.2.31.dist-info → PetThermoTools-0.2.33.dist-info}/METADATA +1 -1
- PetThermoTools-0.2.33.dist-info/RECORD +20 -0
- PetThermoTools-0.2.31.dist-info/RECORD +0 -19
- {PetThermoTools-0.2.31.dist-info → PetThermoTools-0.2.33.dist-info}/WHEEL +0 -0
- {PetThermoTools-0.2.31.dist-info → PetThermoTools-0.2.33.dist-info}/top_level.txt +0 -0
PetThermoTools/Barom.py
CHANGED
@@ -10,6 +10,7 @@ from PetThermoTools.GenFuncs import *
|
|
10
10
|
from PetThermoTools.Plotting import *
|
11
11
|
from PetThermoTools.Liq import *
|
12
12
|
from PetThermoTools.MELTS import *
|
13
|
+
from PetThermoTools.Path import *
|
13
14
|
# try:
|
14
15
|
# from PetThermoTools.Holland import *
|
15
16
|
# except:
|
@@ -23,7 +24,212 @@ from tqdm.notebook import tqdm, trange
|
|
23
24
|
from scipy import interpolate
|
24
25
|
from shapely.geometry import MultiPoint, Point, Polygon
|
25
26
|
|
26
|
-
|
27
|
+
from functools import partial
|
28
|
+
import concurrent.futures
|
29
|
+
|
30
|
+
|
31
|
+
def run_melts_single(Pin, Model, comp, T_maxdrop_C, dt_C, T_initial_C,
|
32
|
+
fO2_buffer, fO2_offset, H2O_Sat, phases):
|
33
|
+
try:
|
34
|
+
return path_MELTS(
|
35
|
+
Model=Model,
|
36
|
+
comp=comp,
|
37
|
+
T_maxdrop_C=T_maxdrop_C,
|
38
|
+
dt_C=dt_C,
|
39
|
+
T_initial_C=T_initial_C,
|
40
|
+
P_bar=Pin,
|
41
|
+
find_liquidus=True,
|
42
|
+
fO2_buffer=fO2_buffer,
|
43
|
+
fO2_offset=fO2_offset,
|
44
|
+
fluid_sat=H2O_Sat,
|
45
|
+
Suppress=['rutile', 'tridymite'],
|
46
|
+
phases=phases
|
47
|
+
)
|
48
|
+
except Exception as e:
|
49
|
+
print(f"Failed at {Pin} bar: {e}")
|
50
|
+
return None
|
51
|
+
|
52
|
+
def mineral_cosaturation(Model="MELTSv1.0.2", cores=int(np.floor(multiprocessing.cpu_count()/2)), bulk=None,
|
53
|
+
phases=['quartz1', 'alkali-feldspar1', 'plagioclase1'],
|
54
|
+
P_bar=np.linspace(250, 5000, 32), Fe3Fet_init=None, H2O_init=None,
|
55
|
+
CO2_init=None, H2O_Sat=False, T_initial_C=None, dt_C=2,
|
56
|
+
T_maxdrop_C=50, T_cut_C=20, find_range=True,
|
57
|
+
find_min=True, fO2_buffer=None, fO2_offset=0.0, timeout = 30):
|
58
|
+
|
59
|
+
comp = bulk.copy()
|
60
|
+
if H2O_Sat:
|
61
|
+
comp['H2O_Liq'] = 20
|
62
|
+
|
63
|
+
comp = comp_fix(Model=Model, comp=comp, Fe3Fet_Liq=Fe3Fet_init,
|
64
|
+
H2O_Liq=H2O_init, CO2_Liq=CO2_init)
|
65
|
+
|
66
|
+
run_partial = partial(run_melts_single,
|
67
|
+
Model=Model, comp=comp, T_maxdrop_C=T_maxdrop_C,
|
68
|
+
dt_C=dt_C, T_initial_C=T_initial_C,
|
69
|
+
fO2_buffer=fO2_buffer, fO2_offset=fO2_offset,
|
70
|
+
H2O_Sat=H2O_Sat, phases=phases)
|
71
|
+
|
72
|
+
results = {}
|
73
|
+
with concurrent.futures.ProcessPoolExecutor(max_workers=cores) as executor:
|
74
|
+
futures = {executor.submit(run_partial, p): i for i, p in enumerate(P_bar)}
|
75
|
+
|
76
|
+
done, not_done = concurrent.futures.wait(
|
77
|
+
futures.keys(), timeout=timeout, return_when=concurrent.futures.ALL_COMPLETED
|
78
|
+
)
|
79
|
+
|
80
|
+
for future in done:
|
81
|
+
i = futures[future]
|
82
|
+
try:
|
83
|
+
results[f"P = {P_bar[i]:.2f} bars"] = future.result()
|
84
|
+
except Exception as e:
|
85
|
+
print(f"Failure at {P_bar[i]} bar: {e}")
|
86
|
+
results[f"P = {P_bar[i]:.2f} bars"] = {}
|
87
|
+
|
88
|
+
for future in not_done:
|
89
|
+
i = futures[future]
|
90
|
+
print(f"Timeout at {P_bar[i]} bar. Either the calculation was slow (increase timeout) or it failed.")
|
91
|
+
results[f"P = {P_bar[i]:.2f} bars"] = {}
|
92
|
+
future.cancel() # Cancel if still running
|
93
|
+
|
94
|
+
Results = stich(Res=results, multi=True, Model=Model)
|
95
|
+
|
96
|
+
## determine the offset between the phases
|
97
|
+
if len(phases) == 3:
|
98
|
+
arr = np.zeros((len(Results.keys()), 4))
|
99
|
+
arr2 = np.zeros((len(Results.keys()), 4))
|
100
|
+
columns = ['P_bar'] + phases + [phases[0] + ' - ' + phases[1], phases[0] + ' - ' + phases[2], phases[1] + ' - ' + phases[2], '3 Phase Saturation']
|
101
|
+
for i, r in enumerate(Results.keys()):
|
102
|
+
for idx, p in enumerate(phases):
|
103
|
+
if p in Results[r]['Mass'].keys():
|
104
|
+
arr[i, idx+1] = Results[r]['Conditions'].loc[Results[r]['Mass'][p] > 0.0, 'T_C'].values[0]
|
105
|
+
else:
|
106
|
+
arr[i, idx + 1] = np.nan
|
107
|
+
|
108
|
+
arr[i,0] = Results[r]['Conditions']['P_bar'].loc[0]
|
109
|
+
|
110
|
+
arr2[:, 0] = np.abs(arr[:,1] - arr[:,2])
|
111
|
+
arr2[:, 1] = np.abs(arr[:,1] - arr[:,3])
|
112
|
+
arr2[:, 2] = np.abs(arr[:,2] - arr[:,3])
|
113
|
+
arr2[:,3] = np.max(arr2[:,0:2], axis = 1)
|
114
|
+
|
115
|
+
r_arr = np.hstack((arr,arr2))
|
116
|
+
|
117
|
+
out = pd.DataFrame(data = r_arr, columns = columns)
|
118
|
+
out = out.sort_values('P_bar').reset_index(drop=True)
|
119
|
+
|
120
|
+
else:
|
121
|
+
arr = np.zeros((len(Results.keys()),4))
|
122
|
+
columns = ['P_bar'] + phases + [phases[0]+' - '+phases[1]]
|
123
|
+
for i, r in enumerate(Results.keys()):
|
124
|
+
for idx, p in enumerate(phases):
|
125
|
+
if p in Results[r]['Mass'].keys():
|
126
|
+
arr[i, idx+1] = Results[r]['Conditions'].loc[Results[r]['Mass'][p] > 0.0, 'T_C'].values[0]
|
127
|
+
else:
|
128
|
+
arr[i, idx + 1] = np.nan
|
129
|
+
|
130
|
+
arr[i,0] = Results[r]['Conditions']['P_bar'].loc[0]
|
131
|
+
|
132
|
+
arr[:,3] = np.abs(arr[:,1] - arr[:,2])
|
133
|
+
|
134
|
+
out = pd.DataFrame(data = r_arr, columns = columns)
|
135
|
+
out = out.sort_values('P_bar').reset_index(drop=True)
|
136
|
+
|
137
|
+
if find_min:
|
138
|
+
res = findmin(out = out, P_bar = P_bar, T_cut_C = T_cut_C)
|
139
|
+
out = {'CurveMin': res, 'Output': out}
|
140
|
+
else:
|
141
|
+
out = {'Output': out}
|
142
|
+
|
143
|
+
return out, Results
|
144
|
+
|
145
|
+
def findmin(out = None, P_bar = None, T_cut_C = None):
|
146
|
+
Res = out.copy()
|
147
|
+
|
148
|
+
if '3 Phase Saturation' in list(Res.keys()):
|
149
|
+
T_cut_old = T_cut_C
|
150
|
+
T_cut_C = T_cut_C + np.nanmin(Res[4:])
|
151
|
+
Minimum = list(Res.keys())[4:]
|
152
|
+
CurveMin = {}
|
153
|
+
for m in Minimum:
|
154
|
+
if len(Res[m][~np.isnan(Res[m].values)]) > 2:
|
155
|
+
y = Res[m][(~np.isnan(Res[m].values)) & (Res[m].values < T_cut_C)].values
|
156
|
+
x = P_bar[(~np.isnan(Res[m].values)) & (Res[m].values < T_cut_C)]
|
157
|
+
|
158
|
+
try:
|
159
|
+
y_new = interpolate.UnivariateSpline(x, y, k = 3)
|
160
|
+
|
161
|
+
P_new = np.linspace(P_bar[P_bar == np.nanmin(P_bar[(~np.isnan(Res[m].values)) & (Res[m].values < T_cut_C)])],
|
162
|
+
P_bar[P_bar == np.nanmax(P_bar[(~np.isnan(Res[m].values)) & (Res[m].values < T_cut_C)])], 200)
|
163
|
+
|
164
|
+
NewMin = np.nanmin(y_new(P_new))
|
165
|
+
P_min = P_new[np.where(y_new(P_new) == NewMin)][0]
|
166
|
+
if NewMin < T_cut_old:
|
167
|
+
Test = 'Pass'
|
168
|
+
else:
|
169
|
+
Test = 'Fail'
|
170
|
+
|
171
|
+
CurveMin[m] = {'P_min': P_min, 'Res_min': NewMin, 'y_new': y_new(P_new), 'P_new': P_new, 'test': Test}
|
172
|
+
except:
|
173
|
+
try:
|
174
|
+
y_new = interpolate.UnivariateSpline(x, y, k = 2)
|
175
|
+
|
176
|
+
P_new = np.linspace(P_bar[P_bar == np.nanmin(P_bar[(~np.isnan(Res[m].values)) & (Res[m].values < T_cut_C)])],
|
177
|
+
P_bar[P_bar == np.nanmax(P_bar[(~np.isnan(Res[m].values)) & (Res[m].values < T_cut_C)])], 200)
|
178
|
+
|
179
|
+
NewMin = np.nanmin(y_new(P_new))
|
180
|
+
P_min = P_new[np.where(y_new(P_new) == NewMin)][0]
|
181
|
+
if NewMin < T_cut_old:
|
182
|
+
Test = 'Pass'
|
183
|
+
else:
|
184
|
+
Test = 'Fail'
|
185
|
+
|
186
|
+
CurveMin[m] = {'P_min': P_min, 'Res_min': NewMin, 'y_new': y_new(P_new), 'P_new': P_new, 'test': Test}
|
187
|
+
except:
|
188
|
+
CurveMin[m] = {'P_min': np.nan, 'Res_min': np.nan, 'y_new': np.nan, 'P_new': np.nan, 'test': 'Fail'}
|
189
|
+
else:
|
190
|
+
y_new = np.nan
|
191
|
+
P_new = np.nan
|
192
|
+
NewMin = np.nan
|
193
|
+
P_min = np.nan
|
194
|
+
Test = 'Fail'
|
195
|
+
CurveMin[m] = {'P_min': P_min, 'Res_min': NewMin, 'y_new': y_new, 'P_new': P_new, 'test': Test}
|
196
|
+
|
197
|
+
else:
|
198
|
+
CurveMin = {}
|
199
|
+
m = Res.keys()[3]
|
200
|
+
if len(Res[m][~np.isnan(Res[m])]) > 2:
|
201
|
+
y = Res[m][(~np.isnan(Res[m].values)) & (Res[m].values < T_cut_C*2)].values
|
202
|
+
x = P_bar[(~np.isnan(Res[m].values)) & (Res[m].values < T_cut_C*2)]
|
203
|
+
|
204
|
+
try:
|
205
|
+
y_new = interpolate.UnivariateSpline(x, y, k = 3)
|
206
|
+
except:
|
207
|
+
y_new = interpolate.UnivariateSpline(x, y, k = 2)
|
208
|
+
|
209
|
+
P_new = np.linspace(P_bar[P_bar == np.nanmin(P_bar[(~np.isnan(Res[m])) & (Res[m] < T_cut_C*2)])],
|
210
|
+
P_bar[P_bar == np.nanmax(P_bar[(~np.isnan(Res[m])) & (Res[m] < T_cut_C*2)])], 200)
|
211
|
+
|
212
|
+
NewMin = np.nanmin(y_new(P_new))
|
213
|
+
P_min = P_new[np.where(y_new(P_new) == NewMin)][0]
|
214
|
+
if NewMin < T_cut_C:
|
215
|
+
Test = 'Pass'
|
216
|
+
else:
|
217
|
+
Test = 'Fail'
|
218
|
+
else:
|
219
|
+
y_new = np.nan
|
220
|
+
P_new = np.nan
|
221
|
+
NewMin = np.nan
|
222
|
+
P_min = np.nan
|
223
|
+
Test = 'Fail'
|
224
|
+
|
225
|
+
CurveMin[m] = {'P_min': P_min, 'Res_min': NewMin, 'y_new': y_new, 'P_new': P_new, 'test': Test}
|
226
|
+
|
227
|
+
return CurveMin
|
228
|
+
|
229
|
+
|
230
|
+
def find_mineral_cosaturation(cores = None, Model = None, bulk = None, phases = None, P_bar = None, Fe3Fet_Liq = None,
|
231
|
+
H2O_Liq = None, H2O_Sat = False, T_initial_C = None, dt_C = None, T_maxdrop_C = None,
|
232
|
+
T_cut_C = None, find_range = None, find_min = None, fO2_buffer = None, fO2_offset = None):
|
27
233
|
'''
|
28
234
|
Carry out multiple calculations in parallel. Allows isobaric, polybaric and isochoric crystallisation to be performed as well as isothermal, isenthalpic or isentropic decompression. All temperature inputs/outputs are reported in degrees celcius and pressure is reported in bars.
|
29
235
|
|
@@ -621,406 +827,3 @@ def satTemperature(q, index, *, Model = None, comp = None, phases = None, T_init
|
|
621
827
|
return
|
622
828
|
|
623
829
|
|
624
|
-
# def detRange(P, Model, bulk, Results, Phases, T_initial = None, Fe3 = None, H2O = None, T_cut = None, findRange = None, cores = None):
|
625
|
-
# '''
|
626
|
-
# re-run the SatPress calculations using a higher resolution to determine the range of P (+H2O +fO2) where the maximum difference between the target saturation curve is below some reference value.
|
627
|
-
# '''
|
628
|
-
# if T_cut is None:
|
629
|
-
# T_cut = 5
|
630
|
-
#
|
631
|
-
# if T_initial is None:
|
632
|
-
# T_initial = 1200
|
633
|
-
#
|
634
|
-
# Res_key = list(Results.keys())[:-2]
|
635
|
-
#
|
636
|
-
# if Fe3 is None and H2O is None:
|
637
|
-
# P_min = np.zeros(len(Res_key))
|
638
|
-
# P_max = np.zeros(len(Res_key))
|
639
|
-
# i = 0
|
640
|
-
# for Res in Res_key:
|
641
|
-
# if len(Results[Res][np.where(Results[Res]<T_cut*2)]) > 0:
|
642
|
-
# P_min[i] = np.nanmin(P[np.where(Results[Res]<T_cut*2)])
|
643
|
-
# P_max[i] = np.nanmax(P[np.where(Results[Res]<T_cut*2)])
|
644
|
-
# else:
|
645
|
-
# P_min[i] = np.nan
|
646
|
-
# P_max[i] = np.nan
|
647
|
-
#
|
648
|
-
# i = i + 1
|
649
|
-
#
|
650
|
-
# P_start = np.nanmin(P_min)
|
651
|
-
# P_end = np.nanmax(P_max)
|
652
|
-
#
|
653
|
-
# P_space = 1 + 3*(P_end - P_start)/((np.max(P) - np.min(P))/(len(P)-1))
|
654
|
-
#
|
655
|
-
# P = np.linspace(P_start, P_end, int(P_space))
|
656
|
-
#
|
657
|
-
# with open('bulk.obj', 'wb') as f:
|
658
|
-
# pickle.dump(bulk, f)
|
659
|
-
#
|
660
|
-
# if len(Phases) == 3:
|
661
|
-
# phases[0], b_Sat, c_Sat, T_Liq, H2O_Melt = findSat(P, Model, Phases, bulk, T_initial = T_initial, dt = T_cut, T_step = T_cut, cores = cores)
|
662
|
-
# else:
|
663
|
-
# phases[0], b_Sat, T_Liq, H2O_Melt = findSat(P, Model, Phases, bulk, T_initial = T_initial, dt = T_cut, T_step = T_cut, cores = cores)
|
664
|
-
#
|
665
|
-
# # calc residuals
|
666
|
-
# if len(Phases) == 3:
|
667
|
-
# Results_new = findResiduals(phases[0], b_Sat, c_Sat = c_Sat)
|
668
|
-
# else:
|
669
|
-
# Results_new = findResiduals(phases[0], b_Sat)
|
670
|
-
#
|
671
|
-
# Results_new['H2O_sat'] = H2O_Melt
|
672
|
-
# Results_new['T_Liq'] = T_Liq
|
673
|
-
#
|
674
|
-
# for Res in Res_key:
|
675
|
-
# if len(Results_new[Res][np.where(~np.isnan(Results_new[Res]))]) > 0:
|
676
|
-
# Results_new[Res + '_min_P'] = np.nanmin(P[~np.isnan(Results_new[Res])])
|
677
|
-
# Results_new[Res + '_max_P'] = np.nanmin(P[~np.isnan(Results_new[Res])])
|
678
|
-
# else:
|
679
|
-
# Results_new[Res + '_min_P'] = np.nan
|
680
|
-
# Results_new[Res + '_max_P'] = np.nan
|
681
|
-
#
|
682
|
-
# return Results_new
|
683
|
-
#
|
684
|
-
# if Fe3 is not None and H2O is None:
|
685
|
-
# P_min = np.zeros(len(Res_key))
|
686
|
-
# P_max = np.zeros(len(Res_key))
|
687
|
-
#
|
688
|
-
# Fe3_min = np.zeros(len(Res_key))
|
689
|
-
# Fe3_max = np.zeros(len(Res_key))
|
690
|
-
#
|
691
|
-
# P_mat, Fe3_mat = np.meshgrid(P, Fe3)
|
692
|
-
#
|
693
|
-
# i = 0
|
694
|
-
# for Res in Res_key:
|
695
|
-
# if len(Results[Res][np.where(Results[Res]<T_cut*2)]) > 0:
|
696
|
-
# P_min[i] = np.nanmin(P_mat[np.where(Results[Res]<T_cut*2)])
|
697
|
-
# P_max[i] = np.nanmax(P_mat[np.where(Results[Res]<T_cut*2)])
|
698
|
-
#
|
699
|
-
# Fe3_min[i] = np.nanmin(Fe3_mat[np.where(Results[Res]<T_cut*2)])
|
700
|
-
# Fe3_max[i] = np.nanmax(Fe3_mat[np.where(Results[Res]<T_cut*2)])
|
701
|
-
# else:
|
702
|
-
#
|
703
|
-
# P_min[i] = np.nan
|
704
|
-
# P_max[i] = np.nan
|
705
|
-
#
|
706
|
-
# Fe3_min[i] = np.nan
|
707
|
-
# Fe3_max[i] = np.nan
|
708
|
-
#
|
709
|
-
# i = i + 1
|
710
|
-
#
|
711
|
-
# P_start = np.nanmin(P_min)
|
712
|
-
# P_end = np.nanmax(P_max)
|
713
|
-
#
|
714
|
-
# Fe3_start = np.nanmin(Fe3_min)
|
715
|
-
# Fe3_end = np.nanmax(Fe3_max)
|
716
|
-
#
|
717
|
-
# P = np.linspace(P_start, P_end, int(1 + 3*(P_end - P_start)/((np.max(P) - np.min(P))/(len(P)-1))))
|
718
|
-
# Fe3 = np.linspace(Fe3_start, Fe3_end, int(1 + 3*(Fe3_end - Fe3_start)/((np.max(Fe3) - np.min(Fe3))/(len(Fe3)-1))))
|
719
|
-
#
|
720
|
-
# if len(Phases) == 3:
|
721
|
-
# Res_abc_mat = np.zeros((len(Fe3), len(P)))
|
722
|
-
# Res_ac_mat = np.zeros((len(Fe3), len(P)))
|
723
|
-
# Res_bc_mat = np.zeros((len(Fe3), len(P)))
|
724
|
-
#
|
725
|
-
# Res_ab_mat = np.zeros((len(Fe3), len(P)))
|
726
|
-
# H2O_mat = np.zeros((len(Fe3), len(P)))
|
727
|
-
# T_Liq_mat = np.zeros((len(Fe3), len(P)))
|
728
|
-
#
|
729
|
-
# for i in range(len(Fe3)):
|
730
|
-
# Bulk_new = bulk.copy()
|
731
|
-
# Bulk_new[3] = Fe3[i]*((159.69/2)/71.844)*bulk[5]
|
732
|
-
# Bulk_new[5] = (1-Fe3[i])*bulk[5]
|
733
|
-
#
|
734
|
-
# with open('bulk.obj', 'wb') as f:
|
735
|
-
# pickle.dump(Bulk_new, f)
|
736
|
-
#
|
737
|
-
# if len(Phases) == 3:
|
738
|
-
# phases[0], b_Sat, c_Sat, T_Liq, H2O_Melt = findSat(P, Model, Phases, bulk, T_initial = T_initial, dt = T_cut, T_step = T_cut, cores = cores)
|
739
|
-
# else:
|
740
|
-
# phases[0], b_Sat, T_Liq, H2O_Melt = findSat(P, Model, Phases, bulk, T_initial = T_initial, dt = T_cut, T_step = T_cut, cores = cores)
|
741
|
-
#
|
742
|
-
# # calc residuals
|
743
|
-
# if len(Phases) == 3:
|
744
|
-
# Res = findResiduals(phases[0], b_Sat, c_Sat = c_Sat)
|
745
|
-
# Res_abc_mat[i, :] = Res['abc']
|
746
|
-
# Res_ac_mat[i, :] = Res['ac']
|
747
|
-
# Res_bc_mat[i, :] = Res['bc']
|
748
|
-
# else:
|
749
|
-
# Res = findResiduals(phases[0], b_Sat)
|
750
|
-
#
|
751
|
-
# T_Liq_mat[i, :] = T_Liq
|
752
|
-
# H2O_mat[i, :] = H2O_Melt
|
753
|
-
# Res_ab_mat[i, :] = Res['ab']
|
754
|
-
#
|
755
|
-
# if len(Phases) == 3:
|
756
|
-
# Results_new = {'abc': Res_abc_mat, 'ab': Res_ab_mat, 'ac': Res_ac_mat, 'bc': Res_bc_mat, 'H2O_Sat': H2O_mat, 'T_Liq': T_Liq_mat}
|
757
|
-
# else:
|
758
|
-
# Results_new = {'ab': Res_ab_mat, 'H2O_Sat': H2O_mat, 'T_Liq': T_Liq_mat}
|
759
|
-
#
|
760
|
-
# P_mat, Fe3_mat = np.meshgrid(P, Fe3)
|
761
|
-
# for Res in Res_key:
|
762
|
-
# if len(Results_new[Res][np.where(~np.isnan(Results_new[Res]))]) > 0:
|
763
|
-
# Results_new[Res + '_min_P'] = np.nanmin(P_mat[np.where(~np.isnan(Results_new[Res]))])
|
764
|
-
# Results_new[Res + '_max_P'] = np.nanmin(P_mat[np.where(~np.isnan(Results_new[Res]))])
|
765
|
-
#
|
766
|
-
# Results_new[Res + '_min_Fe3'] = np.nanmin(Fe3_mat[np.where(~np.isnan(Results_new[Res]))])
|
767
|
-
# Results_new[Res + '_max_Fe3'] = np.nanmin(Fe3_mat[np.where(~np.isnan(Results_new[Res]))])
|
768
|
-
# else:
|
769
|
-
# Results_new[Res + '_min_P'] = np.nan
|
770
|
-
# Results_new[Res + '_max_P'] = np.nan
|
771
|
-
#
|
772
|
-
# Results_new[Res + '_min_Fe3'] = np.nan
|
773
|
-
# Results_new[Res + '_max_Fe3'] = np.nan
|
774
|
-
#
|
775
|
-
# return Results_new
|
776
|
-
#
|
777
|
-
# if Fe3 is None and H2O is not None:
|
778
|
-
# P_min = np.zeros(len(Res_key))
|
779
|
-
# P_max = np.zeros(len(Res_key))
|
780
|
-
#
|
781
|
-
# H2O_min = np.zeros(len(Res_key))
|
782
|
-
# H2O_max = np.zeros(len(Res_key))
|
783
|
-
#
|
784
|
-
# P_mat, H2O_mat = np.meshgrid(P, H2O)
|
785
|
-
#
|
786
|
-
# i = 0
|
787
|
-
# for Res in Res_key:
|
788
|
-
# if len(Results[Res][np.where(Results[Res]<T_cut*2)]) > 0:
|
789
|
-
# P_min[i] = np.nanmin(P_mat[np.where(Results[Res]<T_cut*2)])
|
790
|
-
# P_max[i] = np.nanmax(P_mat[np.where(Results[Res]<T_cut*2)])
|
791
|
-
#
|
792
|
-
# H2O_min[i] = np.nanmin(H2O_mat[np.where(Results[Res]<T_cut*2)])
|
793
|
-
# H2O_max[i] = np.nanmax(H2O_mat[np.where(Results[Res]<T_cut*2)])
|
794
|
-
# else:
|
795
|
-
#
|
796
|
-
# P_min[i] = np.nan
|
797
|
-
# P_max[i] = np.nan
|
798
|
-
#
|
799
|
-
# H2O_min[i] = np.nan
|
800
|
-
# H2O_max[i] = np.nan
|
801
|
-
#
|
802
|
-
# i = i + 1
|
803
|
-
#
|
804
|
-
# P_start = np.nanmin(P_min)
|
805
|
-
# P_end = np.nanmax(P_max)
|
806
|
-
#
|
807
|
-
# H2O_start = np.nanmin(H2O_min)
|
808
|
-
# H2O_end = np.nanmax(H2O_max)
|
809
|
-
#
|
810
|
-
# P = np.linspace(P_start, P_end, int(1 + 3*(P_end - P_start)/((np.max(P) - np.min(P))/(len(P)-1))))
|
811
|
-
# H2O = np.linspace(H2O_start, H2O_end, int(1 + 3*(H2O_end - H2O_start)/((np.max(H2O) - np.min(H2O))/(len(H2O)-1))))
|
812
|
-
#
|
813
|
-
# if len(Phases) == 3:
|
814
|
-
# Res_abc_mat = np.zeros((len(H2O), len(P)))
|
815
|
-
# Res_ac_mat = np.zeros((len(H2O), len(P)))
|
816
|
-
# Res_bc_mat = np.zeros((len(H2O), len(P)))
|
817
|
-
#
|
818
|
-
# Res_ab_mat = np.zeros((len(H2O), len(P)))
|
819
|
-
# H2O_mat = np.zeros((len(H2O), len(P)))
|
820
|
-
# T_Liq_mat = np.zeros((len(H2O), len(P)))
|
821
|
-
#
|
822
|
-
# for i in range(len(H2O)):
|
823
|
-
# Bulk_new = bulk.copy()
|
824
|
-
# Bulk_new[14] = H2O[i]
|
825
|
-
#
|
826
|
-
# with open('bulk.obj', 'wb') as f:
|
827
|
-
# pickle.dump(Bulk_new, f)
|
828
|
-
#
|
829
|
-
# if len(Phases) == 3:
|
830
|
-
# phases[0], b_Sat, c_Sat, T_Liq, H2O_Melt = findSat(P, Model, Phases, bulk, T_initial = T_initial, dt = T_cut, T_step = T_cut, cores = cores)
|
831
|
-
# else:
|
832
|
-
# phases[0], b_Sat, T_Liq, H2O_Melt = findSat(P, Model, Phases, bulk, T_initial = T_initial, dt = T_cut, T_step = T_cut, cores = cores)
|
833
|
-
#
|
834
|
-
# # calc residuals
|
835
|
-
# if len(Phases) == 3:
|
836
|
-
# Res = findResiduals(phases[0], b_Sat, c_Sat = c_Sat)
|
837
|
-
# Res_abc_mat[i, :] = Res['abc']
|
838
|
-
# Res_ac_mat[i, :] = Res['ac']
|
839
|
-
# Res_bc_mat[i, :] = Res['bc']
|
840
|
-
# else:
|
841
|
-
# Res = findResiduals(phases[0], b_Sat)
|
842
|
-
#
|
843
|
-
# T_Liq_mat[i, :] = T_Liq
|
844
|
-
# H2O_mat[i, :] = H2O_Melt
|
845
|
-
# Res_ab_mat[i, :] = Res['ab']
|
846
|
-
#
|
847
|
-
# if len(Phases) == 3:
|
848
|
-
# Results_new = {'abc': Res_abc_mat, 'ab': Res_ab_mat, 'ac': Res_ac_mat, 'bc': Res_bc_mat, 'H2O_Sat': H2O_mat, 'T_Liq': T_Liq_mat}
|
849
|
-
# else:
|
850
|
-
# Results_new = {'ab': Res_ab_mat, 'H2O_Sat': H2O_mat, 'T_Liq': T_Liq_mat}
|
851
|
-
#
|
852
|
-
# P_mat, H2O_mat = np.meshgrid(P, H2O)
|
853
|
-
# for Res in Res_key:
|
854
|
-
# if len(Results_new[Res][np.where(~np.isnan(Results_new[Res]))]) > 0:
|
855
|
-
# Results_new[Res + '_min_P']= np.nanmin(P_mat[np.where(~np.isnan(Results_new[Res]))])
|
856
|
-
# Results_new[Res + '_max_P'] = np.nanmin(P_mat[np.where(~np.isnan(Results_new[Res]))])
|
857
|
-
#
|
858
|
-
# Results_new[Res + '_min_H2O'] = np.nanmin(Results_new['H2O_Sat'][np.where(~np.isnan(Results_new[Res]))])
|
859
|
-
# Results_new[Res + '_max_H2O'] = np.nanmin(Results_new['H2O_Sat'][np.where(~np.isnan(Results_new[Res]))])
|
860
|
-
# else:
|
861
|
-
# Results_new[Res + '_min_P']= np.nan
|
862
|
-
# Results_new[Res + '_max_P'] = np.nan
|
863
|
-
#
|
864
|
-
# Results_new[Res + '_min_H2O'] = np.nan
|
865
|
-
# Results_new[Res + '_max_H2O'] = np.nan
|
866
|
-
#
|
867
|
-
# return Results_new
|
868
|
-
#
|
869
|
-
# if H2O is not None and Fe3 is not None:
|
870
|
-
# Results_new = {}
|
871
|
-
# P_min = np.zeros(len(Res_key))
|
872
|
-
# P_max = np.zeros(len(Res_key))
|
873
|
-
#
|
874
|
-
# Fe3_min = np.zeros(len(Res_key))
|
875
|
-
# Fe3_max = np.zeros(len(Res_key))
|
876
|
-
#
|
877
|
-
# H2O_min = np.zeros(len(Res_key))
|
878
|
-
# H2O_max = np.zeros(len(Res_key))
|
879
|
-
#
|
880
|
-
# Fe3_mat, H2O_mat, P_mat = np.meshgrid(Fe3, H2O, P)
|
881
|
-
#
|
882
|
-
# i = 0
|
883
|
-
# for Res in Res_key:
|
884
|
-
# if len(Results[Res][np.where(Results[Res]<T_cut*2)]) > 0:
|
885
|
-
# P_min[i] = np.nanmin(P_mat[np.where(Results[Res]<T_cut*2)])
|
886
|
-
# P_max[i] = np.nanmax(P_mat[np.where(Results[Res]<T_cut*2)])
|
887
|
-
#
|
888
|
-
# H2O_min[i] = np.nanmin(H2O_mat[np.where(Results[Res]<T_cut*2)])
|
889
|
-
# H2O_max[i] = np.nanmax(H2O_mat[np.where(Results[Res]<T_cut*2)])
|
890
|
-
#
|
891
|
-
# Fe3_min[i] = np.nanmin(Fe3_mat[np.where(Results[Res]<T_cut*2)])
|
892
|
-
# Fe3_max[i] = np.nanmax(Fe3_mat[np.where(Results[Res]<T_cut*2)])
|
893
|
-
# else:
|
894
|
-
#
|
895
|
-
# P_min[i] = np.nan
|
896
|
-
# P_max[i] = np.nan
|
897
|
-
#
|
898
|
-
# H2O_min[i] = np.nan
|
899
|
-
# H2O_max[i] = np.nan
|
900
|
-
#
|
901
|
-
# Fe3_min[i] = np.nan
|
902
|
-
# Fe3_max[i] = np.nan
|
903
|
-
#
|
904
|
-
# i = i + 1
|
905
|
-
#
|
906
|
-
# if findRange == 'abc':
|
907
|
-
# P_start = P_min[0] - (P[1] - P[0])/3
|
908
|
-
# P_end = P_max[0] + (P[1] - P[0])/3
|
909
|
-
#
|
910
|
-
# H2O_start = H2O_min[0] - (H2O[1] - H2O[0])/3
|
911
|
-
# H2O_end = H2O_max[0] + (H2O[1] - H2O[0])/3
|
912
|
-
#
|
913
|
-
# Fe3_start = Fe3_min[0] - (Fe3[1] - Fe3[0])/3
|
914
|
-
# Fe3_end = Fe3_max[0] + (Fe3[1] - Fe3[0])/3
|
915
|
-
# else:
|
916
|
-
# P_start = np.nanmin(P_min)
|
917
|
-
# P_end = np.nanmax(P_max)
|
918
|
-
#
|
919
|
-
# H2O_start = np.nanmin(H2O_min)
|
920
|
-
# H2O_end = np.nanmax(H2O_max)
|
921
|
-
#
|
922
|
-
# Fe3_start = np.nanmin(Fe3_min)
|
923
|
-
# Fe3_end = np.nanmax(Fe3_max)
|
924
|
-
#
|
925
|
-
# if P_end - P_start > 0:
|
926
|
-
# P = np.linspace(P_start, P_end, int(1 + 3*(P_end - P_start)/((np.max(P) - np.min(P))/(len(P)))))
|
927
|
-
# else:
|
928
|
-
# return Results_new
|
929
|
-
#
|
930
|
-
# if H2O_end - H2O_start > 0:
|
931
|
-
# H2O = np.linspace(H2O_start, H2O_end, int(1 + 3*(H2O_end - H2O_start)/((np.max(H2O) - np.min(H2O))/(len(H2O)))))
|
932
|
-
# else:
|
933
|
-
# return Results_new
|
934
|
-
#
|
935
|
-
# if Fe3_end - Fe3_start > 0:
|
936
|
-
# Fe3 = np.linspace(Fe3_start, Fe3_end, int(1 + 3*(Fe3_end - Fe3_start)/((np.max(Fe3) - np.min(Fe3))/(len(Fe3)))))
|
937
|
-
# else:
|
938
|
-
# return Results_new
|
939
|
-
#
|
940
|
-
# if len(Phases) == 3:
|
941
|
-
# Res_abc_mat = np.zeros((len(H2O), len(Fe3), len(P)))
|
942
|
-
# Res_ac_mat = np.zeros((len(H2O), len(Fe3), len(P)))
|
943
|
-
# Res_bc_mat = np.zeros((len(H2O), len(Fe3), len(P)))
|
944
|
-
#
|
945
|
-
# Res_ab_mat = np.zeros((len(H2O), len(Fe3), len(P)))
|
946
|
-
# T_Liq_3Dmat = np.zeros((len(H2O), len(Fe3), len(P)))
|
947
|
-
# H2O_Liq_3Dmat = np.zeros((len(H2O), len(Fe3), len(P)))
|
948
|
-
#
|
949
|
-
# for i in range(len(H2O)):
|
950
|
-
# Bulk_new = bulk.copy()
|
951
|
-
# Bulk_new[14] = H2O[i]
|
952
|
-
#
|
953
|
-
# if len(Phases) == 3:
|
954
|
-
# Res_abc_mat_2D = np.zeros((len(Fe3), len(P)))
|
955
|
-
# Res_ac_mat_2D = np.zeros((len(Fe3), len(P)))
|
956
|
-
# Res_bc_mat_2D = np.zeros((len(Fe3), len(P)))
|
957
|
-
#
|
958
|
-
# Res_ab_mat_2D = np.zeros((len(Fe3), len(P)))
|
959
|
-
# T_Liq_mat_2D = np.zeros((len(Fe3), len(P)))
|
960
|
-
# H2O_Liq_mat_2D = np.zeros((len(Fe3), len(P)))
|
961
|
-
#
|
962
|
-
# for j in range(len(Fe3)):
|
963
|
-
#
|
964
|
-
# Bulk_new[3] = Fe3[j]*((159.69/2)/71.844)*bulk[5]
|
965
|
-
# Bulk_new[5] = (1-Fe3[j])*bulk[5]
|
966
|
-
#
|
967
|
-
# with open('bulk.obj', 'wb') as f:
|
968
|
-
# pickle.dump(Bulk_new, f)
|
969
|
-
#
|
970
|
-
# if len(Phases) == 3:
|
971
|
-
# phases[0], b_Sat, c_Sat, T_Liq, H2O_Melt = findSat(P, Model, Phases, Bulk_new, T_initial = T_initial, dt = T_cut, T_step = T_cut, cores = cores)
|
972
|
-
# else:
|
973
|
-
# phases[0], b_Sat, T_Liq, H2O_Melt = findSat(P, Model, Phases, Bulk_new, T_initial = T_initial, dt = T_cut, T_step = T_cut, cores = cores)
|
974
|
-
#
|
975
|
-
# # calc residuals
|
976
|
-
# if len(Phases) == 3:
|
977
|
-
# Res = findResiduals(phases[0], b_Sat, c_Sat = c_Sat)
|
978
|
-
# Res_abc_mat_2D[j, :] = Res['abc']
|
979
|
-
# Res_ac_mat_2D[j, :] = Res['ac']
|
980
|
-
# Res_bc_mat_2D[j, :] = Res['bc']
|
981
|
-
# else:
|
982
|
-
# Res = findResiduals(phases[0], b_Sat)
|
983
|
-
#
|
984
|
-
# Res_ab_mat_2D[j, :] = Res['ab']
|
985
|
-
# T_Liq_mat_2D[j, :] = T_Liq
|
986
|
-
# H2O_Liq_mat_2D[j, :] = H2O_Melt
|
987
|
-
#
|
988
|
-
# if len(Phases) == 3:
|
989
|
-
# Res_abc_mat[i,:,:] = Res_abc_mat_2D
|
990
|
-
# Res_ac_mat[i,:,:] = Res_ac_mat_2D
|
991
|
-
# Res_bc_mat[i,:,:] = Res_bc_mat_2D
|
992
|
-
#
|
993
|
-
# Res_ab_mat[i,:,:] = Res_ab_mat_2D
|
994
|
-
# T_Liq_3Dmat[i,:,:] = T_Liq_mat_2D
|
995
|
-
# H2O_Liq_3Dmat[i,:,:] = H2O_Liq_mat_2D
|
996
|
-
#
|
997
|
-
# if len(Phases) == 3:
|
998
|
-
# Results_new = {'abc': Res_abc_mat, 'ab': Res_ab_mat, 'ac': Res_ac_mat, 'bc': Res_bc_mat, 'H2O_Sat': H2O_Liq_3Dmat, 'T_Liq': T_Liq_3Dmat}
|
999
|
-
# else:
|
1000
|
-
# Results_new = {'ab': Res_ab_mat, 'H2O_Sat': H2O_Liq_3Dmat, 'T_Liq': T_Liq_3Dmat}
|
1001
|
-
#
|
1002
|
-
#
|
1003
|
-
# Fe3_mat, H2O_mat, P_mat = np.meshgrid(Fe3, H2O, P)
|
1004
|
-
#
|
1005
|
-
# for Res in Res_key:
|
1006
|
-
# if len(Results_new[Res][np.where(~np.isnan(Results_new[Res]))]) > 0:
|
1007
|
-
# Results_new[Res + '_min_P'] = np.nanmin(P_mat[np.where(~np.isnan(Results_new[Res]))])
|
1008
|
-
# Results_new[Res + '_max_P'] = np.nanmax(P_mat[np.where(~np.isnan(Results_new[Res]))])
|
1009
|
-
#
|
1010
|
-
# Results_new[Res + '_min_H2O'] = np.nanmin(Results_new['H2O_Sat'][np.where(~np.isnan(Results_new[Res]))])
|
1011
|
-
# Results_new[Res + '_max_H2O'] = np.nanmax(Results_new['H2O_Sat'][np.where(~np.isnan(Results_new[Res]))])
|
1012
|
-
#
|
1013
|
-
# Results_new[Res + '_min_Fe3'] = np.nanmin(Fe3_mat[np.where(~np.isnan(Results_new[Res]))])
|
1014
|
-
# Results_new[Res + '_max_Fe3'] = np.nanmax(Fe3_mat[np.where(~np.isnan(Results_new[Res]))])
|
1015
|
-
# else:
|
1016
|
-
# Results_new[Res + '_min_P'] = np.nan
|
1017
|
-
# Results_new[Res + '_max_P'] = np.nan
|
1018
|
-
#
|
1019
|
-
# Results_new[Res + '_min_H2O'] = np.nan
|
1020
|
-
# Results_new[Res + '_max_H2O'] = np.nan
|
1021
|
-
#
|
1022
|
-
# Results_new[Res + '_min_Fe3'] = np.nan
|
1023
|
-
# Results_new[Res + '_max_Fe3'] = np.nan
|
1024
|
-
#
|
1025
|
-
# return Results_new
|
1026
|
-
|
PetThermoTools/Liq.py
CHANGED
@@ -366,12 +366,15 @@ def equilibrate_multi(cores = None, Model = None, bulk = None, T_C = None, P_bar
|
|
366
366
|
# Affinity = Af_Combined.copy()
|
367
367
|
return Combined
|
368
368
|
else:
|
369
|
-
import julia
|
370
|
-
from julia.api import Julia
|
371
|
-
jl = Julia(compiled_modules=False)
|
372
|
-
from julia import MAGEMinCalc
|
373
|
-
|
374
|
-
|
369
|
+
# import julia
|
370
|
+
# from julia.api import Julia
|
371
|
+
# jl = Julia(compiled_modules=False)
|
372
|
+
# from julia import MAGEMinCalc
|
373
|
+
## Output = MM.equilibrate_multi(P_bar = P_bar, T_C = T_C, comp = comp)
|
374
|
+
from juliacall import Main as jl, convert as jlconvert
|
375
|
+
|
376
|
+
jl.seval("using MAGEMinCalc")
|
377
|
+
|
375
378
|
comp['O'] = comp['Fe3Fet_Liq']*(((159.59/2)/71.844)*comp['FeOt_Liq'] - comp['FeOt_Liq'])
|
376
379
|
|
377
380
|
if Model == "Weller2024":
|
@@ -380,8 +383,19 @@ def equilibrate_multi(cores = None, Model = None, bulk = None, T_C = None, P_bar
|
|
380
383
|
bulk = comp[['SiO2_Liq', 'Al2O3_Liq', 'CaO_Liq', 'MgO_Liq', 'FeOt_Liq', 'K2O_Liq', 'Na2O_Liq', 'TiO2_Liq', 'O', 'Cr2O3_Liq', 'H2O_Liq']].astype(float).values
|
381
384
|
|
382
385
|
print(np.shape(bulk))
|
386
|
+
bulk_jl = jl.seval("collect")(bulk)
|
387
|
+
|
388
|
+
if type(T_C) == np.ndarray:
|
389
|
+
T_C = jl.seval("collect")(T_C)
|
390
|
+
if type(P_bar) == np.ndarray:
|
391
|
+
P_kbar = jl.seval("collect")(P_bar/1000.0)
|
392
|
+
else:
|
393
|
+
P_kbar = P_bar/1000.0
|
394
|
+
if type(fO2_offset) == np.ndarray:
|
395
|
+
fO2_offset = jl.seval("collect")(fO2_offset)
|
383
396
|
|
384
|
-
Output = MAGEMinCalc.equilibrate(bulk =
|
397
|
+
Output = jl.MAGEMinCalc.equilibrate(bulk = bulk_jl, P_kbar = P_kbar, T_C = T_C, fo2_buffer = fO2_buffer, fo2_offset = fO2_offset, Model = Model)
|
398
|
+
Output = dict(Output)
|
385
399
|
Combined = stich(Output, Model = Model)
|
386
400
|
|
387
401
|
if copy_columns is not None:
|
PetThermoTools/MELTS.py
CHANGED
@@ -299,7 +299,9 @@ def findCO2_MELTS(P_bar = None, Model = None, T_C = None, comp = None, melts = N
|
|
299
299
|
|
300
300
|
return T_Liq, H2O, CO2
|
301
301
|
|
302
|
-
def findLiq_MELTS(P_bar = None, Model = None, T_C_init = None, comp = None, melts = None,
|
302
|
+
def findLiq_MELTS(P_bar = None, Model = None, T_C_init = None, comp = None, melts = None,
|
303
|
+
fO2_buffer = None, fO2_offset = None, Step = None, fluid_test = None,
|
304
|
+
bulk_return = None, step = None, Affinity = False):
|
303
305
|
'''
|
304
306
|
Perform a single find liquidus calculation in MELTS. WARNING! Running this function directly from the command land/jupyter notebook will initiate the MELTS C library in the main python process. Once this has been initiated the MELTS C library cannot be re-loaded and failures during the calculation will likely cause a terminal error to occur.
|
305
307
|
|
@@ -801,12 +803,12 @@ def phaseSat_MELTS(Model = None, comp = None, phases = None, T_initial_C = None,
|
|
801
803
|
|
802
804
|
return Results
|
803
805
|
|
804
|
-
def path_MELTS(Model = None, comp = None, Frac_solid = None, Frac_fluid = None,
|
805
|
-
T_C = None, T_path_C = None, T_start_C = None, T_end_C = None, dt_C = None,
|
806
|
+
def path_MELTS(Model = None, comp = None, Frac_solid = None, Frac_fluid = None, T_initial_C = 1400,
|
807
|
+
T_C = None, T_path_C = None, T_start_C = None, T_end_C = None, dt_C = None, T_maxdrop_C = None,
|
806
808
|
P_bar = None, P_path_bar = None, P_start_bar = None, P_end_bar = None, dp_bar = None,
|
807
809
|
isenthalpic = None, isentropic = None, isochoric = None, find_liquidus = None,
|
808
810
|
fO2_buffer = None, fO2_offset = None, fluid_sat = None, Crystallinity_limit = None,
|
809
|
-
Suppress = ['rutile', 'tridymite'], Suppress_except=False):
|
811
|
+
Suppress = ['rutile', 'tridymite'], Suppress_except=False, phases=None):
|
810
812
|
'''
|
811
813
|
Perform a single calculation in MELTS. WARNING! Running this function directly from the command land/jupyter notebook will initiate the MELTS C library in the main python process. Once this has been initiated the MELTS C library cannot be re-loaded and failures during the calculation will likely cause a terminal error to occur.
|
812
814
|
|
@@ -946,18 +948,21 @@ def path_MELTS(Model = None, comp = None, Frac_solid = None, Frac_fluid = None,
|
|
946
948
|
if P_path_bar is not None:
|
947
949
|
try:
|
948
950
|
if type(P_path_bar) == np.ndarray:
|
949
|
-
Liq_Results = findLiq_MELTS(P_bar = P_path_bar[0], comp = bulk, melts = melts, fO2_buffer = fO2_buffer, fO2_offset = fO2_offset, T_C_init =
|
951
|
+
Liq_Results = findLiq_MELTS(P_bar = P_path_bar[0], comp = bulk, melts = melts, fO2_buffer = fO2_buffer, fO2_offset = fO2_offset, T_C_init = T_initial_C)
|
950
952
|
else:
|
951
|
-
Liq_Results = findLiq_MELTS(P_bar = P_path_bar, comp = bulk, melts = melts, fO2_buffer = fO2_buffer, fO2_offset = fO2_offset, T_C_init =
|
953
|
+
Liq_Results = findLiq_MELTS(P_bar = P_path_bar, comp = bulk, melts = melts, fO2_buffer = fO2_buffer, fO2_offset = fO2_offset, T_C_init = T_initial_C)
|
952
954
|
except:
|
953
955
|
return Results
|
954
956
|
elif P_start_bar is not None:
|
955
957
|
try:
|
956
|
-
Liq_Results = findLiq_MELTS(P_bar = P_start_bar, comp = bulk, melts = melts, fO2_buffer = fO2_buffer, fO2_offset = fO2_offset, T_C_init =
|
958
|
+
Liq_Results = findLiq_MELTS(P_bar = P_start_bar, comp = bulk, melts = melts, fO2_buffer = fO2_buffer, fO2_offset = fO2_offset, T_C_init = T_initial_C)
|
957
959
|
except:
|
958
960
|
return Results
|
959
961
|
|
962
|
+
print(Liq_Results)
|
960
963
|
T_start_C = Liq_Results['T_Liq'] + 0.1
|
964
|
+
if T_end_C is None and T_maxdrop_C is not None:
|
965
|
+
T_end_C = T_start_C - T_maxdrop_C
|
961
966
|
|
962
967
|
else:
|
963
968
|
if fO2_buffer is not None:
|
@@ -1155,6 +1160,15 @@ def path_MELTS(Model = None, comp = None, Frac_solid = None, Frac_fluid = None,
|
|
1155
1160
|
if Volume/Total_volume > Crystallinity_limit:
|
1156
1161
|
break
|
1157
1162
|
|
1163
|
+
if phases is not None:
|
1164
|
+
ll = 0
|
1165
|
+
for p in phases:
|
1166
|
+
if p in Results.keys():
|
1167
|
+
ll = ll + 1
|
1168
|
+
|
1169
|
+
if ll == len(phases):
|
1170
|
+
break
|
1171
|
+
|
1158
1172
|
melts = melts.addNodeAfter()
|
1159
1173
|
|
1160
1174
|
return Results
|
PetThermoTools/Melting.py
CHANGED
@@ -171,8 +171,9 @@ def AdiabaticMelt(q, index, *, Model = None, comp_1 = None, comp_2 = None, comp_
|
|
171
171
|
return
|
172
172
|
|
173
173
|
if Model == "Holland":
|
174
|
-
import pyMAGEMINcalc as MM
|
175
|
-
Results = MM.AdiabaticDecompressionMelting(comp = comp_1, T_p_C = Tp_C, P_start_kbar = P_start_bar/1000, P_end_kbar = P_end_bar/1000, dp_kbar = dp_bar/1000, Frac = 0)
|
174
|
+
# import pyMAGEMINcalc as MM
|
175
|
+
# Results = MM.AdiabaticDecompressionMelting(comp = comp_1, T_p_C = Tp_C, P_start_kbar = P_start_bar/1000, P_end_kbar = P_end_bar/1000, dp_kbar = dp_bar/1000, Frac = 0)
|
176
|
+
print('Note that the ability to use MAGEMin to performed adiabatic decompression melting in PetThermoTools has been temporarily disabled. The underlying issue will be fixed soon and this funciton will once again become available.')
|
176
177
|
q.put([Results, index])
|
177
178
|
return
|
178
179
|
|
PetThermoTools/Path.py
CHANGED
@@ -201,7 +201,7 @@ def multi_path(cores = None, Model = None, bulk = None, comp = None, Frac_solid
|
|
201
201
|
|
202
202
|
qs = []
|
203
203
|
q = Queue()
|
204
|
-
|
204
|
+
|
205
205
|
# perform calculation if only 1 calculation is specified
|
206
206
|
if One == 1:
|
207
207
|
if Print_suppress is None:
|
@@ -374,6 +374,7 @@ def multi_path(cores = None, Model = None, bulk = None, comp = None, Frac_solid
|
|
374
374
|
if Print_suppress is None:
|
375
375
|
print(" Complete (time taken = " + str(round(time.time() - s,2)) + " seconds)", end = "\n", flush = True)
|
376
376
|
|
377
|
+
|
377
378
|
Results = {}
|
378
379
|
Out = {}
|
379
380
|
for i in range(len(qs)):
|
@@ -452,7 +453,6 @@ def multi_path(cores = None, Model = None, bulk = None, comp = None, Frac_solid
|
|
452
453
|
|
453
454
|
#if "MELTS" in Model:
|
454
455
|
Results = stich(Results, multi = True, Model = Model, Frac_fluid = Frac_fluid, Frac_solid = Frac_solid)
|
455
|
-
|
456
456
|
|
457
457
|
for r in Results:
|
458
458
|
i = int(r.split('=')[1].strip())
|
@@ -625,21 +625,41 @@ def path(q, index, *, Model = None, comp = None, Frac_solid = None, Frac_fluid =
|
|
625
625
|
return
|
626
626
|
|
627
627
|
if "MELTS" not in Model:
|
628
|
-
import julia
|
629
|
-
from julia.api import Julia
|
630
|
-
jl = Julia(compiled_modules=False)
|
631
|
-
from julia import MAGEMinCalc
|
632
|
-
# import pyMAGEMINcalc as MM
|
633
|
-
# try:
|
634
|
-
|
628
|
+
# import julia
|
629
|
+
# from julia.api import Julia
|
630
|
+
# jl = Julia(compiled_modules=False)
|
631
|
+
# from julia import MAGEMinCalc
|
632
|
+
# # import pyMAGEMINcalc as MM
|
633
|
+
# # try:
|
634
|
+
# # Results = MM.path(Model = Model, comp = comp, Frac_solid = Frac_solid, Frac_fluid = Frac_fluid, T_C = T_C, T_path_C = T_path_C, T_start_C = T_start_C, T_end_C = T_end_C, dt_C = dt_C, P_bar = P_bar, P_path_bar = P_path_bar, P_start_bar = P_start_bar, P_end_bar = P_end_bar, dp_bar = dp_bar, find_liquidus = find_liquidus, fO2_buffer = fO2_buffer, fO2_offset = fO2_offset)
|
635
|
+
# if Frac_solid is None:
|
636
|
+
# Frac_solid = False
|
637
|
+
|
638
|
+
# Results = MAGEMinCalc.path(comp = comp, T_start_C = T_start_C, T_end_C = T_end_C, dt_C = dt_C,
|
639
|
+
# T_C = T_C, P_start_bar = P_start_bar, P_end_bar = P_end_bar, dp_bar = dp_bar,
|
640
|
+
# P_bar = P_bar, T_path_C = T_path_C, P_path_bar = P_path_bar, frac_xtal = Frac_solid,
|
641
|
+
# Model = Model, fo2_buffer = fO2_buffer, fo2_offset = fO2_offset, find_liquidus = find_liquidus)
|
642
|
+
# q.put([Results, index])
|
643
|
+
|
644
|
+
# import julia
|
645
|
+
from juliacall import Main as jl, convert as jlconvert
|
646
|
+
|
647
|
+
jl.seval("using MAGEMinCalc")
|
648
|
+
|
635
649
|
if Frac_solid is None:
|
636
650
|
Frac_solid = False
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
651
|
+
|
652
|
+
comp_julia = jl.seval("Dict")(comp)
|
653
|
+
|
654
|
+
Results = jl.MAGEMinCalc.path(
|
655
|
+
comp=comp_julia, T_start_C=T_start_C, T_end_C=T_end_C, dt_C=dt_C,
|
656
|
+
T_C=T_C, P_start_bar=P_start_bar, P_end_bar=P_end_bar, dp_bar=dp_bar,
|
657
|
+
P_bar=P_bar, T_path_C=T_path_C, P_path_bar=P_path_bar, frac_xtal=Frac_solid,
|
658
|
+
Model=Model, fo2_buffer=fO2_buffer, fo2_offset=fO2_offset, find_liquidus=find_liquidus
|
659
|
+
)
|
660
|
+
# Results = jl.pyconvert(dict, Results)
|
661
|
+
Results_df = dict(Results)
|
662
|
+
q.put([Results_df, index])
|
643
663
|
# except:
|
644
664
|
# q.put([])
|
645
665
|
# return
|
PetThermoTools/Plotting.py
CHANGED
@@ -131,12 +131,20 @@ def plot_surfaces(Results = None, P_bar = None, phases = None, H2O_Liq = None):
|
|
131
131
|
a.set_xlabel('P (bars)')
|
132
132
|
a.set_ylabel('T ($\degree$C)')
|
133
133
|
for i in range(len(phases)):
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
134
|
+
try:
|
135
|
+
if i == 0:
|
136
|
+
a.plot(P_bar, Results['Output'][phases[0]], '-r', linewidth = 2, label = phases[i])
|
137
|
+
if i == 1:
|
138
|
+
a.plot(P_bar, Results['Output'][phases[1]], '-b', linewidth = 2, label = phases[i])
|
139
|
+
if i == 2:
|
140
|
+
a.plot(P_bar, Results['Output'][phases[2]], '-k', linewidth = 2, label = phases[i])
|
141
|
+
except:
|
142
|
+
if i == 0:
|
143
|
+
a.plot(P_bar, Results[phases[0]][0,0,:], '-r', linewidth = 2, label = phases[i])
|
144
|
+
if i == 1:
|
145
|
+
a.plot(P_bar, Results[phases[1]][0,0,:], '-b', linewidth = 2, label = phases[i])
|
146
|
+
if i == 2:
|
147
|
+
a.plot(P_bar, Results[phases[2]][0,0,:], '-k', linewidth = 2, label = phases[i])
|
140
148
|
|
141
149
|
a.legend()
|
142
150
|
|
@@ -184,7 +192,11 @@ def residualT_plot(Results = None, P_bar = None, phases = None, H2O_Liq = None,
|
|
184
192
|
for i in range(2):
|
185
193
|
for j in range(2):
|
186
194
|
a[i][j].set_title(Name[i,j])
|
187
|
-
|
195
|
+
try:
|
196
|
+
a[i][j].plot(P_bar, Results['Output'][m[i,j]], 'ok', markerfacecolor="b", label="original", markersize = 8)
|
197
|
+
except:
|
198
|
+
print("You are using the old find_mineral_saturation function.\n This will soon be removed, please transition to the mineral_cosaturation function.")
|
199
|
+
a[i][j].plot(P_bar, Results[m[i,j]][0,0,:], 'ok', markerfacecolor="b", label="original", markersize = 8)
|
188
200
|
if interpolate is True:
|
189
201
|
if ~np.isnan(Results['CurveMin'][m[i,j]]['P_min']):
|
190
202
|
a[i][j].plot(Results['CurveMin'][m[i,j]]['P_new'], Results['CurveMin'][m[i,j]]['y_new'],
|
PetThermoTools/_version.py
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
LICENSE
|
2
|
+
|
3
|
+
Copyright (c) [2025] [Matthew Gleeson]
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, subject to the following conditions:
|
6
|
+
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
8
|
+
|
9
|
+
Special Clause on GUI Usage
|
10
|
+
|
11
|
+
Use of PetThermoTools in graphical user interfaces (GUIs), including but not limited to applications that provide point-and-click access to PetThermoTools's functions, requires prior written permission from the author.
|
12
|
+
|
13
|
+
This requirement exists because of a broader issue in the geoscience community: tools that wrap or interface with core scientific software often receive the bulk of citations, while foundational packages like PetThermoTools go unrecognized—particularly when journals impose citation limits. PetThermoTools represents a significant and ongoing labor investment. Responsible citation and acknowledgment are necessary to support its continued development and maintenance.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
16
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
PetThermoTools/Barom.py,sha256=zfRgGnqInXP1B5oG_k5ZMJH3cylHcQXWiBRz7YlQjkw,36119
|
2
|
+
PetThermoTools/Compositions.py,sha256=65NzfduzWdfHJ8VmHBN1Cv7fMz7kF3QbDVLei-e4v00,1483
|
3
|
+
PetThermoTools/GenFuncs.py,sha256=u2GWqH--Wmqd0WXHxfulEAatQb6uswjl1s9SyyoHSa8,16412
|
4
|
+
PetThermoTools/Holland.py,sha256=udBFeVUyTBpSfLIhx7Hy6o0I8ApNCDvwU_gZa0diY5w,7251
|
5
|
+
PetThermoTools/Installation.py,sha256=UfVOW1NZFdzMWPyID5u7t0KwvpJA0AqYohzidXIAwYs,6098
|
6
|
+
PetThermoTools/Liq.py,sha256=2kdU8r00Y20khwvPvCvLr6P7y2HEOvCH2cwrF_qw5u8,35541
|
7
|
+
PetThermoTools/MELTS.py,sha256=hqc5vSDwvnCyBwD7wbEOwemUNpDQGpsWdOOoVjNnMvE,72810
|
8
|
+
PetThermoTools/Melting.py,sha256=h1-KchPFw5tI2xoOyNJUfVy_TJqTtcYiHtGuInIwzio,11017
|
9
|
+
PetThermoTools/Path.py,sha256=FI_JkpCDXUVWsaKxA_PKOyKvXSzsQEBiLonGNiamcIM,33424
|
10
|
+
PetThermoTools/Path_wrappers.py,sha256=_0pBs_cK2hICxAHkYxKXICUnUEBSiUg07-qhgBeuTdc,26555
|
11
|
+
PetThermoTools/PhaseDiagrams.py,sha256=8S_BcqggBzfUbiCPcsJRWFBenGL4tcCevte3-ATQjQI,30884
|
12
|
+
PetThermoTools/Plotting.py,sha256=IMYYusZy6REQATG9NI3dGlGs6h3vQ48aJHkZnHmSDDY,28924
|
13
|
+
PetThermoTools/Saturation.py,sha256=XXY6fKVouQM3RLgQgXur4xSq7_uGp7bCw_k7NNlWYi8,14095
|
14
|
+
PetThermoTools/__init__.py,sha256=PbiwQj_mNNEwuIZOLETmtMMshiXa50wjCA6mfvpOpOs,2393
|
15
|
+
PetThermoTools/_version.py,sha256=i2Na-DPnshyTFid0Y6FmelIcA0OHEcYVuQdFt_mKzeI,296
|
16
|
+
PetThermoTools-0.2.33.dist-info/LICENSE.txt,sha256=-mkx4iEw8Pk1RZUvncBhGLW87Uur5JB7FBQtOmX-VP0,1752
|
17
|
+
PetThermoTools-0.2.33.dist-info/METADATA,sha256=MM-RsleOmZq3PfygLozR2VrdewAuBMezGJLwnGc9Km8,796
|
18
|
+
PetThermoTools-0.2.33.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
19
|
+
PetThermoTools-0.2.33.dist-info/top_level.txt,sha256=IqK8iYBR3YJozzMOTRZ8x8mU2k6x8ycoMBxZTm-I06U,15
|
20
|
+
PetThermoTools-0.2.33.dist-info/RECORD,,
|
@@ -1,19 +0,0 @@
|
|
1
|
-
PetThermoTools/Barom.py,sha256=RmFT7HQ2htKrrnzLNBU1HiVN88LU82Am3cEKByxo_6o,44439
|
2
|
-
PetThermoTools/Compositions.py,sha256=65NzfduzWdfHJ8VmHBN1Cv7fMz7kF3QbDVLei-e4v00,1483
|
3
|
-
PetThermoTools/GenFuncs.py,sha256=u2GWqH--Wmqd0WXHxfulEAatQb6uswjl1s9SyyoHSa8,16412
|
4
|
-
PetThermoTools/Holland.py,sha256=udBFeVUyTBpSfLIhx7Hy6o0I8ApNCDvwU_gZa0diY5w,7251
|
5
|
-
PetThermoTools/Installation.py,sha256=UfVOW1NZFdzMWPyID5u7t0KwvpJA0AqYohzidXIAwYs,6098
|
6
|
-
PetThermoTools/Liq.py,sha256=I-vYp2i7CpQjzoo-nZ8gQNTP5jrao6pZtmkmwLtjodY,35043
|
7
|
-
PetThermoTools/MELTS.py,sha256=-nkyo3yx7dZXVnRwZhlMRGCc5SkYSm1nP3qDbLDNNyY,72354
|
8
|
-
PetThermoTools/Melting.py,sha256=iQpSXXDhwfEUTlHa80-XFK1lahb_VNrLW8ISbVCE8lY,10773
|
9
|
-
PetThermoTools/Path.py,sha256=RChQYqDayqc0hVugmX3j3uE1x2BvWIfcINFqcqwrRxw,32642
|
10
|
-
PetThermoTools/Path_wrappers.py,sha256=_0pBs_cK2hICxAHkYxKXICUnUEBSiUg07-qhgBeuTdc,26555
|
11
|
-
PetThermoTools/PhaseDiagrams.py,sha256=8S_BcqggBzfUbiCPcsJRWFBenGL4tcCevte3-ATQjQI,30884
|
12
|
-
PetThermoTools/Plotting.py,sha256=biM4QJFCH6xVDpK-nG2oAIGIFFJCzBt5Uez6XzTFiGY,28107
|
13
|
-
PetThermoTools/Saturation.py,sha256=XXY6fKVouQM3RLgQgXur4xSq7_uGp7bCw_k7NNlWYi8,14095
|
14
|
-
PetThermoTools/__init__.py,sha256=PbiwQj_mNNEwuIZOLETmtMMshiXa50wjCA6mfvpOpOs,2393
|
15
|
-
PetThermoTools/_version.py,sha256=x3oJ2coFvekDMGQwrW7LzNxduPT9SxWIZWCKamBahjQ,296
|
16
|
-
PetThermoTools-0.2.31.dist-info/METADATA,sha256=TDZlBVXnbinSw2bKIR_YvA9KJqR4w2XxlqSGVEe4klg,796
|
17
|
-
PetThermoTools-0.2.31.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
18
|
-
PetThermoTools-0.2.31.dist-info/top_level.txt,sha256=IqK8iYBR3YJozzMOTRZ8x8mU2k6x8ycoMBxZTm-I06U,15
|
19
|
-
PetThermoTools-0.2.31.dist-info/RECORD,,
|
File without changes
|
File without changes
|