PetThermoTools 0.2.39__py3-none-any.whl → 0.2.41__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 +701 -575
- PetThermoTools/GenFuncs.py +18 -2
- PetThermoTools/Liq.py +0 -8
- PetThermoTools/MELTS.py +85 -57
- PetThermoTools/Melting.py +12 -1
- PetThermoTools/Path.py +239 -139
- PetThermoTools/Path_wrappers.py +448 -259
- PetThermoTools/PhaseDiagrams.py +50 -98
- PetThermoTools/Saturation.py +353 -2
- PetThermoTools/_version.py +1 -1
- {PetThermoTools-0.2.39.dist-info → PetThermoTools-0.2.41.dist-info}/METADATA +2 -2
- PetThermoTools-0.2.41.dist-info/RECORD +20 -0
- PetThermoTools-0.2.39.dist-info/RECORD +0 -20
- {PetThermoTools-0.2.39.dist-info → PetThermoTools-0.2.41.dist-info}/LICENSE.txt +0 -0
- {PetThermoTools-0.2.39.dist-info → PetThermoTools-0.2.41.dist-info}/WHEEL +0 -0
- {PetThermoTools-0.2.39.dist-info → PetThermoTools-0.2.41.dist-info}/top_level.txt +0 -0
PetThermoTools/PhaseDiagrams.py
CHANGED
@@ -11,7 +11,12 @@ from tqdm.notebook import tqdm, trange
|
|
11
11
|
import random
|
12
12
|
import time
|
13
13
|
|
14
|
-
def phaseDiagram_calc(cores = None, Model = None, bulk = None, T_C = None, P_bar = None,
|
14
|
+
def phaseDiagram_calc(cores = None, Model = None, bulk = None, T_C = None, P_bar = None,
|
15
|
+
T_min_C = None, T_max_C = None, T_num = None,
|
16
|
+
P_min_bar = None, P_max_bar = None, P_num = None,
|
17
|
+
Fe3Fet_Liq = None, H2O_Liq = None, CO2_Liq = None,
|
18
|
+
Fe3Fet_init = None, H2O_init = None, CO2_init = None,
|
19
|
+
fO2_buffer = None, fO2_offset = None, i_max = 25, grid = True, refine = None):
|
15
20
|
"""
|
16
21
|
Calculate phase diagrams for igneous systems (rocks and magmas).
|
17
22
|
|
@@ -62,6 +67,40 @@ def phaseDiagram_calc(cores = None, Model = None, bulk = None, T_C = None, P_bar
|
|
62
67
|
A dataframe containing the phase diagram results.
|
63
68
|
"""
|
64
69
|
|
70
|
+
## make sure everything is a float
|
71
|
+
T_C = to_float(T_C)
|
72
|
+
T_min_C = to_float(T_min_C)
|
73
|
+
T_max_C = to_float(T_max_C)
|
74
|
+
T_num = to_float(T_num)
|
75
|
+
|
76
|
+
P_bar = to_float(P_bar)
|
77
|
+
P_min_bar = to_float(P_min_bar)
|
78
|
+
P_max_bar= to_float(P_max_bar)
|
79
|
+
P_num = to_float(P_num)
|
80
|
+
|
81
|
+
Fe3Fet_init= to_float(Fe3Fet_init)
|
82
|
+
Fe3Fet_Liq = to_float(Fe3Fet_Liq)
|
83
|
+
H2O_init = to_float(H2O_init)
|
84
|
+
H2O_Liq = to_float(H2O_Liq)
|
85
|
+
CO2_init = to_float(CO2_init)
|
86
|
+
CO2_Liq = to_float(CO2_Liq)
|
87
|
+
fO2_offset = to_float(fO2_offset)
|
88
|
+
|
89
|
+
if H2O_Liq is not None:
|
90
|
+
print('Warning - the kwarg "H2O_Liq" will be removed from v1.0.0 onwards. Please use "H2O_init" instead.')
|
91
|
+
if H2O_init is None:
|
92
|
+
H2O_init = H2O_Liq
|
93
|
+
|
94
|
+
if CO2_Liq is not None:
|
95
|
+
print('Warning - the kwarg "CO2_Liq" will be removed from v1.0.0 onwards. Please use "CO2_init" instead.')
|
96
|
+
if CO2_init is None:
|
97
|
+
CO2_init = CO2_Liq
|
98
|
+
|
99
|
+
if Fe3Fet_Liq is not None:
|
100
|
+
print('Warning - the kwarg "Fe3Fet_Liq" will be removed from v1.0.0 onwards. Please use "Fe3Fet_init" instead.')
|
101
|
+
if Fe3Fet_init is None:
|
102
|
+
Fe3Fet_init = Fe3Fet_Liq
|
103
|
+
|
65
104
|
comp = bulk.copy()
|
66
105
|
|
67
106
|
if cores is None:
|
@@ -80,7 +119,7 @@ def phaseDiagram_calc(cores = None, Model = None, bulk = None, T_C = None, P_bar
|
|
80
119
|
comp = comp.to_dict()
|
81
120
|
|
82
121
|
# ensure the bulk composition has the correct headers etc.
|
83
|
-
comp = comp_fix(Model = Model, comp = comp, Fe3Fet_Liq =
|
122
|
+
comp = comp_fix(Model = Model, comp = comp, Fe3Fet_Liq = Fe3Fet_init, H2O_Liq = H2O_init, CO2_Liq=CO2_init)
|
84
123
|
|
85
124
|
if type(comp) == dict:
|
86
125
|
if comp['Fe3Fet_Liq'] == 0.0 and "MELTS" in Model and fO2_buffer is None:
|
@@ -110,20 +149,6 @@ def phaseDiagram_calc(cores = None, Model = None, bulk = None, T_C = None, P_bar
|
|
110
149
|
c = 0
|
111
150
|
j = 0
|
112
151
|
|
113
|
-
|
114
|
-
# subarray_length = len(T_flat) // cores
|
115
|
-
|
116
|
-
# # Initialize an empty list to store subarrays
|
117
|
-
# subarrays_T = []
|
118
|
-
|
119
|
-
# Loop through the indices and create subarrays
|
120
|
-
# for i in range(subarray_length):
|
121
|
-
# subarray_T = T_flat[i::subarray_length]
|
122
|
-
# subarrays_T.append(subarray_T)
|
123
|
-
|
124
|
-
# subarray_P = T_flat[i::subarray_length]
|
125
|
-
# subarrays_P.append(subarray_P)
|
126
|
-
|
127
152
|
while len(T_flat)>1:
|
128
153
|
if j > i_max:
|
129
154
|
break
|
@@ -175,22 +200,6 @@ def phaseDiagram_calc(cores = None, Model = None, bulk = None, T_C = None, P_bar
|
|
175
200
|
T_path_C = np.flip(T_path_C)
|
176
201
|
P_path_bar = np.flip(P_path_bar)
|
177
202
|
|
178
|
-
# if "MELTS" not in Model:
|
179
|
-
# T_path_C = T_path_C.tolist()
|
180
|
-
# P_path_bar = P_path_bar.tolist()
|
181
|
-
|
182
|
-
# if j > 5:
|
183
|
-
# com = list(zip(T, P))
|
184
|
-
|
185
|
-
# # Step 2: Randomize the order of the combined list
|
186
|
-
# random.shuffle(com)
|
187
|
-
|
188
|
-
# # Step 3: Separate the pairs back into two arrays
|
189
|
-
# T_randomized, P_randomized = zip(*com)
|
190
|
-
|
191
|
-
# T_path_C = np.array(T_randomized)
|
192
|
-
# P_path_bar = np.array(P_randomized)
|
193
|
-
|
194
203
|
p = Process(target = path, args = (q,i), kwargs = {'Model': Model, 'comp': comp,
|
195
204
|
'T_path_C': T_path_C,
|
196
205
|
'P_path_bar': P_path_bar,
|
@@ -242,66 +251,6 @@ def phaseDiagram_calc(cores = None, Model = None, bulk = None, T_C = None, P_bar
|
|
242
251
|
p.join()
|
243
252
|
p.terminate()
|
244
253
|
|
245
|
-
# TIMEOUT = 150 #+ #0.5*len(T_flat)
|
246
|
-
# start = time.time()
|
247
|
-
# for p in ps:
|
248
|
-
# ret = []
|
249
|
-
# if time.time() - start <= TIMEOUT:
|
250
|
-
# while time.time() - start <= TIMEOUT:
|
251
|
-
# try:
|
252
|
-
# ret = q.get(timeout = 2)
|
253
|
-
# break
|
254
|
-
# except:
|
255
|
-
# continue
|
256
|
-
#
|
257
|
-
# # if p.is_alive():
|
258
|
-
# # time.sleep(.1)
|
259
|
-
# # else:
|
260
|
-
# # p.terminate()
|
261
|
-
# # p.join()
|
262
|
-
# # break
|
263
|
-
#
|
264
|
-
# # if p.is_alive():
|
265
|
-
# else:
|
266
|
-
# try:
|
267
|
-
# ret = q.get(timeout = 5)
|
268
|
-
# except:
|
269
|
-
# ret =[]
|
270
|
-
#
|
271
|
-
# p.terminate()
|
272
|
-
# p.join()
|
273
|
-
|
274
|
-
# else:
|
275
|
-
# p.terminate()
|
276
|
-
# p.join()
|
277
|
-
|
278
|
-
# try:
|
279
|
-
# ret = q.get(timeout = 5)
|
280
|
-
# except:
|
281
|
-
# ret = []
|
282
|
-
|
283
|
-
# qs.append(ret)
|
284
|
-
# if p.is_alive():
|
285
|
-
# while time.time() - start <= TIMEOUT:
|
286
|
-
# if not p.is_alive():
|
287
|
-
# p.terminate()
|
288
|
-
# p.join()
|
289
|
-
# break
|
290
|
-
# time.sleep(.1)
|
291
|
-
# else:
|
292
|
-
# p.terminate()
|
293
|
-
# p.join()
|
294
|
-
# else:
|
295
|
-
# p.terminate()
|
296
|
-
# p.join()
|
297
|
-
#
|
298
|
-
# try:
|
299
|
-
# ret = q.get(timeout = 2)
|
300
|
-
# except:
|
301
|
-
# ret = []
|
302
|
-
|
303
|
-
# qs.append(ret)
|
304
|
-
|
305
254
|
for p in ps:
|
306
255
|
p.kill()
|
307
256
|
|
@@ -347,9 +296,6 @@ def phaseDiagram_calc(cores = None, Model = None, bulk = None, T_C = None, P_bar
|
|
347
296
|
new_flat = flat[np.where((flat[:, None] == Res_flat).all(-1).any(-1) == False)]
|
348
297
|
|
349
298
|
if np.shape(new_flat)[0] > 0.0:
|
350
|
-
# df = pd.DataFrame(columns = ['T_C', 'P_bar'])
|
351
|
-
# for i in range(len(new_flat)):
|
352
|
-
# df.loc[i] = new_flat[i]
|
353
299
|
A = np.zeros((np.shape(new_flat)[0], np.shape(Combined.values)[1]))
|
354
300
|
A[:,:2] = new_flat
|
355
301
|
|
@@ -358,7 +304,6 @@ def phaseDiagram_calc(cores = None, Model = None, bulk = None, T_C = None, P_bar
|
|
358
304
|
C = np.concatenate((A, B))
|
359
305
|
|
360
306
|
Combined = pd.DataFrame(columns = list(Combined.keys()), data = C)
|
361
|
-
# Combined = pd.concat([Combined, df], axis = 0, ignore_index = True)
|
362
307
|
|
363
308
|
Combined['T_C'] = np.round(Combined['T_C'], 2)
|
364
309
|
Combined['P_bar'] = np.round(Combined['P_bar'], 2)
|
@@ -366,9 +311,15 @@ def phaseDiagram_calc(cores = None, Model = None, bulk = None, T_C = None, P_bar
|
|
366
311
|
Combined = Combined.reset_index(drop = True)
|
367
312
|
Combined = Combined.dropna(subset = ['T_C'])
|
368
313
|
|
314
|
+
if refine is not None:
|
315
|
+
for i in range(refine):
|
316
|
+
Combined = phaseDiagram_refine(Data = Combined, Model = Model, bulk = bulk, Fe3Fet_Liq=Fe3Fet_init,
|
317
|
+
H2O_Liq=H2O_init, CO2_Liq=CO2_init, fO2_buffer=fO2_buffer, fO2_offset=fO2_offset, i_max = i_max)
|
318
|
+
|
369
319
|
return Combined
|
370
320
|
|
371
|
-
def phaseDiagram_refine(Data = None, Model = None, bulk = None, Fe3Fet_Liq = None, H2O_Liq = None,
|
321
|
+
def phaseDiagram_refine(Data = None, Model = None, bulk = None, Fe3Fet_Liq = None, H2O_Liq = None, CO2_Liq = None,
|
322
|
+
fO2_buffer = None, fO2_offset = None, i_max = 150):
|
372
323
|
Combined = Data.copy()
|
373
324
|
# find existing T,P data
|
374
325
|
T_C = Combined['T_C'].unique()
|
@@ -508,7 +459,8 @@ def phaseDiagram_refine(Data = None, Model = None, bulk = None, Fe3Fet_Liq = Non
|
|
508
459
|
matching_df = matching_df.loc[np.where(matching_df['h'] != 0.0)[0],:]
|
509
460
|
matching_df = matching_df.reset_index(drop = True)
|
510
461
|
|
511
|
-
New = phaseDiagram_calc(cores =
|
462
|
+
New = phaseDiagram_calc(cores = multiprocessing.cpu_count(),
|
463
|
+
Model = Model, bulk = bulk, T_C = T_C, P_bar = P_bar, Fe3Fet_init = Fe3Fet_Liq, H2O_init = H2O_Liq, CO2_init = CO2_Liq, fO2_buffer = fO2_buffer, fO2_offset = fO2_offset, i_max = i_max, grid = False)
|
512
464
|
|
513
465
|
# A = New.values
|
514
466
|
# B = matching_df.values
|
PetThermoTools/Saturation.py
CHANGED
@@ -303,7 +303,357 @@ def findSatPressure(cores = None, Model = None, bulk = None, T_C_init = None, T_
|
|
303
303
|
return Res
|
304
304
|
|
305
305
|
|
306
|
-
def
|
306
|
+
def saturation_pressure(Model = "MELTSv1.2.0", cores = multiprocessing.cpu_count(),
|
307
|
+
bulk = None, T_C_init = None, T_fixed_C = None, P_bar_init = 5000,
|
308
|
+
Fe3Fet_Liq = None, Fe3Fet_init = None, H2O_Liq = None, H2O_init = None,
|
309
|
+
CO2_Liq = None, CO2_init = None, fO2_buffer = None, fO2_offset = None,
|
310
|
+
copy_columns = None, multi_processing = True, timeout = 180):
|
311
|
+
"""
|
312
|
+
Estimates the pressure at which volatile saturation occurs for one or more melt compositions
|
313
|
+
using MELTS thermodynamic models.
|
314
|
+
|
315
|
+
Supports both single and batched calculations, with optional multiprocessing to accelerate large-scale runs.
|
316
|
+
|
317
|
+
Parameters
|
318
|
+
----------
|
319
|
+
Model : str, default 'MELTSv1.2.0'
|
320
|
+
The thermodynamic model to use.
|
321
|
+
MELTS:
|
322
|
+
"MELTSv1.2.0"
|
323
|
+
"MELTSv1.1.0"
|
324
|
+
"MELTSv1.0.2" - only H2O
|
325
|
+
"pMELTS" - only H2O
|
326
|
+
cores : int, default multiprocessing.cpu_count()
|
327
|
+
Number of parallel processes to use.
|
328
|
+
bulk : dict, pandas.Series, or pandas.DataFrame
|
329
|
+
Bulk melt composition(s). If a Series or single dict is passed, a single calculation is run.
|
330
|
+
If a DataFrame is passed, a calculation is performed for each row.
|
331
|
+
T_C_init : float or np.ndarray, optional
|
332
|
+
Initial temperature(s) in degrees Celsius. System will co-solve the liquidus temperature and pressure of volatile saturation. Used if not specifying `T_fixed_C`.
|
333
|
+
T_fixed_C : float or np.ndarray, optional
|
334
|
+
Fixed temperature(s) for the saturation pressure calculation. Solid phases are disabled in all calculations.
|
335
|
+
P_bar_init : float or np.ndarray, default 5000
|
336
|
+
Initial pressure guess(es) in bars.
|
337
|
+
Fe3Fet_Liq : float or np.ndarray, optional [DEPRECATED]
|
338
|
+
Legacy alias for initial Fe³⁺/∑Fe ratio. Prefer `Fe3Fet_init`.
|
339
|
+
Fe3Fet_init : float or np.ndarray, optional
|
340
|
+
Initial Fe³⁺/∑Fe ratio(s) in the liquid.
|
341
|
+
H2O_Liq : float or np.ndarray, optional [DEPRECATED]
|
342
|
+
Legacy alias for initial H₂O content. Prefer `H2O_init`.
|
343
|
+
H2O_init : float or np.ndarray, optional
|
344
|
+
Initial H₂O content(s) in the liquid, in wt%.
|
345
|
+
CO2_Liq : float or np.ndarray, optional [DEPRECATED]
|
346
|
+
Legacy alias for initial CO₂ content. Prefer `CO2_init`.
|
347
|
+
CO2_init : float or np.ndarray, optional
|
348
|
+
Initial CO₂ content(s) in the liquid, in wt%.
|
349
|
+
fO2_buffer : str, optional
|
350
|
+
Oxygen fugacity buffer to use ('FMQ' or 'NNO').
|
351
|
+
fO2_offset : float or np.ndarray, optional
|
352
|
+
Offset from the fO₂ buffer in log units (e.g., +1.0 = 1 log unit above buffer).
|
353
|
+
copy_columns : str or list of str, optional
|
354
|
+
If bulk is a DataFrame, copies specified columns from input into output DataFrame for tracking.
|
355
|
+
multi_processing : bool, default True
|
356
|
+
Whether to parallelize the calculations across multiple cores.
|
357
|
+
timeout : int, default 180
|
358
|
+
Timeout for individual parallel processes, in seconds.
|
359
|
+
|
360
|
+
Returns
|
361
|
+
-------
|
362
|
+
pandas.DataFrame or dict
|
363
|
+
- If multiple calculations are performed, returns a DataFrame with saturation pressures and
|
364
|
+
other outputs, indexed by run number.
|
365
|
+
- If a single calculation is run (`multi_processing=False` or `bulk` is a single composition),
|
366
|
+
returns a dictionary of calculated results.
|
367
|
+
|
368
|
+
Raises
|
369
|
+
------
|
370
|
+
Warning
|
371
|
+
- If required MELTS packages are not found in the Python path.
|
372
|
+
- If unsupported fO₂ buffers are specified.
|
373
|
+
- If zero Fe³⁺/∑Fe or H₂O is specified in MELTS without buffer constraints.
|
374
|
+
|
375
|
+
Notes
|
376
|
+
-----
|
377
|
+
- Missing inputs for temperature, pressure, or fO₂ offset are auto-expanded if multiple runs are inferred.
|
378
|
+
- For MELTS-based models, small amounts of H₂O and ferric iron often improve model stability.
|
379
|
+
- The function handles multiprocessing with safe timeouts and partial result recovery.
|
380
|
+
"""
|
381
|
+
|
382
|
+
if "MELTS" in Model:
|
383
|
+
try:
|
384
|
+
from meltsdynamic import MELTSdynamic
|
385
|
+
except:
|
386
|
+
Warning('alphaMELTS for Python files are not on the python path. \n Please add these files to the path running \n import sys \n sys.path.append(r"insert_your_path_to_melts_here") \n You are looking for the location of the meltsdynamic.py file')
|
387
|
+
|
388
|
+
if bulk is not None:
|
389
|
+
comp = bulk.copy()
|
390
|
+
|
391
|
+
if H2O_Liq is not None:
|
392
|
+
print('Warning - the kwarg "H2O_Liq" will be removed from v1.0.0 onwards. Please use "H2O_init" instead.')
|
393
|
+
if H2O_init is None:
|
394
|
+
H2O_init = H2O_Liq
|
395
|
+
|
396
|
+
if CO2_Liq is not None:
|
397
|
+
print('Warning - the kwarg "CO2_Liq" will be removed from v1.0.0 onwards. Please use "CO2_init" instead.')
|
398
|
+
if CO2_init is None:
|
399
|
+
CO2_init = CO2_Liq
|
400
|
+
|
401
|
+
if Fe3Fet_Liq is not None:
|
402
|
+
print('Warning - the kwarg "Fe3Fet_Liq" will be removed from v1.0.0 onwards. Please use "Fe3Fet_init" instead.')
|
403
|
+
if Fe3Fet_init is None:
|
404
|
+
Fe3Fet_init = Fe3Fet_Liq
|
405
|
+
|
406
|
+
# if comp is entered as a pandas series, it must first be converted to a dict
|
407
|
+
if type(comp) == pd.core.series.Series:
|
408
|
+
comp = comp.to_dict()
|
409
|
+
|
410
|
+
if fO2_buffer is not None:
|
411
|
+
if fO2_buffer != "NNO":
|
412
|
+
if fO2_buffer != "FMQ":
|
413
|
+
raise Warning("fO2 buffer specified is not an allowed input. This argument can only be 'FMQ' or 'NNO' \n if you want to offset from these buffers use the 'fO2_offset' argument.")
|
414
|
+
|
415
|
+
# ensure the bulk composition has the correct headers etc.
|
416
|
+
comp = comp_fix(Model = Model, comp = comp, Fe3Fet_Liq = Fe3Fet_init, H2O_Liq = H2O_init, CO2_Liq = CO2_init)
|
417
|
+
|
418
|
+
if type(comp) == dict:
|
419
|
+
if comp['H2O_Liq'] == 0.0 and "MELTS" in Model:
|
420
|
+
raise Warning("Adding small amounts of H$_{2}$O may improve the ability of MELTS to accurately reproduce the saturation of oxide minerals. Additionally, sufficient H$_{2}$O is required in the model for MELTS to predict the crystallisation of apatite, rather than whitlockite.")
|
421
|
+
|
422
|
+
if comp['Fe3Fet_Liq'] == 0.0 and "MELTS" in Model and fO2_buffer is None:
|
423
|
+
raise Warning("MELTS often fails to produce any results when no ferric Fe is included in the starting composition and an fO2 buffer is not set.")
|
424
|
+
|
425
|
+
# specify the number of calculations to be performed in each sequence
|
426
|
+
One = 0
|
427
|
+
if type(comp) == pd.core.frame.DataFrame: # simplest scenario - one calculation per bulk composition imported
|
428
|
+
A = len(comp['SiO2_Liq'])//cores
|
429
|
+
B = len(comp['SiO2_Liq'])%cores
|
430
|
+
else:
|
431
|
+
if T_fixed_C is not None and type(T_fixed_C) == np.ndarray: # one calculation per T loaded.
|
432
|
+
A = len(T_fixed_C)//cores
|
433
|
+
B = len(T_fixed_C)%cores
|
434
|
+
elif fO2_offset is not None and type(fO2_offset) == np.ndarray: # one calculation per offset
|
435
|
+
A = len(fO2_offset)//cores
|
436
|
+
B = len(fO2_offset)%cores
|
437
|
+
else: # just one calculation
|
438
|
+
One = 1
|
439
|
+
A = 1
|
440
|
+
B = 0
|
441
|
+
|
442
|
+
Group = np.zeros(A) + cores
|
443
|
+
if B > 0:
|
444
|
+
Group = np.append(Group, B)
|
445
|
+
|
446
|
+
qs = []
|
447
|
+
q = Queue()
|
448
|
+
if One == 1:
|
449
|
+
if multi_processing:
|
450
|
+
p = Process(target = satP, args = (q,0),
|
451
|
+
kwargs = {'Model': Model, 'comp': comp, 'T_C_init': T_C_init,
|
452
|
+
'T_fixed_C': T_fixed_C, 'P_bar_init': P_bar_init,
|
453
|
+
'fO2_buffer': fO2_buffer, 'fO2_offset': fO2_offset})
|
454
|
+
p.start()
|
455
|
+
try:
|
456
|
+
ret = q.get(timeout = timeout)
|
457
|
+
except:
|
458
|
+
ret = []
|
459
|
+
|
460
|
+
TIMEOUT = 5
|
461
|
+
start = time.time()
|
462
|
+
if p.is_alive():
|
463
|
+
while time.time() - start <= TIMEOUT:
|
464
|
+
if not p.is_alive():
|
465
|
+
p.join()
|
466
|
+
p.terminate()
|
467
|
+
break
|
468
|
+
time.sleep(.1)
|
469
|
+
else:
|
470
|
+
p.terminate()
|
471
|
+
p.join(5)
|
472
|
+
else:
|
473
|
+
p.join()
|
474
|
+
p.terminate()
|
475
|
+
|
476
|
+
if len(ret) > 0:
|
477
|
+
Results, index = ret
|
478
|
+
else:
|
479
|
+
Results = {}
|
480
|
+
|
481
|
+
return Results
|
482
|
+
else:
|
483
|
+
Results = findSatPressure_MELTS(Model = Model, T_C_init=T_C_init, T_fixed_C=T_fixed_C,
|
484
|
+
P_bar_init=P_bar_init, comp = comp, fO2_buffer=fO2_buffer,
|
485
|
+
fO2_offset=fO2_offset)
|
486
|
+
return Results
|
487
|
+
else: # perform multiple crystallisation calculations
|
488
|
+
# first make sure everything is the right length
|
489
|
+
L = np.sum(Group)
|
490
|
+
if type(P_bar_init) == float or type(P_bar_init) == int:
|
491
|
+
P_bar_init = np.zeros(int(L)) + P_bar_init
|
492
|
+
if T_C_init is None:
|
493
|
+
T_C_init = [None] * int(L)
|
494
|
+
elif type(T_C_init) == float or type(T_C_init) == int:
|
495
|
+
T_C_init = np.zeros(int(L)) + T_C_init
|
496
|
+
if T_fixed_C is None:
|
497
|
+
T_fixed_C = [None] * int(L)
|
498
|
+
elif type(T_fixed_C) == float or type(T_fixed_C) == int:
|
499
|
+
T_fixed_C = np.zeros(int(L)) + T_fixed_C
|
500
|
+
if fO2_offset is None:
|
501
|
+
fO2_offset = [None] * int(L)
|
502
|
+
elif type(fO2_offset) == float or type(fO2_offset) == int:
|
503
|
+
fO2_offset = np.zeros(int(L)) + fO2_offset
|
504
|
+
|
505
|
+
index_in = np.arange(int(L))
|
506
|
+
combined_results = {}
|
507
|
+
index_out = np.array([], dtype=int)
|
508
|
+
timeout_main = timeout
|
509
|
+
|
510
|
+
while len(index_out)<len(index_in):
|
511
|
+
index = np.setdiff1d(index_in, index_out)
|
512
|
+
groups = np.array_split(index, cores)
|
513
|
+
non_empty_groups = [g for g in groups if g.size > 0]
|
514
|
+
groups = non_empty_groups
|
515
|
+
|
516
|
+
if len(groups[0])< 15:
|
517
|
+
timeout = len(groups[0])*timeout_main
|
518
|
+
else:
|
519
|
+
timeout = 15*timeout_main
|
520
|
+
|
521
|
+
processes = []
|
522
|
+
Start = time.time()
|
523
|
+
for i in range(len(groups)):
|
524
|
+
q = Queue()
|
525
|
+
p = Process(target = saturationP_multi, args = (q, groups[i]),
|
526
|
+
kwargs = {'Model': Model, 'comp': comp, 'T_C_init': T_C_init,
|
527
|
+
'T_fixed_C': T_fixed_C, 'P_bar_init': P_bar_init,
|
528
|
+
'fO2_buffer': fO2_buffer, 'fO2_offset': fO2_offset})
|
529
|
+
|
530
|
+
processes.append([p, q, groups[i]])
|
531
|
+
p.start()
|
532
|
+
|
533
|
+
for p, q, group in processes:
|
534
|
+
try:
|
535
|
+
if time.time() - Start < timeout + 5:
|
536
|
+
res = q.get(timeout = timeout)
|
537
|
+
else:
|
538
|
+
res = q.get(timeout=10)
|
539
|
+
except:
|
540
|
+
res = []
|
541
|
+
idx_chunks = np.array([group[0]], dtype = int)
|
542
|
+
|
543
|
+
p.join(timeout=2)
|
544
|
+
p.terminate()
|
545
|
+
|
546
|
+
if len(res) > 0.0:
|
547
|
+
idx_chunks, results = res
|
548
|
+
combined_results.update(results)
|
549
|
+
|
550
|
+
index_out = np.hstack((index_out, idx_chunks))
|
551
|
+
|
552
|
+
print(f"Completed {100*len(index_out)/len(index_in)} %")
|
553
|
+
|
554
|
+
results = combined_results
|
555
|
+
|
556
|
+
def results_to_dataframe(results, full_index):
|
557
|
+
# Convert 'Run X' → X and create DataFrame
|
558
|
+
df = pd.DataFrame.from_dict(results, orient='index')
|
559
|
+
df.index = df.index.str.extract(r'Run (\d+)')[0].values.astype(int)
|
560
|
+
|
561
|
+
# Reindex with full range, fill missing with 0.0
|
562
|
+
df = df.reindex(full_index, fill_value=0.0)
|
563
|
+
|
564
|
+
# Optional: sort index if needed
|
565
|
+
df = df.sort_index()
|
566
|
+
|
567
|
+
return df
|
568
|
+
Results = results_to_dataframe(results, index_in)
|
569
|
+
|
570
|
+
if copy_columns is not None:
|
571
|
+
if type(copy_columns) == str:
|
572
|
+
Results.insert(0, copy_columns, comp[copy_columns])
|
573
|
+
# Af_Combined.insert(0, copy_columns, comp[copy_columns])
|
574
|
+
elif type(copy_columns) == list:
|
575
|
+
j = 0
|
576
|
+
for i in copy_columns:
|
577
|
+
Results.insert(j, i, comp[i])
|
578
|
+
# Af_Combined.insert(j, i, comp[i])
|
579
|
+
j = j + 1
|
580
|
+
|
581
|
+
return Results
|
582
|
+
|
583
|
+
def saturationP_multi(q, index, *, Model = None, comp = None, T_C_init = None, T_fixed_C = None,
|
584
|
+
P_bar_init = None, fO2_buffer = None, fO2_offset = None):
|
585
|
+
results = {}
|
586
|
+
idx = []
|
587
|
+
if "MELTS" in Model:
|
588
|
+
from meltsdynamic import MELTSdynamic
|
589
|
+
|
590
|
+
if Model is None or Model == "MELTSv1.0.2":
|
591
|
+
melts = MELTSdynamic(1)
|
592
|
+
elif Model == "pMELTS":
|
593
|
+
melts = MELTSdynamic(2)
|
594
|
+
elif Model == "MELTSv1.1.0":
|
595
|
+
melts = MELTSdynamic(3)
|
596
|
+
elif Model == "MELTSv1.2.0":
|
597
|
+
melts = MELTSdynamic(4)
|
598
|
+
|
599
|
+
|
600
|
+
melts.engine.pressure = P_bar_init[0]
|
601
|
+
if T_fixed_C[0] is not None:
|
602
|
+
melts.engine.temperature = T_fixed_C[0] + 500
|
603
|
+
else:
|
604
|
+
melts.engine.temperature = T_C_init[0] + 500
|
605
|
+
|
606
|
+
if type(comp) == dict:
|
607
|
+
bulk = [comp['SiO2_Liq'], comp['TiO2_Liq'], comp['Al2O3_Liq'],
|
608
|
+
comp['Fe3Fet_Liq']*((159.59/2)/71.844)*comp['FeOt_Liq'],
|
609
|
+
comp['Cr2O3_Liq'], (1- comp['Fe3Fet_Liq'])*comp['FeOt_Liq'],
|
610
|
+
comp['MnO_Liq'], comp['MgO_Liq'], 0.0, 0.0, comp['CaO_Liq'],
|
611
|
+
comp['Na2O_Liq'], comp['K2O_Liq'], comp['P2O5_Liq'],
|
612
|
+
comp['H2O_Liq'], comp['CO2_Liq'], 0.0, 0.0, 0.0]
|
613
|
+
else:
|
614
|
+
bulk = [comp.loc[0,'SiO2_Liq'], comp.loc[0,'TiO2_Liq'], comp.loc[0,'Al2O3_Liq'],
|
615
|
+
comp.loc[0,'Fe3Fet_Liq']*((159.59/2)/71.844)*comp.loc[0,'FeOt_Liq'],
|
616
|
+
comp.loc[0,'Cr2O3_Liq'], (1- comp.loc[0,'Fe3Fet_Liq'])*comp.loc[0,'FeOt_Liq'],
|
617
|
+
comp.loc[0,'MnO_Liq'], comp.loc[0,'MgO_Liq'], 0.0, 0.0, comp.loc[0,'CaO_Liq'],
|
618
|
+
comp.loc[0,'Na2O_Liq'], comp.loc[0,'K2O_Liq'], comp.loc[0,'P2O5_Liq'],
|
619
|
+
comp.loc[0,'H2O_Liq'], comp.loc[0,'CO2_Liq'], 0.0, 0.0, 0.0]
|
620
|
+
|
621
|
+
melts.engine.setBulkComposition(bulk)
|
622
|
+
PL = melts.engine.calcSaturationState()
|
623
|
+
if T_fixed_C[0] is not None:
|
624
|
+
for p in PL:
|
625
|
+
if p != "fluid":
|
626
|
+
if p != "water":
|
627
|
+
melts.engine.setSystemProperties("Suppress", p)
|
628
|
+
else:
|
629
|
+
Suppress = ['rutile', 'tridymite']
|
630
|
+
for p in Suppress:
|
631
|
+
melts.engine.setSystemProperties("Suppress", p)
|
632
|
+
|
633
|
+
for i in index:
|
634
|
+
melts = melts.addNodeAfter()
|
635
|
+
try:
|
636
|
+
if type(comp) == dict:
|
637
|
+
Results, tr = findSatPressure_MELTS(Model = Model, T_C_init=T_C_init[i], T_fixed_C=T_fixed_C[i],
|
638
|
+
P_bar_init=P_bar_init[i], comp = comp, fO2_buffer=fO2_buffer,
|
639
|
+
fO2_offset=fO2_offset[i], trial = True, melts = melts, suppressed = True)
|
640
|
+
else:
|
641
|
+
Results, tr = findSatPressure_MELTS(Model = Model, T_C_init=T_C_init[i], T_fixed_C=T_fixed_C[i],
|
642
|
+
P_bar_init=P_bar_init[i], comp = comp.loc[i].to_dict(), fO2_buffer=fO2_buffer,
|
643
|
+
fO2_offset=fO2_offset[i], trial = True, melts = melts, suppressed = True)
|
644
|
+
|
645
|
+
results[f"Run {i}"] = Results
|
646
|
+
idx.append(i)
|
647
|
+
if tr is False:
|
648
|
+
break
|
649
|
+
except:
|
650
|
+
idx.append(i)
|
651
|
+
break
|
652
|
+
|
653
|
+
q.put([idx, results])
|
654
|
+
|
655
|
+
def satP(q, index, *, Model = None, comp = None, T_C_init = None, T_fixed_C = None,
|
656
|
+
P_bar_init = None, fO2_buffer = None, fO2_offset = None):
|
307
657
|
"""Find the saturation pressure for a given composition and temperature.
|
308
658
|
|
309
659
|
This function calculates the volatile saturation pressure for a given composition using the MELTS models. The results are returned in the form of a tuple and added to the specified queue.
|
@@ -329,7 +679,8 @@ def satP(q, index, *, Model = None, comp = None, T_C_init = None, T_fixed_C = No
|
|
329
679
|
|
330
680
|
def satP_multi(q, index, *, Model = None, comp = None, fO2_buffer = None):
|
331
681
|
if "MELTS" in Model:
|
332
|
-
Results = findSatPressure_MELTS_multi(Model = Model, comp = comp, fO2_buffer=fO2_buffer,
|
682
|
+
Results = findSatPressure_MELTS_multi(Model = Model, comp = comp, fO2_buffer=fO2_buffer,
|
683
|
+
fO2_offset=comp['fO2_offset'],
|
333
684
|
P_bar = comp['P_bar'], T_fixed_C=comp['T_fixed_C'])
|
334
685
|
q.put([Results, index])
|
335
686
|
return
|
PetThermoTools/_version.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: PetThermoTools
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.41
|
4
4
|
Summary: PetThermoTools
|
5
5
|
Home-page: https://github.com/gleesonm1/PetThermoTools
|
6
6
|
Author: Matthew Gleeson
|
@@ -12,7 +12,7 @@ Classifier: Operating System :: OS Independent
|
|
12
12
|
Requires-Python: >=3.8
|
13
13
|
Description-Content-Type: text/markdown
|
14
14
|
Requires-Dist: pandas
|
15
|
-
Requires-Dist: numpy
|
15
|
+
Requires-Dist: numpy
|
16
16
|
Requires-Dist: matplotlib
|
17
17
|
Requires-Dist: scikit-learn
|
18
18
|
Requires-Dist: scipy
|
@@ -0,0 +1,20 @@
|
|
1
|
+
PetThermoTools/Barom.py,sha256=6uObJ8ZsHQD6r46ZAyBQGiuVKbmdIVMe4SFp5v-Vigg,46149
|
2
|
+
PetThermoTools/Compositions.py,sha256=65NzfduzWdfHJ8VmHBN1Cv7fMz7kF3QbDVLei-e4v00,1483
|
3
|
+
PetThermoTools/GenFuncs.py,sha256=qiDB0Tdxu4sErSZGCl_Hm6ZUginDI2LG0s9YGiiRqBw,18130
|
4
|
+
PetThermoTools/Holland.py,sha256=udBFeVUyTBpSfLIhx7Hy6o0I8ApNCDvwU_gZa0diY5w,7251
|
5
|
+
PetThermoTools/Installation.py,sha256=UfVOW1NZFdzMWPyID5u7t0KwvpJA0AqYohzidXIAwYs,6098
|
6
|
+
PetThermoTools/Liq.py,sha256=BxAiHTeVQSLgpJT1Ac71apOQYmY3LGTPrxXclwE4F6w,35145
|
7
|
+
PetThermoTools/MELTS.py,sha256=MIW1QUF-W76xjS4nD4tmFXKzYdh7ghY4W05kXU3hoBc,76412
|
8
|
+
PetThermoTools/Melting.py,sha256=O6BX_NEWsjLrdkpaZSwPYqQOzIvSHxfyOMKtg7HSmZc,13061
|
9
|
+
PetThermoTools/Path.py,sha256=9ijpgp91QNRUftnR80F7wWgenWr8bsZkaZ20OIdOD0M,38116
|
10
|
+
PetThermoTools/Path_wrappers.py,sha256=gUxs_4Qbk4MLlLl4iySxfbfKU34588bIJAYyhHmhFdc,30177
|
11
|
+
PetThermoTools/PhaseDiagrams.py,sha256=CqiZbP3R2DHTHXI6EYam91Lqz_CqrRjyxG01FlOUVHU,29847
|
12
|
+
PetThermoTools/Plotting.py,sha256=uvL_j2emMveGumLQ-IeJqyMXGUQT_PyInOpGnsWziAI,28992
|
13
|
+
PetThermoTools/Saturation.py,sha256=m014Wtcd6pT8qmQhUoQQczZEB6dX3iIdxsCGtxmuOh0,29806
|
14
|
+
PetThermoTools/__init__.py,sha256=PbiwQj_mNNEwuIZOLETmtMMshiXa50wjCA6mfvpOpOs,2393
|
15
|
+
PetThermoTools/_version.py,sha256=WvrDLHqvUFROTO0ipm6xZxsmiXhJ3Pibqtgbf_NAJkM,296
|
16
|
+
PetThermoTools-0.2.41.dist-info/LICENSE.txt,sha256=-mkx4iEw8Pk1RZUvncBhGLW87Uur5JB7FBQtOmX-VP0,1752
|
17
|
+
PetThermoTools-0.2.41.dist-info/METADATA,sha256=DQ0lx7W5xgUFICbzLIyjAzANmDoHfdU1bPe4Op9Jh2U,794
|
18
|
+
PetThermoTools-0.2.41.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
19
|
+
PetThermoTools-0.2.41.dist-info/top_level.txt,sha256=IqK8iYBR3YJozzMOTRZ8x8mU2k6x8ycoMBxZTm-I06U,15
|
20
|
+
PetThermoTools-0.2.41.dist-info/RECORD,,
|
@@ -1,20 +0,0 @@
|
|
1
|
-
PetThermoTools/Barom.py,sha256=CXjwCb7KpQG8x7IhewCLTfqoJ02s4Ott3NwDcGQMWtQ,40221
|
2
|
-
PetThermoTools/Compositions.py,sha256=65NzfduzWdfHJ8VmHBN1Cv7fMz7kF3QbDVLei-e4v00,1483
|
3
|
-
PetThermoTools/GenFuncs.py,sha256=_hhy4Myen18rMa5AVagb0wvwdXVZ5BtF2bRW_vnM3tY,17681
|
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=DeTM8j2fJ5dAw_2DVCGfgh1R_lQB4Z5rLopKSJ1Q5xQ,73852
|
8
|
-
PetThermoTools/Melting.py,sha256=6EXjDJi5ZEZkQdoZbClRvnm3la_9c1tqurwyagcp5ts,12808
|
9
|
-
PetThermoTools/Path.py,sha256=ey1nKnmdtriQ_0W6nG5Hbqhhk4EYqY64y1bMwhoXTW0,33050
|
10
|
-
PetThermoTools/Path_wrappers.py,sha256=_0pBs_cK2hICxAHkYxKXICUnUEBSiUg07-qhgBeuTdc,26555
|
11
|
-
PetThermoTools/PhaseDiagrams.py,sha256=8S_BcqggBzfUbiCPcsJRWFBenGL4tcCevte3-ATQjQI,30884
|
12
|
-
PetThermoTools/Plotting.py,sha256=uvL_j2emMveGumLQ-IeJqyMXGUQT_PyInOpGnsWziAI,28992
|
13
|
-
PetThermoTools/Saturation.py,sha256=XXY6fKVouQM3RLgQgXur4xSq7_uGp7bCw_k7NNlWYi8,14095
|
14
|
-
PetThermoTools/__init__.py,sha256=PbiwQj_mNNEwuIZOLETmtMMshiXa50wjCA6mfvpOpOs,2393
|
15
|
-
PetThermoTools/_version.py,sha256=mHkADyHdAemaOsQ81BakYanLTpx-qI1XT0aama1lkCw,296
|
16
|
-
PetThermoTools-0.2.39.dist-info/LICENSE.txt,sha256=-mkx4iEw8Pk1RZUvncBhGLW87Uur5JB7FBQtOmX-VP0,1752
|
17
|
-
PetThermoTools-0.2.39.dist-info/METADATA,sha256=EaGuwfuigrt061ZQbwUN0JEYA0jg-D7YIQd-pXPwQe0,796
|
18
|
-
PetThermoTools-0.2.39.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
19
|
-
PetThermoTools-0.2.39.dist-info/top_level.txt,sha256=IqK8iYBR3YJozzMOTRZ8x8mU2k6x8ycoMBxZTm-I06U,15
|
20
|
-
PetThermoTools-0.2.39.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|