PetThermoTools 0.2.32__py3-none-any.whl → 0.2.34__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 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,357 @@ from tqdm.notebook import tqdm, trange
23
24
  from scipy import interpolate
24
25
  from shapely.geometry import MultiPoint, Point, Polygon
25
26
 
26
- def find_mineral_cosaturation(cores = None, Model = None, bulk = None, phases = None, P_bar = None, Fe3Fet_Liq = None, H2O_Liq = None, H2O_Sat = False, T_initial_C = None, dt_C = None, T_maxdrop_C = None, T_cut_C = None, find_range = None, find_min = None, fO2_buffer = None, fO2_offset = None):
27
+ from functools import partial
28
+ import concurrent.futures
29
+
30
+ import numpy as np
31
+ import pandas as pd
32
+ from joblib import Parallel, delayed
33
+ import multiprocessing
34
+ import time
35
+
36
+ def path_4_saturation(q, index, *, Model = None, P_bar = None, comp = None, T_maxdrop_C = None, dt_C = None, T_initial_C = None, fO2_buffer = None,
37
+ fO2_offset = 0.0, H2O_Sat = None, phases = None):
38
+ if "MELTS" in Model:
39
+ Results = path_MELTS(P_bar = P_bar,
40
+ Model=Model,
41
+ comp=comp,
42
+ T_maxdrop_C=T_maxdrop_C,
43
+ dt_C=dt_C,
44
+ T_initial_C=T_initial_C,
45
+ find_liquidus=True,
46
+ fO2_buffer=fO2_buffer,
47
+ fO2_offset=fO2_offset,
48
+ fluid_sat=H2O_Sat,
49
+ Suppress=['rutile', 'tridymite'],
50
+ phases=phases
51
+ )
52
+ q.put([index, Results])
53
+ return
54
+
55
+ def path_4_saturation_multi(q, index, *, Model = None, P_bar = None, comp = None, T_maxdrop_C = None, dt_C = None, T_initial_C = None, fO2_buffer = None,
56
+ fO2_offset = 0.0, H2O_Sat = None, phases = None):
57
+ results = {}
58
+ idx = []
59
+
60
+ if "MELTS" in Model:
61
+ from meltsdynamic import MELTSdynamic
62
+
63
+ if Model is None or Model == "MELTSv1.0.2":
64
+ melts = MELTSdynamic(1)
65
+ elif Model == "pMELTS":
66
+ melts = MELTSdynamic(2)
67
+ elif Model == "MELTSv1.1.0":
68
+ melts = MELTSdynamic(3)
69
+ elif Model == "MELTSv1.2.0":
70
+ melts = MELTSdynamic(4)
71
+ else:
72
+ from juliacall import Main as jl, convert as jlconvert
73
+
74
+ jl.seval("using MAGEMinCalc")
75
+
76
+ comp_julia = jl.seval("Dict")(comp)
77
+
78
+ for i in index:
79
+ # try:
80
+ if "MELTS" in Model:
81
+ Results, tr = path_MELTS(P_bar = P_bar[i],
82
+ Model=Model,
83
+ comp=comp,
84
+ T_maxdrop_C=T_maxdrop_C,
85
+ dt_C=dt_C,
86
+ T_initial_C=T_initial_C,
87
+ find_liquidus=True,
88
+ fO2_buffer=fO2_buffer,
89
+ fO2_offset=fO2_offset,
90
+ fluid_sat=H2O_Sat,
91
+ Suppress=['rutile', 'tridymite'],
92
+ phases=phases,
93
+ trail = True,
94
+ melts = melts
95
+ )
96
+ else:
97
+ if fO2_offset is None:
98
+ fO2_offset = 0.0
99
+
100
+ Results_df = jl.MAGEMinCalc.path(
101
+ comp=comp_julia, dt_C=dt_C,
102
+ P_bar=P_bar[i], T_min_C = T_maxdrop_C,
103
+ Model=Model, fo2_buffer=fO2_buffer,
104
+ fo2_offset=fO2_offset, find_liquidus=True,
105
+ frac_xtal = False
106
+ )
107
+
108
+ Results = dict(Results_df)
109
+
110
+ tr = True
111
+
112
+ idx.append(i)
113
+
114
+
115
+ results[f"index = {i}"] = Results
116
+
117
+ if tr is False:
118
+ break
119
+ # except:
120
+ # idx.append(i)
121
+
122
+ q.put([idx, results])
123
+ return
124
+
125
+ def mineral_cosaturation(Model="MELTSv1.0.2", cores=int(np.floor(multiprocessing.cpu_count())), bulk=None,
126
+ phases=['quartz1', 'alkali-feldspar1', 'plagioclase1'],
127
+ P_bar=np.linspace(250, 5000, 32), Fe3Fet_init=None, H2O_init=None,
128
+ CO2_init=None, H2O_Sat=False, T_initial_C=None, dt_C=2,
129
+ T_maxdrop_C=50, T_cut_C=20, find_range=True,
130
+ find_min=True, fO2_buffer=None, fO2_offset=0.0, timeout = 30):
131
+
132
+ comp = bulk.copy()
133
+ if H2O_Sat:
134
+ comp['H2O_Liq'] = 20
135
+
136
+ comp = comp_fix(Model=Model, comp=comp, Fe3Fet_Liq=Fe3Fet_init,
137
+ H2O_Liq=H2O_init, CO2_Liq=CO2_init)
138
+
139
+ index_in = np.arange(len(P_bar))
140
+ # index_in = index
141
+ combined_results = {}
142
+ index_out = np.array([], dtype=int)
143
+
144
+ while len(index_out) < len(index_in):
145
+ index = np.setdiff1d(index_in, index_out)
146
+ groups = np.array_split(index, cores)
147
+
148
+ processes = []
149
+ for i in range(len(groups)):
150
+ q = Queue()
151
+ p = Process(target = path_4_saturation_multi, args = (q, groups[i]),
152
+ kwargs = {'Model': Model, 'comp': comp,
153
+ 'T_initial_C': T_initial_C, 'T_maxdrop_C': T_maxdrop_C,
154
+ 'dt_C': dt_C, 'P_bar': P_bar, 'phases': phases,
155
+ 'fO2_buffer': fO2_buffer, 'fO2_offset': fO2_offset})
156
+
157
+ processes.append((p, q))
158
+ p.start()
159
+
160
+ for p, q in processes:
161
+ res = q.get(timeout=timeout)
162
+ p.join(timeout = 2)
163
+ p.terminate()
164
+
165
+ idx_chunks, results = res
166
+
167
+ index_out = np.hstack((index_out, idx_chunks))
168
+ combined_results.update(results)
169
+
170
+ results = combined_results
171
+ # results = {}
172
+ # if len(P_bar) > 1:
173
+ # A = len(P_bar)//cores
174
+ # B = len(P_bar) % cores
175
+
176
+ # if A > 0:
177
+ # Group = np.zeros(A) + cores
178
+ # if B > 0:
179
+ # Group = np.append(Group, B)
180
+ # else:
181
+ # Group = np.array([B])
182
+
183
+ # # initialise queue
184
+ # qs = []
185
+ # q = Queue()
186
+
187
+
188
+ # # run calculations
189
+ # for k in range(len(Group)):
190
+ # ps = []
191
+
192
+ # for kk in range(int(cores*k), int(cores*k + Group[k])):
193
+ # p = Process(target = path_4_saturation, args = (q, kk),
194
+ # kwargs = {'Model': Model, 'comp': comp,
195
+ # 'T_initial_C': T_initial_C, 'T_maxdrop_C': T_maxdrop_C,
196
+ # 'dt_C': dt_C, 'P_bar': P_bar[kk], 'phases': phases,
197
+ # 'fO2_buffer': fO2_buffer, 'fO2_offset': fO2_offset})
198
+
199
+ # ps.append(p)
200
+ # p.start()
201
+
202
+ # start = time.time()
203
+ # for p in ps:
204
+ # if time.time() - start < timeout - 10:
205
+ # try:
206
+ # ret = q.get(timeout = timeout - (time.time()-start) + 10)
207
+ # except:
208
+ # ret = []
209
+ # else:
210
+ # try:
211
+ # ret = q.get(timeout = 10)
212
+ # except:
213
+ # ret = []
214
+
215
+ # qs.append(ret)
216
+
217
+ # TIMEOUT = 5
218
+ # start = time.time()
219
+ # for p in ps:
220
+ # if p.is_alive():
221
+ # while time.time() - start <= TIMEOUT:
222
+ # if not p.is_alive():
223
+ # p.join()
224
+ # p.terminate()
225
+ # break
226
+ # time.sleep(.1)
227
+ # else:
228
+ # p.terminate()
229
+ # p.join(5)
230
+ # else:
231
+ # p.join()
232
+ # p.terminate()
233
+
234
+ # for kk in range(len(qs)):
235
+ # if len(qs[kk]) > 0:
236
+ # index, res = qs[kk]
237
+ # results[f"P = {P_bar[index]:.2f} bars"] = res.copy()
238
+
239
+ Results = stich(Res=results, multi=True, Model=Model)
240
+
241
+ ## determine the offset between the phases
242
+ if len(phases) == 3:
243
+ arr = np.zeros((len(Results.keys()), 4))
244
+ arr2 = np.zeros((len(Results.keys()), 4))
245
+ columns = ['P_bar'] + phases + [phases[0] + ' - ' + phases[1], phases[0] + ' - ' + phases[2], phases[1] + ' - ' + phases[2], '3 Phase Saturation']
246
+ for i, r in enumerate(Results.keys()):
247
+ for idx, p in enumerate(phases):
248
+ if p in Results[r]['Mass'].keys():
249
+ arr[i, idx+1] = Results[r]['Conditions'].loc[Results[r]['Mass'][p] > 0.0, 'T_C'].values[0]
250
+ else:
251
+ arr[i, idx + 1] = np.nan
252
+
253
+ arr[i,0] = Results[r]['Conditions']['P_bar'].loc[0]
254
+
255
+ arr2[:, 0] = np.abs(arr[:,1] - arr[:,2])
256
+ arr2[:, 1] = np.abs(arr[:,1] - arr[:,3])
257
+ arr2[:, 2] = np.abs(arr[:,2] - arr[:,3])
258
+ arr2[:,3] = np.max(arr2[:,0:2], axis = 1)
259
+
260
+ r_arr = np.hstack((arr,arr2))
261
+
262
+ out = pd.DataFrame(data = r_arr, columns = columns)
263
+ out = out.sort_values('P_bar').reset_index(drop=True)
264
+
265
+ else:
266
+ arr = np.zeros((len(Results.keys()),4))
267
+ columns = ['P_bar'] + phases + [phases[0]+' - '+phases[1]]
268
+ for i, r in enumerate(Results.keys()):
269
+ for idx, p in enumerate(phases):
270
+ if p in Results[r]['Mass'].keys():
271
+ arr[i, idx+1] = Results[r]['Conditions'].loc[Results[r]['Mass'][p] > 0.0, 'T_C'].values[0]
272
+ else:
273
+ arr[i, idx + 1] = np.nan
274
+
275
+ arr[i,0] = Results[r]['Conditions']['P_bar'].loc[0]
276
+
277
+ arr[:,3] = np.abs(arr[:,1] - arr[:,2])
278
+
279
+ out = pd.DataFrame(data = arr, columns = columns)
280
+ out = out.sort_values('P_bar').reset_index(drop=True)
281
+
282
+ if find_min:
283
+ res = findmin(out = out, P_bar = P_bar, T_cut_C = T_cut_C)
284
+ out = {'CurveMin': res, 'Output': out}
285
+ else:
286
+ out = {'Output': out}
287
+
288
+ return out, Results
289
+
290
+ def findmin(out = None, P_bar = None, T_cut_C = None):
291
+ Res = out.copy()
292
+
293
+ if '3 Phase Saturation' in list(Res.keys()):
294
+ T_cut_old = T_cut_C
295
+ T_cut_C = T_cut_C + np.nanmin(Res[4:])
296
+ Minimum = list(Res.keys())[4:]
297
+ CurveMin = {}
298
+ for m in Minimum:
299
+ if len(Res[m][~np.isnan(Res[m].values)]) > 2:
300
+ y = Res[m][(~np.isnan(Res[m].values)) & (Res[m].values < T_cut_C)].values
301
+ x = P_bar[(~np.isnan(Res[m].values)) & (Res[m].values < T_cut_C)]
302
+
303
+ try:
304
+ y_new = interpolate.UnivariateSpline(x, y, k = 3)
305
+
306
+ P_new = np.linspace(P_bar[P_bar == np.nanmin(P_bar[(~np.isnan(Res[m].values)) & (Res[m].values < T_cut_C)])],
307
+ P_bar[P_bar == np.nanmax(P_bar[(~np.isnan(Res[m].values)) & (Res[m].values < T_cut_C)])], 200)
308
+
309
+ NewMin = np.nanmin(y_new(P_new))
310
+ P_min = P_new[np.where(y_new(P_new) == NewMin)][0]
311
+ if NewMin < T_cut_old:
312
+ Test = 'Pass'
313
+ else:
314
+ Test = 'Fail'
315
+
316
+ CurveMin[m] = {'P_min': P_min, 'Res_min': NewMin, 'y_new': y_new(P_new), 'P_new': P_new, 'test': Test}
317
+ except:
318
+ try:
319
+ y_new = interpolate.UnivariateSpline(x, y, k = 2)
320
+
321
+ P_new = np.linspace(P_bar[P_bar == np.nanmin(P_bar[(~np.isnan(Res[m].values)) & (Res[m].values < T_cut_C)])],
322
+ P_bar[P_bar == np.nanmax(P_bar[(~np.isnan(Res[m].values)) & (Res[m].values < T_cut_C)])], 200)
323
+
324
+ NewMin = np.nanmin(y_new(P_new))
325
+ P_min = P_new[np.where(y_new(P_new) == NewMin)][0]
326
+ if NewMin < T_cut_old:
327
+ Test = 'Pass'
328
+ else:
329
+ Test = 'Fail'
330
+
331
+ CurveMin[m] = {'P_min': P_min, 'Res_min': NewMin, 'y_new': y_new(P_new), 'P_new': P_new, 'test': Test}
332
+ except:
333
+ CurveMin[m] = {'P_min': np.nan, 'Res_min': np.nan, 'y_new': np.nan, 'P_new': np.nan, 'test': 'Fail'}
334
+ else:
335
+ y_new = np.nan
336
+ P_new = np.nan
337
+ NewMin = np.nan
338
+ P_min = np.nan
339
+ Test = 'Fail'
340
+ CurveMin[m] = {'P_min': P_min, 'Res_min': NewMin, 'y_new': y_new, 'P_new': P_new, 'test': Test}
341
+
342
+ else:
343
+ CurveMin = {}
344
+ m = Res.keys()[3]
345
+ if len(Res[m][~np.isnan(Res[m])]) > 2:
346
+ y = Res[m][(~np.isnan(Res[m].values)) & (Res[m].values < T_cut_C*2)].values
347
+ x = P_bar[(~np.isnan(Res[m].values)) & (Res[m].values < T_cut_C*2)]
348
+
349
+ try:
350
+ y_new = interpolate.UnivariateSpline(x, y, k = 3)
351
+ except:
352
+ y_new = interpolate.UnivariateSpline(x, y, k = 2)
353
+
354
+ P_new = np.linspace(P_bar[P_bar == np.nanmin(P_bar[(~np.isnan(Res[m])) & (Res[m] < T_cut_C*2)])],
355
+ P_bar[P_bar == np.nanmax(P_bar[(~np.isnan(Res[m])) & (Res[m] < T_cut_C*2)])], 200)
356
+
357
+ NewMin = np.nanmin(y_new(P_new))
358
+ P_min = P_new[np.where(y_new(P_new) == NewMin)][0]
359
+ if NewMin < T_cut_C:
360
+ Test = 'Pass'
361
+ else:
362
+ Test = 'Fail'
363
+ else:
364
+ y_new = np.nan
365
+ P_new = np.nan
366
+ NewMin = np.nan
367
+ P_min = np.nan
368
+ Test = 'Fail'
369
+
370
+ CurveMin[m] = {'P_min': P_min, 'Res_min': NewMin, 'y_new': y_new, 'P_new': P_new, 'test': Test}
371
+
372
+ return CurveMin
373
+
374
+
375
+ def find_mineral_cosaturation(cores = None, Model = None, bulk = None, phases = None, P_bar = None, Fe3Fet_Liq = None,
376
+ H2O_Liq = None, H2O_Sat = False, T_initial_C = None, dt_C = None, T_maxdrop_C = None,
377
+ T_cut_C = None, find_range = None, find_min = None, fO2_buffer = None, fO2_offset = None):
27
378
  '''
28
379
  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
380
 
@@ -621,406 +972,3 @@ def satTemperature(q, index, *, Model = None, comp = None, phases = None, T_init
621
972
  return
622
973
 
623
974
 
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/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, fO2_buffer = None, fO2_offset = None, Step = None, fluid_test = None, bulk_return = None, step = None, Affinity = False):
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, trail = None, melts = 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
 
@@ -882,6 +884,8 @@ def path_MELTS(Model = None, comp = None, Frac_solid = None, Frac_fluid = None,
882
884
 
883
885
  '''
884
886
  Results = {}
887
+ if trail is not None:
888
+ trail = False
885
889
 
886
890
  if comp is None:
887
891
  raise Exception("No composition specified")
@@ -896,16 +900,17 @@ def path_MELTS(Model = None, comp = None, Frac_solid = None, Frac_fluid = None,
896
900
  if T_path_C is None and T_start_C is None and find_liquidus is None:
897
901
  raise Exception("Starting temperature must be specified or the liquidus must be found")
898
902
 
899
- from meltsdynamic import MELTSdynamic
903
+ if melts is None:
904
+ from meltsdynamic import MELTSdynamic
900
905
 
901
- if Model is None or Model == "MELTSv1.0.2":
902
- melts = MELTSdynamic(1)
903
- elif Model == "pMELTS":
904
- melts = MELTSdynamic(2)
905
- elif Model == "MELTSv1.1.0":
906
- melts = MELTSdynamic(3)
907
- elif Model == "MELTSv1.2.0":
908
- melts = MELTSdynamic(4)
906
+ if Model is None or Model == "MELTSv1.0.2":
907
+ melts = MELTSdynamic(1)
908
+ elif Model == "pMELTS":
909
+ melts = MELTSdynamic(2)
910
+ elif Model == "MELTSv1.1.0":
911
+ melts = MELTSdynamic(3)
912
+ elif Model == "MELTSv1.2.0":
913
+ melts = MELTSdynamic(4)
909
914
 
910
915
  bulk = [comp['SiO2_Liq'], comp['TiO2_Liq'], comp['Al2O3_Liq'], comp['Fe3Fet_Liq']*((159.59/2)/71.844)*comp['FeOt_Liq'], comp['Cr2O3_Liq'], (1- comp['Fe3Fet_Liq'])*comp['FeOt_Liq'], comp['MnO_Liq'], comp['MgO_Liq'], 0.0, 0.0, comp['CaO_Liq'], comp['Na2O_Liq'], comp['K2O_Liq'], comp['P2O5_Liq'], comp['H2O_Liq'], comp['CO2_Liq'], 0.0, 0.0, 0.0]
911
916
  bulk = list(100*np.array(bulk)/np.sum(bulk))
@@ -946,18 +951,27 @@ def path_MELTS(Model = None, comp = None, Frac_solid = None, Frac_fluid = None,
946
951
  if P_path_bar is not None:
947
952
  try:
948
953
  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 = 1400)
954
+ 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
955
  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 = 1400)
956
+ 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
957
  except:
953
- return Results
958
+ if trail is not None:
959
+ return Results, trail
960
+ else:
961
+ return Results
954
962
  elif P_start_bar is not None:
955
963
  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 = 1400)
964
+ 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
965
  except:
958
- return Results
966
+ if trail is not None:
967
+ return Results, trail
968
+ else:
969
+ return Results
959
970
 
971
+ print(Liq_Results)
960
972
  T_start_C = Liq_Results['T_Liq'] + 0.1
973
+ if T_end_C is None and T_maxdrop_C is not None:
974
+ T_end_C = T_start_C - T_maxdrop_C
961
975
 
962
976
  else:
963
977
  if fO2_buffer is not None:
@@ -1034,6 +1048,10 @@ def path_MELTS(Model = None, comp = None, Frac_solid = None, Frac_fluid = None,
1034
1048
  Results['liquid1_prop'] = pd.DataFrame(data = np.zeros((length, 4)), columns = ['h', 'mass', 'v', 'rho'])
1035
1049
 
1036
1050
  for i in range(length):
1051
+ if i == 1:
1052
+ if trail is not None:
1053
+ trail = True
1054
+
1037
1055
  if type(T) == np.ndarray:
1038
1056
  melts.engine.temperature = T[i]
1039
1057
  if type(P) == np.ndarray:
@@ -1082,7 +1100,11 @@ def path_MELTS(Model = None, comp = None, Frac_solid = None, Frac_fluid = None,
1082
1100
  else:
1083
1101
  melts.engine.calcEquilibriumState(1,0)
1084
1102
  except:
1085
- return Results
1103
+ trail = False
1104
+ # if trail is not None:
1105
+ # return Results, trail
1106
+ # else:
1107
+ # return Results
1086
1108
  break
1087
1109
 
1088
1110
  if isenthalpic is not None:
@@ -1092,7 +1114,11 @@ def path_MELTS(Model = None, comp = None, Frac_solid = None, Frac_fluid = None,
1092
1114
  else:
1093
1115
  melts.engine.calcEquilibriumState(2,0)
1094
1116
  except:
1095
- # return Results
1117
+ trail = False
1118
+ # if trail is not None:
1119
+ # return Results, trail
1120
+ # else:
1121
+ # return Results
1096
1122
  break
1097
1123
 
1098
1124
  if isentropic is not None:
@@ -1102,6 +1128,7 @@ def path_MELTS(Model = None, comp = None, Frac_solid = None, Frac_fluid = None,
1102
1128
  else:
1103
1129
  melts.engine.calcEquilibriumState(3,0)
1104
1130
  except:
1131
+ trail = False
1105
1132
  # return Results
1106
1133
  break
1107
1134
 
@@ -1109,6 +1136,7 @@ def path_MELTS(Model = None, comp = None, Frac_solid = None, Frac_fluid = None,
1109
1136
  try:
1110
1137
  melts.engine.calcEquilibriumState(4,0)
1111
1138
  except:
1139
+ trail = False
1112
1140
  # return Results
1113
1141
  break
1114
1142
 
@@ -1128,7 +1156,8 @@ def path_MELTS(Model = None, comp = None, Frac_solid = None, Frac_fluid = None,
1128
1156
  try:
1129
1157
  PhaseList = ['liquid1'] + melts.engine.solidNames
1130
1158
  except:
1131
- return Results
1159
+ trail = False
1160
+ # return Results
1132
1161
  break
1133
1162
 
1134
1163
  for phase in PhaseList:
@@ -1155,9 +1184,22 @@ def path_MELTS(Model = None, comp = None, Frac_solid = None, Frac_fluid = None,
1155
1184
  if Volume/Total_volume > Crystallinity_limit:
1156
1185
  break
1157
1186
 
1187
+ if phases is not None:
1188
+ ll = 0
1189
+ for p in phases:
1190
+ if p in Results.keys():
1191
+ ll = ll + 1
1192
+
1193
+ if ll == len(phases):
1194
+ break
1195
+
1158
1196
  melts = melts.addNodeAfter()
1159
1197
 
1160
- return Results
1198
+
1199
+ if trail is not None:
1200
+ return Results, trail
1201
+ else:
1202
+ return Results
1161
1203
 
1162
1204
  def findSatPressure_MELTS_multi(Model = None, comp = None, fO2_buffer = None, fO2_offset = None, P_bar = None, T_fixed_C = None):
1163
1205
  out = pd.DataFrame(columns = ['Sample_ID_Liq', 'SiO2_Liq', 'TiO2_Liq', 'Al2O3_Liq', 'Cr2O3_Liq', 'FeOt_Liq', 'MnO_Liq', 'MgO_Liq', 'CaO_Liq', 'Na2O_Liq', 'K2O_Liq', 'P2O5_Liq', 'H2O_Liq', 'CO2_Liq', 'Fe3Fet_Liq', 'P_bar', 'T_Liq'])
@@ -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
- if i == 0:
135
- a.plot(P_bar, Results[phases[0]][0,0,:], '-r', linewidth = 2, label = phases[i])
136
- if i == 1:
137
- a.plot(P_bar, Results[phases[1]][0,0,:], '-b', linewidth = 2, label = phases[i])
138
- if i == 2:
139
- a.plot(P_bar, Results[phases[2]][0,0,:], '-k', linewidth = 2, label = phases[i])
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
- a[i][j].plot(P_bar, Results[m[i,j]][0,0,:], 'ok', markerfacecolor="b", label="original", markersize = 8)
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'],
@@ -5,4 +5,4 @@
5
5
  # 1) we don't load dependencies by storing it in __init__.py
6
6
  # 2) we can import it in setup.py for the same reason
7
7
  # 3) we can import it into your module
8
- __version__ = '0.2.32'
8
+ __version__ = '0.2.34'
@@ -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
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PetThermoTools
3
- Version: 0.2.32
3
+ Version: 0.2.34
4
4
  Summary: PetThermoTools
5
5
  Home-page: https://github.com/gleesonm1/PetThermoTools
6
6
  Author: Matthew Gleeson
@@ -1,19 +1,20 @@
1
- PetThermoTools/Barom.py,sha256=RmFT7HQ2htKrrnzLNBU1HiVN88LU82Am3cEKByxo_6o,44439
1
+ PetThermoTools/Barom.py,sha256=chxLZCCu0I8PLw0-TWsJboxiRqQJufKyVEVLk35dzVo,40494
2
2
  PetThermoTools/Compositions.py,sha256=65NzfduzWdfHJ8VmHBN1Cv7fMz7kF3QbDVLei-e4v00,1483
3
3
  PetThermoTools/GenFuncs.py,sha256=u2GWqH--Wmqd0WXHxfulEAatQb6uswjl1s9SyyoHSa8,16412
4
4
  PetThermoTools/Holland.py,sha256=udBFeVUyTBpSfLIhx7Hy6o0I8ApNCDvwU_gZa0diY5w,7251
5
5
  PetThermoTools/Installation.py,sha256=UfVOW1NZFdzMWPyID5u7t0KwvpJA0AqYohzidXIAwYs,6098
6
6
  PetThermoTools/Liq.py,sha256=2kdU8r00Y20khwvPvCvLr6P7y2HEOvCH2cwrF_qw5u8,35541
7
- PetThermoTools/MELTS.py,sha256=-nkyo3yx7dZXVnRwZhlMRGCc5SkYSm1nP3qDbLDNNyY,72354
7
+ PetThermoTools/MELTS.py,sha256=CjUOJSUEoq4yXEojl77HgCj7aewhFDeSGt4ZGk3L3vs,73688
8
8
  PetThermoTools/Melting.py,sha256=h1-KchPFw5tI2xoOyNJUfVy_TJqTtcYiHtGuInIwzio,11017
9
9
  PetThermoTools/Path.py,sha256=FI_JkpCDXUVWsaKxA_PKOyKvXSzsQEBiLonGNiamcIM,33424
10
10
  PetThermoTools/Path_wrappers.py,sha256=_0pBs_cK2hICxAHkYxKXICUnUEBSiUg07-qhgBeuTdc,26555
11
11
  PetThermoTools/PhaseDiagrams.py,sha256=8S_BcqggBzfUbiCPcsJRWFBenGL4tcCevte3-ATQjQI,30884
12
- PetThermoTools/Plotting.py,sha256=biM4QJFCH6xVDpK-nG2oAIGIFFJCzBt5Uez6XzTFiGY,28107
12
+ PetThermoTools/Plotting.py,sha256=IMYYusZy6REQATG9NI3dGlGs6h3vQ48aJHkZnHmSDDY,28924
13
13
  PetThermoTools/Saturation.py,sha256=XXY6fKVouQM3RLgQgXur4xSq7_uGp7bCw_k7NNlWYi8,14095
14
14
  PetThermoTools/__init__.py,sha256=PbiwQj_mNNEwuIZOLETmtMMshiXa50wjCA6mfvpOpOs,2393
15
- PetThermoTools/_version.py,sha256=Dx2nyXCP2anL0ePIK0yaL-9dVQUNLwN_Y5sjqdoNjU0,296
16
- PetThermoTools-0.2.32.dist-info/METADATA,sha256=bzOGZMsHROBRHP9DrgSejdN3d8YyMbaYSX9Pt9yn5Ho,796
17
- PetThermoTools-0.2.32.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
18
- PetThermoTools-0.2.32.dist-info/top_level.txt,sha256=IqK8iYBR3YJozzMOTRZ8x8mU2k6x8ycoMBxZTm-I06U,15
19
- PetThermoTools-0.2.32.dist-info/RECORD,,
15
+ PetThermoTools/_version.py,sha256=ZyVKd7JEm_88aeNoezRSEHfFgAtOuHaYQWt8wmb4mgc,296
16
+ PetThermoTools-0.2.34.dist-info/LICENSE.txt,sha256=-mkx4iEw8Pk1RZUvncBhGLW87Uur5JB7FBQtOmX-VP0,1752
17
+ PetThermoTools-0.2.34.dist-info/METADATA,sha256=okQdLGfhCpo2f211FXt6szwCr2KrRHpqxAVKSl6kPec,796
18
+ PetThermoTools-0.2.34.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
19
+ PetThermoTools-0.2.34.dist-info/top_level.txt,sha256=IqK8iYBR3YJozzMOTRZ8x8mU2k6x8ycoMBxZTm-I06U,15
20
+ PetThermoTools-0.2.34.dist-info/RECORD,,