PetThermoTools 0.2.40__tar.gz → 0.2.42__tar.gz

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.
Files changed (25) hide show
  1. {PetThermoTools-0.2.40/src/PetThermoTools.egg-info → PetThermoTools-0.2.42}/PKG-INFO +1 -1
  2. {PetThermoTools-0.2.40 → PetThermoTools-0.2.42}/setup.py +1 -1
  3. {PetThermoTools-0.2.40 → PetThermoTools-0.2.42}/src/PetThermoTools/Barom.py +24 -1
  4. {PetThermoTools-0.2.40 → PetThermoTools-0.2.42}/src/PetThermoTools/GenFuncs.py +74 -24
  5. {PetThermoTools-0.2.40 → PetThermoTools-0.2.42}/src/PetThermoTools/Liq.py +46 -4
  6. {PetThermoTools-0.2.40 → PetThermoTools-0.2.42}/src/PetThermoTools/MELTS.py +3 -1
  7. {PetThermoTools-0.2.40 → PetThermoTools-0.2.42}/src/PetThermoTools/Melting.py +105 -52
  8. {PetThermoTools-0.2.40 → PetThermoTools-0.2.42}/src/PetThermoTools/Path.py +60 -18
  9. {PetThermoTools-0.2.40 → PetThermoTools-0.2.42}/src/PetThermoTools/PhaseDiagrams.py +32 -1
  10. {PetThermoTools-0.2.40 → PetThermoTools-0.2.42}/src/PetThermoTools/Plotting.py +395 -164
  11. {PetThermoTools-0.2.40 → PetThermoTools-0.2.42}/src/PetThermoTools/Saturation.py +5 -0
  12. {PetThermoTools-0.2.40 → PetThermoTools-0.2.42}/src/PetThermoTools/_version.py +1 -1
  13. {PetThermoTools-0.2.40 → PetThermoTools-0.2.42/src/PetThermoTools.egg-info}/PKG-INFO +1 -1
  14. {PetThermoTools-0.2.40 → PetThermoTools-0.2.42}/src/PetThermoTools.egg-info/requires.txt +1 -1
  15. {PetThermoTools-0.2.40 → PetThermoTools-0.2.42}/LICENSE.txt +0 -0
  16. {PetThermoTools-0.2.40 → PetThermoTools-0.2.42}/README.md +0 -0
  17. {PetThermoTools-0.2.40 → PetThermoTools-0.2.42}/setup.cfg +0 -0
  18. {PetThermoTools-0.2.40 → PetThermoTools-0.2.42}/src/PetThermoTools/Compositions.py +0 -0
  19. {PetThermoTools-0.2.40 → PetThermoTools-0.2.42}/src/PetThermoTools/Holland.py +0 -0
  20. {PetThermoTools-0.2.40 → PetThermoTools-0.2.42}/src/PetThermoTools/Installation.py +0 -0
  21. {PetThermoTools-0.2.40 → PetThermoTools-0.2.42}/src/PetThermoTools/Path_wrappers.py +0 -0
  22. {PetThermoTools-0.2.40 → PetThermoTools-0.2.42}/src/PetThermoTools/__init__.py +0 -0
  23. {PetThermoTools-0.2.40 → PetThermoTools-0.2.42}/src/PetThermoTools.egg-info/SOURCES.txt +0 -0
  24. {PetThermoTools-0.2.40 → PetThermoTools-0.2.42}/src/PetThermoTools.egg-info/dependency_links.txt +0 -0
  25. {PetThermoTools-0.2.40 → PetThermoTools-0.2.42}/src/PetThermoTools.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PetThermoTools
3
- Version: 0.2.40
3
+ Version: 0.2.42
4
4
  Summary: PetThermoTools
5
5
  Home-page: https://github.com/gleesonm1/PetThermoTools
6
6
  Author: Matthew Gleeson
@@ -30,7 +30,7 @@ setup(
30
30
  },
31
31
  install_requires=[
32
32
  'pandas',
33
- 'numpy<2',
33
+ 'numpy',
34
34
  'matplotlib',
35
35
  'scikit-learn',
36
36
  'scipy',
@@ -186,8 +186,31 @@ def mineral_cosaturation(Model="MELTSv1.0.2", cores=int(np.floor(multiprocessing
186
186
  Results : dict
187
187
  Raw simulation outputs for each pressure step.
188
188
  """
189
-
189
+ ## make sure everything is a float
190
+ T_initial_C = to_float(T_initial_C)
191
+ T_maxdrop_C = to_float(T_maxdrop_C)
192
+ T_cut_C = to_float(T_cut_C)
193
+
194
+ P_bar = to_float(P_bar)
195
+
196
+ Fe3Fet_init= to_float(Fe3Fet_init)
197
+ H2O_init = to_float(H2O_init)
198
+ CO2_init = to_float(CO2_init)
199
+ fO2_offset = to_float(fO2_offset)
200
+
190
201
  comp = bulk.copy()
202
+
203
+ if fO2_buffer is not None:
204
+ if fO2_buffer != "NNO":
205
+ if fO2_buffer != "FMQ":
206
+ 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.")
207
+
208
+ if "MELTS" not in Model:
209
+ if fO2_buffer == "FMQ":
210
+ fO2_buffer = "qfm"
211
+ if fO2_buffer == "NNO":
212
+ fO2_buffer = "nno"
213
+
191
214
  if H2O_Sat:
192
215
  comp['H2O_Liq'] = 20
193
216
 
@@ -4,52 +4,64 @@ import pandas as pd
4
4
  # from PetThermoTools.Liq import *
5
5
  # from PetThermoTools.Crystallise import *
6
6
  from PetThermoTools.MELTS import *
7
+ from PetThermoTools.Compositions import *
7
8
  # try:
8
9
  # from PetThermoTools.Holland import *
9
10
  # except:
10
11
  # pass
11
12
 
12
13
  Names = {'liquid1': '_Liq',
13
- 'liquid2': '_Liq2',
14
- 'liquid3': '_Liq3',
15
- 'liquid4': '_Liq4',
16
14
  'olivine1': '_Ol',
17
- 'olivine2': '_Ol2',
15
+ 'orthopyroxene1': '_Opx',
18
16
  'clinopyroxene1': '_Cpx',
19
- 'clinopyroxene2': '_Cpx2',
17
+ 'garnet1': '_Grt',
18
+ 'spinel1': '_Sp',
19
+ 'k-feldspar1': '_Kspar',
20
+ 'quartz1': '_Qtz',
21
+ 'rhm-oxide1': '_Rhm',
22
+ 'apatite1': '_Apa',
23
+ 'olivine2': '_Ol2',
20
24
  'plagioclase1': '_Plag',
25
+ 'clinopyroxene2': '_Cpx2',
21
26
  'plagioclase2': '_Plag2',
22
- 'spinel1': '_Sp',
23
27
  'spinel2': '_Sp2',
24
- 'k-feldspar1': '_Kspar',
25
28
  'k-feldspar2': '_Kspar2',
26
- 'garnet1': '_Grt',
27
29
  'garnet2': '_Grt2',
28
- 'rhm-oxide1': '_Rhm',
29
30
  'rhm-oxide2': '_Rhm2',
30
- 'quartz1': '_Qtz',
31
31
  'quartz2': '_Qtz2',
32
- 'orthopyroxene1': '_Opx',
33
32
  'orthopyroxene2': '_Opx2',
34
- 'apatite1': '_Apa',
35
- 'apatite2': '_Apa2'}
33
+ 'apatite2': '_Apa2',
34
+ 'liquid2': '_Liq2',
35
+ 'liquid3': '_Liq3',
36
+ 'liquid4': '_Liq4'}
36
37
 
37
38
  Names_MM = {'liq1': '_Liq',
38
- 'liq2': '_Liq2',
39
- 'liq3': '_Liq3',
40
- 'liq4': '_Liq4',
41
39
  'ol1': '_Ol',
42
- 'ol2': '_Ol2',
40
+ 'opx1': '_Opx',
43
41
  'cpx1': '_Cpx',
42
+ 'g1': '_Grt',
43
+ 'spl1': '_Sp',
44
+ 'fsp1': '_Plag',
45
+ 'ol2': '_Ol2',
44
46
  'cpx2': '_Cpx2',
45
- 'opx1': '_Opx',
46
47
  'opx2': '_Opx2',
47
- 'g1': '_Grt',
48
48
  'g2': '_Grt2',
49
- 'fsp1': '_Plag',
50
49
  'fsp2': '_Plag2',
51
- 'spl1': '_Sp',
52
- 'spl2': '_Sp2'}
50
+ 'spl2': '_Sp2',
51
+ 'liq2': '_Liq2',
52
+ 'liq3': '_Liq3',
53
+ 'liq4': '_Liq4'}
54
+
55
+ def to_float(x):
56
+ if x is None:
57
+ return None
58
+ if isinstance(x, (int, float)):
59
+ return float(x)
60
+ if isinstance(x, (list, tuple)):
61
+ return [float(v) for v in x]
62
+ if isinstance(x, np.ndarray):
63
+ return x.astype(float)
64
+ return x # leave unchanged if unexpected type
53
65
 
54
66
  def label_results(Result,label):
55
67
  Results = Result.copy()
@@ -93,6 +105,36 @@ def supCalc(Model = "MELTSv1.0.2", bulk = None, phase = None, T_C = None, P_bar
93
105
 
94
106
  return Results
95
107
 
108
+ def comp_check(comp_lith, Model, MELTS_filter, Fe3Fet):
109
+ if type(comp_lith) == str:
110
+ if Model != "pyMelt":
111
+ comp = Compositions[comp_lith]
112
+ else:
113
+ comp = comp_lith
114
+ else:
115
+ comp = comp_lith.copy()
116
+
117
+ # if comp is entered as a pandas series, it must first be converted to a dict
118
+ if Model != "pyMelt":
119
+ if type(comp) == pd.core.series.Series:
120
+ comp = comp.to_dict()
121
+
122
+ comp = comp_fix(Model = Model, comp = comp, Fe3Fet_Liq = Fe3Fet)
123
+
124
+ if "MELTS" in Model and MELTS_filter == True:
125
+ if type(comp) == pd.core.frame.DataFrame:
126
+ comp['K2O_Liq'] = np.zeros(len(comp['SiO2_Liq']))
127
+ comp['P2O5_Liq'] = np.zeros(len(comp['SiO2_Liq']))
128
+ comp['H2O_Liq'] = np.zeros(len(comp['SiO2_Liq']))
129
+ comp['CO2_Liq'] = np.zeros(len(comp['SiO2_Liq']))
130
+ else:
131
+ comp['K2O_Liq'] = 0
132
+ comp['P2O5_Liq'] = 0
133
+ comp['H2O_Liq'] = 0
134
+ comp['CO2_Liq'] = 0
135
+
136
+ return comp
137
+
96
138
 
97
139
  def comp_fix(Model = None, comp = None, Fe3Fet_Liq = None, H2O_Liq = None, CO2_Liq = None):
98
140
  '''
@@ -345,12 +387,20 @@ def stich_work(Results = None, Order = None, Model = "MELTS", Frac_fluid = None,
345
387
  Results_Mass['fluid1_cumsum'] = Results_Mass['fluid1'].cumsum()
346
388
  elif Frac_fluid is None:
347
389
  for n in SN:
348
- if n != 'liquid1' and n!= 'fluid1':
390
+ if n != 'liquid1' and n!= 'fluid1' and n != 'liq1' and n != 'fl1':
349
391
  Results_Mass[n + '_cumsum'] = Results_Mass[n].cumsum()
392
+ if 'liq1' in SN:
393
+ Results_Mass[n + '_cumsum'] = Results_Mass.loc[0, 'liq1'] - Results_Mass.loc[:,Results_Mass.columns.str.contains('_cumsum')].sum(axis = 1)
394
+ elif 'liquid1' in SN:
395
+ Results_Mass[n + '_cumsum'] = Results_Mass.loc[0, 'liquid1'] - Results_Mass.loc[:,Results_Mass.columns.str.contains('_cumsum')].sum(axis = 1)
350
396
  else:
351
397
  for n in SN:
352
- if n != 'liquid1':
398
+ if n != 'liquid1' and n != 'liq1':
353
399
  Results_Mass[n + '_cumsum'] = Results_Mass[n].cumsum()
400
+ if 'liq1' in SN:
401
+ Results_Mass[n + '_cumsum'] = Results_Mass.loc[0, 'liq1'] - Results_Mass.loc[:,Results_Mass.columns.str.contains('_cumsum')].sum(axis = 1)
402
+ elif 'liquid1' in SN:
403
+ Results_Mass[n + '_cumsum'] = Results_Mass.loc[0, 'liquid1'] - Results_Mass.loc[:,Results_Mass.columns.str.contains('_cumsum')].sum(axis = 1)
354
404
 
355
405
  Results_All = Results['Conditions'].copy()
356
406
  for R in Results:
@@ -16,6 +16,26 @@ def equilibrate_multi(cores = None, Model = None, bulk = None, T_C = None, P_bar
16
16
  Fe3Fet_Liq = None, H2O_Liq = None, CO2_Liq = None, fO2_buffer = None, fO2_offset = None,
17
17
  timeout = None, copy_columns = None, Suppress = None):
18
18
 
19
+ T_C = to_float(T_C)
20
+
21
+ P_bar = to_float(P_bar)
22
+
23
+ H2O_Liq = to_float(H2O_Liq)
24
+ CO2_Liq = to_float(CO2_Liq)
25
+ Fe3Fet_Liq = to_float(Fe3Fet_Liq)
26
+ fO2_offset = to_float(fO2_offset)
27
+
28
+ if fO2_buffer is not None:
29
+ if fO2_buffer != "NNO":
30
+ if fO2_buffer != "FMQ":
31
+ 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.")
32
+
33
+ if "MELTS" not in Model:
34
+ if fO2_buffer == "FMQ":
35
+ fO2_buffer = "qfm"
36
+ if fO2_buffer == "NNO":
37
+ fO2_buffer = "nno"
38
+
19
39
  if "MELTS" in Model:
20
40
  try:
21
41
  from meltsdynamic import MELTSdynamic
@@ -410,6 +430,17 @@ def findCO2_multi(cores = None, Model = None, bulk = None, T_initial_C = None, P
410
430
  except:
411
431
  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')
412
432
 
433
+ if fO2_buffer is not None:
434
+ if fO2_buffer != "NNO":
435
+ if fO2_buffer != "FMQ":
436
+ 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.")
437
+
438
+ if "MELTS" not in Model:
439
+ if fO2_buffer == "FMQ":
440
+ fO2_buffer = "qfm"
441
+ if fO2_buffer == "NNO":
442
+ fO2_buffer = "nno"
443
+
413
444
  comp = bulk.copy()
414
445
 
415
446
  if Model is None:
@@ -607,11 +638,22 @@ def findLiq_multi(cores = None, Model = None, bulk = None, T_initial_C = None, P
607
638
 
608
639
  comp = bulk.copy()
609
640
 
641
+ if fO2_buffer is not None:
642
+ if fO2_buffer != "NNO":
643
+ if fO2_buffer != "FMQ":
644
+ 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.")
645
+
646
+ if "MELTS" not in Model:
647
+ if fO2_buffer == "FMQ":
648
+ fO2_buffer = "qfm"
649
+ if fO2_buffer == "NNO":
650
+ fO2_buffer = "nno"
651
+
610
652
  if Model is None:
611
653
  Model = "MELTSv1.0.2"
612
654
 
613
- if Model == "Holland":
614
- import pyMAGEMINcalc as MM
655
+ # if Model == "Holland":
656
+ # import pyMAGEMINcalc as MM
615
657
 
616
658
  # if comp is entered as a pandas series, it must first be converted to a dict
617
659
  if type(comp) == pd.core.series.Series:
@@ -792,8 +834,8 @@ def findLiq_multi(cores = None, Model = None, bulk = None, T_initial_C = None, P
792
834
  else:
793
835
  return Res
794
836
  else:
795
- T_Liq = MM.findLiq_multi(P_bar = P_bar, T_initial_C = T_initial_C, comp = comp)
796
- return T_Liq
837
+ # T_Liq = MM.findLiq_multi(P_bar = P_bar, T_initial_C = T_initial_C, comp = comp)
838
+ return "find liquidus calculations are currently not available through the MAGEMin models. This is an issue I'm working to fix as soon as possible."
797
839
 
798
840
  def findCO2(q, index, *, Model = None, P_bar = None, T_initial_C = None, comp = None, fO2_buffer = None, fO2_offset = None):
799
841
  T_Liq = 0
@@ -1572,7 +1572,9 @@ def findSatPressure_MELTS(Model = None, T_C_init = None, T_fixed_C = None, P_bar
1572
1572
  else:
1573
1573
  return out
1574
1574
 
1575
- def AdiabaticDecompressionMelting_MELTS(Model = None, comp = None, Tp_C = None, P_path_bar = None, P_start_bar = None, P_end_bar = None, dp_bar = None, Frac = False, fO2_buffer = None, fO2_offset = None):
1575
+ def AdiabaticDecompressionMelting_MELTS(Model = None, comp = None, Tp_C = None, Tp_Method = None,
1576
+ P_path_bar = None, P_start_bar = None, P_end_bar = None, dp_bar = None,
1577
+ Frac = False, fO2_buffer = None, fO2_offset = None):
1576
1578
  try:
1577
1579
  import pyMelt as m
1578
1580
  Lithologies = {'KLB-1': m.lithologies.matthews.klb1(),
@@ -10,37 +10,6 @@ from multiprocessing import Process
10
10
  import time
11
11
  import sys
12
12
  from tqdm.notebook import tqdm, trange
13
- # import pyMelt as m
14
-
15
- def comp_check(comp_lith, Model, MELTS_filter, Fe3Fet):
16
- if type(comp_lith) == str:
17
- if Model != "pyMelt":
18
- comp = Compositions[comp_lith]
19
- else:
20
- comp = comp_lith
21
- else:
22
- comp = comp_lith.copy()
23
-
24
- # if comp is entered as a pandas series, it must first be converted to a dict
25
- if Model != "pyMelt":
26
- if type(comp) == pd.core.series.Series:
27
- comp = comp.to_dict()
28
-
29
- comp = comp_fix(Model = Model, comp = comp, Fe3Fet_Liq = Fe3Fet)
30
-
31
- if "MELTS" in Model and MELTS_filter == True:
32
- if type(comp) == pd.core.frame.DataFrame:
33
- comp['K2O_Liq'] = np.zeros(len(comp['SiO2_Liq']))
34
- comp['P2O5_Liq'] = np.zeros(len(comp['SiO2_Liq']))
35
- comp['H2O_Liq'] = np.zeros(len(comp['SiO2_Liq']))
36
- comp['CO2_Liq'] = np.zeros(len(comp['SiO2_Liq']))
37
- else:
38
- comp['K2O_Liq'] = 0
39
- comp['P2O5_Liq'] = 0
40
- comp['H2O_Liq'] = 0
41
- comp['CO2_Liq'] = 0
42
-
43
- return comp
44
13
 
45
14
  def AdiabaticDecompressionMelting(cores = multiprocessing.cpu_count(),
46
15
  Model = "pMELTS", bulk = "KLB-1", comp_lith_1 = None,
@@ -48,22 +17,105 @@ def AdiabaticDecompressionMelting(cores = multiprocessing.cpu_count(),
48
17
  P_start_bar = 30000, P_end_bar = 2000, dp_bar = 200,
49
18
  P_path_bar = None, Frac = False, prop = None,
50
19
  fO2_buffer = None, fO2_offset = None, Fe3Fet = None, MELTS_filter = True):
20
+ """
21
+ Perform adiabatic decompression melting calculations using MELTS, MAGEMin, or pyMelt.
22
+
23
+ Simulates mantle melting along an adiabatic upwelling path (e.g., ridge or plume) with user-defined
24
+ starting potential temperature, pressure range, and step size. Supports single-lithology mantle sources
25
+ (e.g., KLB-1) at present, with expansion to multi-lithology systems in development.
26
+
27
+ Parameters
28
+ ----------
29
+ cores : int, optional
30
+ Number of CPU cores to use for multiprocessing. Defaults to total available.
31
+ Model : str, optional
32
+ Thermodynamic model. MELTS variants: "MELTSv1.0.2", "MELTSv1.1.0", "MELTSv1.2.0", "pMELTS";
33
+ or MAGEMin: "Green2025", "Weller2024". Alternatively calculations can be performed using
34
+ pyMelt (Matthews et al. 2020): "pyMelt"
35
+ bulk : dict ot str, optional
36
+ Bulk composition name or composition dictionary.
37
+ Default is "KLB-1".
38
+ Tp_C : float or np.ndarray, optional
39
+ Mantle potential temperature(s) in °C. Default is 1350.
40
+ Tp_Method : str, optional
41
+ Method to calculate the starting pressure for adiabatic melting. Default is "pyMelt".
42
+ P_start_bar, P_end_bar, dp_bar : float or array, optional
43
+ Starting, ending, and step size pressures (in bar) for adiabatic decompression.
44
+ Defaults: 30000, 2000, and 200, respectively.
45
+ P_path_bar : np.ndarray, optional
46
+ User-specified pressure path (in bar). If given, overrides `P_start_bar`, `P_end_bar`, and `dp_bar`.
47
+ fO2_buffer : {"FMQ", "NNO"}, optional
48
+ Redox buffer for constraining oxygen fugacity.
49
+ fO2_offset : float, optional
50
+ Offset (log units) from the chosen fO2 buffer.
51
+ Fe3Fet : float, optional
52
+ Initial Fe³⁺/ΣFe ratio for the bulk composition. If None, values is taken from the "bulk" variable or set according to fO2 buffer positions.
53
+ MELTS_filter : bool, default=True
54
+ If True, filters oxide components to avoid issues in MELTS calculations (e.g., K2O content set to 0.0).
55
+
56
+ Returns
57
+ -------
58
+ Results : dict
59
+ Dictionary containing DataFrames for the system and phase compositions and properties.
60
+
61
+ Notes
62
+ -----
63
+ - Currently limited to single-lithology melting.
64
+ - Normalizes output mass so that total initial mass = 1.
65
+
66
+ Examples
67
+ --------
68
+ Run a single adiabatic decompression path from 3.0 GPa to 0.2 GPa:
69
+
70
+ >>> results = AdiabaticDecompressionMelting(Model="pMELTS", bulk="KLB-1",
71
+ ... Tp_C=1350, P_start_bar=30000,
72
+ ... P_end_bar=2000, dp_bar=200)
73
+
74
+ Run with an explicit pressure path:
75
+
76
+ >>> import numpy as np
77
+ >>> P_path = np.linspace(30000, 2000, 20)
78
+ >>> results = AdiabaticDecompressionMelting(Model="pMELTS", comp_lith_1="KLB-1",
79
+ ... P_path_bar=P_path, Tp_C=1400)
80
+ """
51
81
 
52
- if Tp_Method == "pyMelt":
53
- try:
54
- import pyMelt as m
55
- Lithologies = {'KLB-1': m.lithologies.matthews.klb1(),
56
- 'KG1': m.lithologies.matthews.kg1(),
57
- 'G2': m.lithologies.matthews.eclogite(),
58
- 'hz': m.lithologies.shorttle.harzburgite()}
59
- except ImportError:
60
- raise RuntimeError('You havent installed pyMelt or there is an error when importing pyMelt. pyMelt is currently required to estimate the starting point for the melting calculations.')
82
+ Tp_C = to_float(Tp_C)
83
+
84
+ P_path_bar = to_float(P_path_bar)
85
+ P_start_bar= to_float(P_start_bar)
86
+ P_end_bar = to_float(P_end_bar)
87
+ dp_bar = to_float(dp_bar)
88
+
89
+ Fe3Fet = to_float(Fe3Fet)
90
+ fO2_offset = to_float(fO2_offset)
91
+
92
+ if fO2_buffer is not None:
93
+ if fO2_buffer != "NNO":
94
+ if fO2_buffer != "FMQ":
95
+ 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.")
96
+
97
+ if "MELTS" not in Model:
98
+ if fO2_buffer == "FMQ":
99
+ fO2_buffer = "qfm"
100
+ if fO2_buffer == "NNO":
101
+ fO2_buffer = "nno"
102
+
103
+ # if Tp_Method == "pyMelt":
104
+ # try:
105
+ # import pyMelt as m
106
+ # Lithologies = {'KLB-1': m.lithologies.matthews.klb1(),
107
+ # 'KG1': m.lithologies.matthews.kg1(),
108
+ # 'G2': m.lithologies.matthews.eclogite(),
109
+ # 'hz': m.lithologies.shorttle.harzburgite()}
110
+ # except ImportError:
111
+ # raise RuntimeError('You havent installed pyMelt or there is an error when importing pyMelt. pyMelt is currently required to estimate the starting point for the melting calculations.')
61
112
 
62
113
  if bulk is not None and comp_lith_1 is None:
63
114
  comp_lith_1 = bulk
64
115
 
65
116
  comp_1 = comp_check(comp_lith_1, Model, MELTS_filter, Fe3Fet)
66
117
 
118
+ # place holders for when code is expanded to account for multi-lithology mantle
67
119
  if comp_lith_2 is not None:
68
120
  comp_2 = comp_check(comp_lith_2, Model, MELTS_filter, Fe3Fet)
69
121
  else:
@@ -74,6 +126,8 @@ def AdiabaticDecompressionMelting(cores = multiprocessing.cpu_count(),
74
126
  else:
75
127
  comp_3 = None
76
128
 
129
+
130
+ # At present calculations only work for a single simulation - this represents a placeholder for when the code is expanded to account for multiple simulations
77
131
  One = 0
78
132
  if Model != "pyMelt":
79
133
  if type(comp_1) == pd.core.frame.DataFrame: # simplest scenario - one calculation per bulk composition imported
@@ -114,7 +168,7 @@ def AdiabaticDecompressionMelting(cores = multiprocessing.cpu_count(),
114
168
  if One == 1:
115
169
  p = Process(target = AdiabaticMelt, args = (q, 1),
116
170
  kwargs = {'Model': Model, 'comp_1': comp_1, 'comp_2': comp_2, 'comp_3': comp_3,
117
- 'Tp_C': Tp_C, 'P_path_bar': P_path_bar,
171
+ 'Tp_C': Tp_C, 'Tp_Method': Tp_Method, 'P_path_bar': P_path_bar,
118
172
  'P_start_bar': P_start_bar, 'P_end_bar': P_end_bar, 'dp_bar': dp_bar,
119
173
  'fO2_buffer': fO2_buffer, 'fO2_offset': fO2_offset, 'Frac': Frac, 'prop': prop})
120
174
 
@@ -156,7 +210,7 @@ def AdiabaticDecompressionMelting(cores = multiprocessing.cpu_count(),
156
210
 
157
211
  return Results
158
212
 
159
- def AdiabaticMelt(q, index, *, Model = None, comp_1 = None, comp_2 = None, comp_3 = None,
213
+ def AdiabaticMelt(q, index, *, Model = None, comp_1 = None, comp_2 = None, comp_3 = None, Tp_Method = "pyMelt",
160
214
  Tp_C = None, P_start_bar = None, P_end_bar = None, dp_bar = None, P_path_bar = None,
161
215
  Frac = None, fO2_buffer = None, fO2_offset = None, prop = None):
162
216
  '''
@@ -166,7 +220,7 @@ def AdiabaticMelt(q, index, *, Model = None, comp_1 = None, comp_2 = None, comp_
166
220
  Results = {}
167
221
  if "MELTS" in Model:
168
222
  try:
169
- Results = AdiabaticDecompressionMelting_MELTS(Model = Model, comp = comp_1, Tp_C = Tp_C,
223
+ Results = AdiabaticDecompressionMelting_MELTS(Model = Model, comp = comp_1, Tp_C = Tp_C, Tp_Method = "pyMelt",
170
224
  P_path_bar = P_path_bar, P_start_bar = P_start_bar, P_end_bar = P_end_bar, dp_bar = dp_bar,
171
225
  fO2_buffer = fO2_buffer, fO2_offset = fO2_offset)
172
226
  q.put([Results, index])
@@ -239,10 +293,6 @@ def AdiabaticMelt(q, index, *, Model = None, comp_1 = None, comp_2 = None, comp_
239
293
  return
240
294
 
241
295
  else:
242
- # import pyMAGEMINcalc as MM
243
- # 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)
244
- # 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.')
245
-
246
296
  try:
247
297
  import pyMelt as m
248
298
  Lithologies = {'KLB-1': m.lithologies.matthews.klb1(),
@@ -252,10 +302,13 @@ def AdiabaticMelt(q, index, *, Model = None, comp_1 = None, comp_2 = None, comp_
252
302
  except ImportError:
253
303
  raise RuntimeError('You havent installed pyMelt or there is an error when importing pyMelt. pyMelt is currently required to estimate the starting point for the melting calculations.')
254
304
 
255
- lz = m.lithologies.matthews.klb1()
256
- mantle = m.mantle([lz], [1], ['Lz'])
257
- T_start_C = mantle.adiabat(P_start_bar/10000.0, Tp_C)
258
-
305
+ if Tp_Method == "pyMelt":
306
+ lz = m.lithologies.matthews.klb1()
307
+ mantle = m.mantle([lz], [1], ['Lz'])
308
+ T_start_C = mantle.adiabat(P_start_bar/10000.0, Tp_C)
309
+ else:
310
+ T_start_C = None
311
+
259
312
  from juliacall import Main as jl, convert as jlconvert
260
313
 
261
314
  jl.seval("using MAGEMinCalc")
@@ -265,7 +318,7 @@ def AdiabaticMelt(q, index, *, Model = None, comp_1 = None, comp_2 = None, comp_
265
318
  if type(comp_1) == dict:
266
319
  comp_julia = jl.seval("Dict")(comp_1)
267
320
  else:
268
- comp_new = comp_1.loc[i].to_dict()
321
+ comp_new = comp_1.loc[0].to_dict()
269
322
  comp_julia = jl.seval("Dict")(comp_new)
270
323
 
271
324
  Output_jl = jl.MAGEMinCalc.AdiabaticDecompressionMelting(comp = comp_julia, P_start_kbar = P_start_bar/1000.0,
@@ -98,6 +98,26 @@ def multi_path(cores = None, Model = None, bulk = None, comp = None, Frac_solid
98
98
  Dictionary with each run's label as key. Values are sub-dictionaries of phase/property DataFrames.
99
99
  Includes `Input` key summarizing model configuration per run.
100
100
  """
101
+ ## make sure everything is a float
102
+ T_C = to_float(T_C)
103
+ T_path_C = to_float(T_path_C)
104
+ T_start_C = to_float(T_start_C)
105
+ T_end_C = to_float(T_end_C)
106
+ dt_C = to_float(dt_C)
107
+
108
+ P_bar = to_float(P_bar)
109
+ P_path_bar = to_float(P_path_bar)
110
+ P_start_bar= to_float(P_start_bar)
111
+ P_end_bar = to_float(P_end_bar)
112
+ dp_bar = to_float(dp_bar)
113
+
114
+ Fe3Fet_init= to_float(Fe3Fet_init)
115
+ Fe3Fet_Liq = to_float(Fe3Fet_Liq)
116
+ H2O_init = to_float(H2O_init)
117
+ H2O_Liq = to_float(H2O_Liq)
118
+ CO2_init = to_float(CO2_init)
119
+ CO2_Liq = to_float(CO2_Liq)
120
+ fO2_offset = to_float(fO2_offset)
101
121
 
102
122
  if timeout is None:
103
123
  timeout = 180
@@ -150,10 +170,12 @@ def multi_path(cores = None, Model = None, bulk = None, comp = None, Frac_solid
150
170
  if "MELTS" not in Model:
151
171
  if fO2_buffer == "FMQ":
152
172
  fO2_buffer = "qfm"
173
+ if fO2_buffer == "NNO":
174
+ fO2_buffer = "nno"
153
175
 
154
176
  # ensure the bulk composition has the correct headers etc.
155
177
  comp = comp_fix(Model = Model, comp = comp, Fe3Fet_Liq = Fe3Fet_init, H2O_Liq = H2O_init, CO2_Liq = CO2_init)
156
-
178
+
157
179
  if type(comp) == dict:
158
180
  if comp['H2O_Liq'] == 0.0 and "MELTS" in Model:
159
181
  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.")
@@ -473,28 +495,48 @@ def path_multi(q, index, *, Model = None, comp = None, Frac_solid = None, Frac_f
473
495
 
474
496
  jl.seval("using MAGEMinCalc")
475
497
 
476
-
477
498
  for i in index:
478
499
  try:
479
500
  if "MELTS" in Model:
480
501
  if type(comp) == dict:
481
- Results, tr = path_MELTS(Model = Model, comp = comp, Frac_solid = Frac_solid, Frac_fluid = Frac_fluid,
482
- T_initial_C = 1400, T_C = T_C[i], T_path_C = T_path_C[i], T_start_C = T_start_C[i],
483
- T_end_C = T_end_C[i], dt_C = dt_C[i], P_bar = P_bar[i], P_path_bar = P_path_bar[i],
484
- P_start_bar = P_start_bar[i], P_end_bar = P_end_bar[i], dp_bar = dp_bar[i],
485
- isenthalpic = isenthalpic, isentropic = isentropic, isochoric = isochoric,
486
- find_liquidus = find_liquidus, fO2_buffer = fO2_buffer, fO2_offset = fO2_offset[i],
487
- fluid_sat = fluid_sat, Crystallinity_limit = Crystallinity_limit, Suppress = Suppress,
488
- Suppress_except=Suppress_except, trail = trail, melts = melts)
502
+ if trail is not None:
503
+ Results, tr = path_MELTS(Model = Model, comp = comp, Frac_solid = Frac_solid, Frac_fluid = Frac_fluid,
504
+ T_initial_C = 1400, T_C = T_C[i], T_path_C = T_path_C[i], T_start_C = T_start_C[i],
505
+ T_end_C = T_end_C[i], dt_C = dt_C[i], P_bar = P_bar[i], P_path_bar = P_path_bar[i],
506
+ P_start_bar = P_start_bar[i], P_end_bar = P_end_bar[i], dp_bar = dp_bar[i],
507
+ isenthalpic = isenthalpic, isentropic = isentropic, isochoric = isochoric,
508
+ find_liquidus = find_liquidus, fO2_buffer = fO2_buffer, fO2_offset = fO2_offset[i],
509
+ fluid_sat = fluid_sat, Crystallinity_limit = Crystallinity_limit, Suppress = Suppress,
510
+ Suppress_except=Suppress_except, trail = trail, melts = melts)
511
+ else:
512
+ Results = path_MELTS(Model = Model, comp = comp, Frac_solid = Frac_solid, Frac_fluid = Frac_fluid,
513
+ T_initial_C = 1400, T_C = T_C[i], T_path_C = T_path_C[i], T_start_C = T_start_C[i],
514
+ T_end_C = T_end_C[i], dt_C = dt_C[i], P_bar = P_bar[i], P_path_bar = P_path_bar[i],
515
+ P_start_bar = P_start_bar[i], P_end_bar = P_end_bar[i], dp_bar = dp_bar[i],
516
+ isenthalpic = isenthalpic, isentropic = isentropic, isochoric = isochoric,
517
+ find_liquidus = find_liquidus, fO2_buffer = fO2_buffer, fO2_offset = fO2_offset[i],
518
+ fluid_sat = fluid_sat, Crystallinity_limit = Crystallinity_limit, Suppress = Suppress,
519
+ Suppress_except=Suppress_except, trail = trail, melts = melts)
520
+
489
521
  else:
490
- Results, tr = path_MELTS(Model = Model, comp = comp.loc[i].to_dict(), Frac_solid = Frac_solid, Frac_fluid = Frac_fluid,
491
- T_initial_C = 1400, T_C = T_C[i], T_path_C = T_path_C[i], T_start_C = T_start_C[i],
492
- T_end_C = T_end_C[i], dt_C = dt_C[i], P_bar = P_bar[i], P_path_bar = P_path_bar[i],
493
- P_start_bar = P_start_bar[i], P_end_bar = P_end_bar[i], dp_bar = dp_bar[i],
494
- isenthalpic = isenthalpic, isentropic = isentropic, isochoric = isochoric,
495
- find_liquidus = find_liquidus, fO2_buffer = fO2_buffer, fO2_offset = fO2_offset[i],
496
- fluid_sat = fluid_sat, Crystallinity_limit = Crystallinity_limit, Suppress = Suppress,
497
- Suppress_except=Suppress_except, trail = trail, melts = melts)
522
+ if trail is not None:
523
+ Results, tr = path_MELTS(Model = Model, comp = comp.loc[i].to_dict(), Frac_solid = Frac_solid, Frac_fluid = Frac_fluid,
524
+ T_initial_C = 1400, T_C = T_C[i], T_path_C = T_path_C[i], T_start_C = T_start_C[i],
525
+ T_end_C = T_end_C[i], dt_C = dt_C[i], P_bar = P_bar[i], P_path_bar = P_path_bar[i],
526
+ P_start_bar = P_start_bar[i], P_end_bar = P_end_bar[i], dp_bar = dp_bar[i],
527
+ isenthalpic = isenthalpic, isentropic = isentropic, isochoric = isochoric,
528
+ find_liquidus = find_liquidus, fO2_buffer = fO2_buffer, fO2_offset = fO2_offset[i],
529
+ fluid_sat = fluid_sat, Crystallinity_limit = Crystallinity_limit, Suppress = Suppress,
530
+ Suppress_except=Suppress_except, trail = trail, melts = melts)
531
+ else:
532
+ Results = path_MELTS(Model = Model, comp = comp.loc[i].to_dict(), Frac_solid = Frac_solid, Frac_fluid = Frac_fluid,
533
+ T_initial_C = 1400, T_C = T_C[i], T_path_C = T_path_C[i], T_start_C = T_start_C[i],
534
+ T_end_C = T_end_C[i], dt_C = dt_C[i], P_bar = P_bar[i], P_path_bar = P_path_bar[i],
535
+ P_start_bar = P_start_bar[i], P_end_bar = P_end_bar[i], dp_bar = dp_bar[i],
536
+ isenthalpic = isenthalpic, isentropic = isentropic, isochoric = isochoric,
537
+ find_liquidus = find_liquidus, fO2_buffer = fO2_buffer, fO2_offset = fO2_offset[i],
538
+ fluid_sat = fluid_sat, Crystallinity_limit = Crystallinity_limit, Suppress = Suppress,
539
+ Suppress_except=Suppress_except, trail = trail, melts = melts)
498
540
  else:
499
541
  if fO2_offset[i] is None:
500
542
  fO2_offset[i] = 0.0