PetThermoTools 0.2.32__py3-none-any.whl → 0.2.33__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
PetThermoTools/Barom.py CHANGED
@@ -10,6 +10,7 @@ from PetThermoTools.GenFuncs import *
10
10
  from PetThermoTools.Plotting import *
11
11
  from PetThermoTools.Liq import *
12
12
  from PetThermoTools.MELTS import *
13
+ from PetThermoTools.Path import *
13
14
  # try:
14
15
  # from PetThermoTools.Holland import *
15
16
  # except:
@@ -23,7 +24,212 @@ from tqdm.notebook import tqdm, trange
23
24
  from scipy import interpolate
24
25
  from shapely.geometry import MultiPoint, Point, Polygon
25
26
 
26
- 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
+
31
+ def run_melts_single(Pin, Model, comp, T_maxdrop_C, dt_C, T_initial_C,
32
+ fO2_buffer, fO2_offset, H2O_Sat, phases):
33
+ try:
34
+ return path_MELTS(
35
+ Model=Model,
36
+ comp=comp,
37
+ T_maxdrop_C=T_maxdrop_C,
38
+ dt_C=dt_C,
39
+ T_initial_C=T_initial_C,
40
+ P_bar=Pin,
41
+ find_liquidus=True,
42
+ fO2_buffer=fO2_buffer,
43
+ fO2_offset=fO2_offset,
44
+ fluid_sat=H2O_Sat,
45
+ Suppress=['rutile', 'tridymite'],
46
+ phases=phases
47
+ )
48
+ except Exception as e:
49
+ print(f"Failed at {Pin} bar: {e}")
50
+ return None
51
+
52
+ def mineral_cosaturation(Model="MELTSv1.0.2", cores=int(np.floor(multiprocessing.cpu_count()/2)), bulk=None,
53
+ phases=['quartz1', 'alkali-feldspar1', 'plagioclase1'],
54
+ P_bar=np.linspace(250, 5000, 32), Fe3Fet_init=None, H2O_init=None,
55
+ CO2_init=None, H2O_Sat=False, T_initial_C=None, dt_C=2,
56
+ T_maxdrop_C=50, T_cut_C=20, find_range=True,
57
+ find_min=True, fO2_buffer=None, fO2_offset=0.0, timeout = 30):
58
+
59
+ comp = bulk.copy()
60
+ if H2O_Sat:
61
+ comp['H2O_Liq'] = 20
62
+
63
+ comp = comp_fix(Model=Model, comp=comp, Fe3Fet_Liq=Fe3Fet_init,
64
+ H2O_Liq=H2O_init, CO2_Liq=CO2_init)
65
+
66
+ run_partial = partial(run_melts_single,
67
+ Model=Model, comp=comp, T_maxdrop_C=T_maxdrop_C,
68
+ dt_C=dt_C, T_initial_C=T_initial_C,
69
+ fO2_buffer=fO2_buffer, fO2_offset=fO2_offset,
70
+ H2O_Sat=H2O_Sat, phases=phases)
71
+
72
+ results = {}
73
+ with concurrent.futures.ProcessPoolExecutor(max_workers=cores) as executor:
74
+ futures = {executor.submit(run_partial, p): i for i, p in enumerate(P_bar)}
75
+
76
+ done, not_done = concurrent.futures.wait(
77
+ futures.keys(), timeout=timeout, return_when=concurrent.futures.ALL_COMPLETED
78
+ )
79
+
80
+ for future in done:
81
+ i = futures[future]
82
+ try:
83
+ results[f"P = {P_bar[i]:.2f} bars"] = future.result()
84
+ except Exception as e:
85
+ print(f"Failure at {P_bar[i]} bar: {e}")
86
+ results[f"P = {P_bar[i]:.2f} bars"] = {}
87
+
88
+ for future in not_done:
89
+ i = futures[future]
90
+ print(f"Timeout at {P_bar[i]} bar. Either the calculation was slow (increase timeout) or it failed.")
91
+ results[f"P = {P_bar[i]:.2f} bars"] = {}
92
+ future.cancel() # Cancel if still running
93
+
94
+ Results = stich(Res=results, multi=True, Model=Model)
95
+
96
+ ## determine the offset between the phases
97
+ if len(phases) == 3:
98
+ arr = np.zeros((len(Results.keys()), 4))
99
+ arr2 = np.zeros((len(Results.keys()), 4))
100
+ columns = ['P_bar'] + phases + [phases[0] + ' - ' + phases[1], phases[0] + ' - ' + phases[2], phases[1] + ' - ' + phases[2], '3 Phase Saturation']
101
+ for i, r in enumerate(Results.keys()):
102
+ for idx, p in enumerate(phases):
103
+ if p in Results[r]['Mass'].keys():
104
+ arr[i, idx+1] = Results[r]['Conditions'].loc[Results[r]['Mass'][p] > 0.0, 'T_C'].values[0]
105
+ else:
106
+ arr[i, idx + 1] = np.nan
107
+
108
+ arr[i,0] = Results[r]['Conditions']['P_bar'].loc[0]
109
+
110
+ arr2[:, 0] = np.abs(arr[:,1] - arr[:,2])
111
+ arr2[:, 1] = np.abs(arr[:,1] - arr[:,3])
112
+ arr2[:, 2] = np.abs(arr[:,2] - arr[:,3])
113
+ arr2[:,3] = np.max(arr2[:,0:2], axis = 1)
114
+
115
+ r_arr = np.hstack((arr,arr2))
116
+
117
+ out = pd.DataFrame(data = r_arr, columns = columns)
118
+ out = out.sort_values('P_bar').reset_index(drop=True)
119
+
120
+ else:
121
+ arr = np.zeros((len(Results.keys()),4))
122
+ columns = ['P_bar'] + phases + [phases[0]+' - '+phases[1]]
123
+ for i, r in enumerate(Results.keys()):
124
+ for idx, p in enumerate(phases):
125
+ if p in Results[r]['Mass'].keys():
126
+ arr[i, idx+1] = Results[r]['Conditions'].loc[Results[r]['Mass'][p] > 0.0, 'T_C'].values[0]
127
+ else:
128
+ arr[i, idx + 1] = np.nan
129
+
130
+ arr[i,0] = Results[r]['Conditions']['P_bar'].loc[0]
131
+
132
+ arr[:,3] = np.abs(arr[:,1] - arr[:,2])
133
+
134
+ out = pd.DataFrame(data = r_arr, columns = columns)
135
+ out = out.sort_values('P_bar').reset_index(drop=True)
136
+
137
+ if find_min:
138
+ res = findmin(out = out, P_bar = P_bar, T_cut_C = T_cut_C)
139
+ out = {'CurveMin': res, 'Output': out}
140
+ else:
141
+ out = {'Output': out}
142
+
143
+ return out, Results
144
+
145
+ def findmin(out = None, P_bar = None, T_cut_C = None):
146
+ Res = out.copy()
147
+
148
+ if '3 Phase Saturation' in list(Res.keys()):
149
+ T_cut_old = T_cut_C
150
+ T_cut_C = T_cut_C + np.nanmin(Res[4:])
151
+ Minimum = list(Res.keys())[4:]
152
+ CurveMin = {}
153
+ for m in Minimum:
154
+ if len(Res[m][~np.isnan(Res[m].values)]) > 2:
155
+ y = Res[m][(~np.isnan(Res[m].values)) & (Res[m].values < T_cut_C)].values
156
+ x = P_bar[(~np.isnan(Res[m].values)) & (Res[m].values < T_cut_C)]
157
+
158
+ try:
159
+ y_new = interpolate.UnivariateSpline(x, y, k = 3)
160
+
161
+ P_new = np.linspace(P_bar[P_bar == np.nanmin(P_bar[(~np.isnan(Res[m].values)) & (Res[m].values < T_cut_C)])],
162
+ P_bar[P_bar == np.nanmax(P_bar[(~np.isnan(Res[m].values)) & (Res[m].values < T_cut_C)])], 200)
163
+
164
+ NewMin = np.nanmin(y_new(P_new))
165
+ P_min = P_new[np.where(y_new(P_new) == NewMin)][0]
166
+ if NewMin < T_cut_old:
167
+ Test = 'Pass'
168
+ else:
169
+ Test = 'Fail'
170
+
171
+ CurveMin[m] = {'P_min': P_min, 'Res_min': NewMin, 'y_new': y_new(P_new), 'P_new': P_new, 'test': Test}
172
+ except:
173
+ try:
174
+ y_new = interpolate.UnivariateSpline(x, y, k = 2)
175
+
176
+ P_new = np.linspace(P_bar[P_bar == np.nanmin(P_bar[(~np.isnan(Res[m].values)) & (Res[m].values < T_cut_C)])],
177
+ P_bar[P_bar == np.nanmax(P_bar[(~np.isnan(Res[m].values)) & (Res[m].values < T_cut_C)])], 200)
178
+
179
+ NewMin = np.nanmin(y_new(P_new))
180
+ P_min = P_new[np.where(y_new(P_new) == NewMin)][0]
181
+ if NewMin < T_cut_old:
182
+ Test = 'Pass'
183
+ else:
184
+ Test = 'Fail'
185
+
186
+ CurveMin[m] = {'P_min': P_min, 'Res_min': NewMin, 'y_new': y_new(P_new), 'P_new': P_new, 'test': Test}
187
+ except:
188
+ CurveMin[m] = {'P_min': np.nan, 'Res_min': np.nan, 'y_new': np.nan, 'P_new': np.nan, 'test': 'Fail'}
189
+ else:
190
+ y_new = np.nan
191
+ P_new = np.nan
192
+ NewMin = np.nan
193
+ P_min = np.nan
194
+ Test = 'Fail'
195
+ CurveMin[m] = {'P_min': P_min, 'Res_min': NewMin, 'y_new': y_new, 'P_new': P_new, 'test': Test}
196
+
197
+ else:
198
+ CurveMin = {}
199
+ m = Res.keys()[3]
200
+ if len(Res[m][~np.isnan(Res[m])]) > 2:
201
+ y = Res[m][(~np.isnan(Res[m].values)) & (Res[m].values < T_cut_C*2)].values
202
+ x = P_bar[(~np.isnan(Res[m].values)) & (Res[m].values < T_cut_C*2)]
203
+
204
+ try:
205
+ y_new = interpolate.UnivariateSpline(x, y, k = 3)
206
+ except:
207
+ y_new = interpolate.UnivariateSpline(x, y, k = 2)
208
+
209
+ P_new = np.linspace(P_bar[P_bar == np.nanmin(P_bar[(~np.isnan(Res[m])) & (Res[m] < T_cut_C*2)])],
210
+ P_bar[P_bar == np.nanmax(P_bar[(~np.isnan(Res[m])) & (Res[m] < T_cut_C*2)])], 200)
211
+
212
+ NewMin = np.nanmin(y_new(P_new))
213
+ P_min = P_new[np.where(y_new(P_new) == NewMin)][0]
214
+ if NewMin < T_cut_C:
215
+ Test = 'Pass'
216
+ else:
217
+ Test = 'Fail'
218
+ else:
219
+ y_new = np.nan
220
+ P_new = np.nan
221
+ NewMin = np.nan
222
+ P_min = np.nan
223
+ Test = 'Fail'
224
+
225
+ CurveMin[m] = {'P_min': P_min, 'Res_min': NewMin, 'y_new': y_new, 'P_new': P_new, 'test': Test}
226
+
227
+ return CurveMin
228
+
229
+
230
+ def find_mineral_cosaturation(cores = None, Model = None, bulk = None, phases = None, P_bar = None, Fe3Fet_Liq = None,
231
+ H2O_Liq = None, H2O_Sat = False, T_initial_C = None, dt_C = None, T_maxdrop_C = None,
232
+ T_cut_C = None, find_range = None, find_min = None, fO2_buffer = None, fO2_offset = None):
27
233
  '''
28
234
  Carry out multiple calculations in parallel. Allows isobaric, polybaric and isochoric crystallisation to be performed as well as isothermal, isenthalpic or isentropic decompression. All temperature inputs/outputs are reported in degrees celcius and pressure is reported in bars.
29
235
 
@@ -621,406 +827,3 @@ def satTemperature(q, index, *, Model = None, comp = None, phases = None, T_init
621
827
  return
622
828
 
623
829
 
624
- # def detRange(P, Model, bulk, Results, Phases, T_initial = None, Fe3 = None, H2O = None, T_cut = None, findRange = None, cores = None):
625
- # '''
626
- # re-run the SatPress calculations using a higher resolution to determine the range of P (+H2O +fO2) where the maximum difference between the target saturation curve is below some reference value.
627
- # '''
628
- # if T_cut is None:
629
- # T_cut = 5
630
- #
631
- # if T_initial is None:
632
- # T_initial = 1200
633
- #
634
- # Res_key = list(Results.keys())[:-2]
635
- #
636
- # if Fe3 is None and H2O is None:
637
- # P_min = np.zeros(len(Res_key))
638
- # P_max = np.zeros(len(Res_key))
639
- # i = 0
640
- # for Res in Res_key:
641
- # if len(Results[Res][np.where(Results[Res]<T_cut*2)]) > 0:
642
- # P_min[i] = np.nanmin(P[np.where(Results[Res]<T_cut*2)])
643
- # P_max[i] = np.nanmax(P[np.where(Results[Res]<T_cut*2)])
644
- # else:
645
- # P_min[i] = np.nan
646
- # P_max[i] = np.nan
647
- #
648
- # i = i + 1
649
- #
650
- # P_start = np.nanmin(P_min)
651
- # P_end = np.nanmax(P_max)
652
- #
653
- # P_space = 1 + 3*(P_end - P_start)/((np.max(P) - np.min(P))/(len(P)-1))
654
- #
655
- # P = np.linspace(P_start, P_end, int(P_space))
656
- #
657
- # with open('bulk.obj', 'wb') as f:
658
- # pickle.dump(bulk, f)
659
- #
660
- # if len(Phases) == 3:
661
- # phases[0], b_Sat, c_Sat, T_Liq, H2O_Melt = findSat(P, Model, Phases, bulk, T_initial = T_initial, dt = T_cut, T_step = T_cut, cores = cores)
662
- # else:
663
- # phases[0], b_Sat, T_Liq, H2O_Melt = findSat(P, Model, Phases, bulk, T_initial = T_initial, dt = T_cut, T_step = T_cut, cores = cores)
664
- #
665
- # # calc residuals
666
- # if len(Phases) == 3:
667
- # Results_new = findResiduals(phases[0], b_Sat, c_Sat = c_Sat)
668
- # else:
669
- # Results_new = findResiduals(phases[0], b_Sat)
670
- #
671
- # Results_new['H2O_sat'] = H2O_Melt
672
- # Results_new['T_Liq'] = T_Liq
673
- #
674
- # for Res in Res_key:
675
- # if len(Results_new[Res][np.where(~np.isnan(Results_new[Res]))]) > 0:
676
- # Results_new[Res + '_min_P'] = np.nanmin(P[~np.isnan(Results_new[Res])])
677
- # Results_new[Res + '_max_P'] = np.nanmin(P[~np.isnan(Results_new[Res])])
678
- # else:
679
- # Results_new[Res + '_min_P'] = np.nan
680
- # Results_new[Res + '_max_P'] = np.nan
681
- #
682
- # return Results_new
683
- #
684
- # if Fe3 is not None and H2O is None:
685
- # P_min = np.zeros(len(Res_key))
686
- # P_max = np.zeros(len(Res_key))
687
- #
688
- # Fe3_min = np.zeros(len(Res_key))
689
- # Fe3_max = np.zeros(len(Res_key))
690
- #
691
- # P_mat, Fe3_mat = np.meshgrid(P, Fe3)
692
- #
693
- # i = 0
694
- # for Res in Res_key:
695
- # if len(Results[Res][np.where(Results[Res]<T_cut*2)]) > 0:
696
- # P_min[i] = np.nanmin(P_mat[np.where(Results[Res]<T_cut*2)])
697
- # P_max[i] = np.nanmax(P_mat[np.where(Results[Res]<T_cut*2)])
698
- #
699
- # Fe3_min[i] = np.nanmin(Fe3_mat[np.where(Results[Res]<T_cut*2)])
700
- # Fe3_max[i] = np.nanmax(Fe3_mat[np.where(Results[Res]<T_cut*2)])
701
- # else:
702
- #
703
- # P_min[i] = np.nan
704
- # P_max[i] = np.nan
705
- #
706
- # Fe3_min[i] = np.nan
707
- # Fe3_max[i] = np.nan
708
- #
709
- # i = i + 1
710
- #
711
- # P_start = np.nanmin(P_min)
712
- # P_end = np.nanmax(P_max)
713
- #
714
- # Fe3_start = np.nanmin(Fe3_min)
715
- # Fe3_end = np.nanmax(Fe3_max)
716
- #
717
- # P = np.linspace(P_start, P_end, int(1 + 3*(P_end - P_start)/((np.max(P) - np.min(P))/(len(P)-1))))
718
- # Fe3 = np.linspace(Fe3_start, Fe3_end, int(1 + 3*(Fe3_end - Fe3_start)/((np.max(Fe3) - np.min(Fe3))/(len(Fe3)-1))))
719
- #
720
- # if len(Phases) == 3:
721
- # Res_abc_mat = np.zeros((len(Fe3), len(P)))
722
- # Res_ac_mat = np.zeros((len(Fe3), len(P)))
723
- # Res_bc_mat = np.zeros((len(Fe3), len(P)))
724
- #
725
- # Res_ab_mat = np.zeros((len(Fe3), len(P)))
726
- # H2O_mat = np.zeros((len(Fe3), len(P)))
727
- # T_Liq_mat = np.zeros((len(Fe3), len(P)))
728
- #
729
- # for i in range(len(Fe3)):
730
- # Bulk_new = bulk.copy()
731
- # Bulk_new[3] = Fe3[i]*((159.69/2)/71.844)*bulk[5]
732
- # Bulk_new[5] = (1-Fe3[i])*bulk[5]
733
- #
734
- # with open('bulk.obj', 'wb') as f:
735
- # pickle.dump(Bulk_new, f)
736
- #
737
- # if len(Phases) == 3:
738
- # phases[0], b_Sat, c_Sat, T_Liq, H2O_Melt = findSat(P, Model, Phases, bulk, T_initial = T_initial, dt = T_cut, T_step = T_cut, cores = cores)
739
- # else:
740
- # phases[0], b_Sat, T_Liq, H2O_Melt = findSat(P, Model, Phases, bulk, T_initial = T_initial, dt = T_cut, T_step = T_cut, cores = cores)
741
- #
742
- # # calc residuals
743
- # if len(Phases) == 3:
744
- # Res = findResiduals(phases[0], b_Sat, c_Sat = c_Sat)
745
- # Res_abc_mat[i, :] = Res['abc']
746
- # Res_ac_mat[i, :] = Res['ac']
747
- # Res_bc_mat[i, :] = Res['bc']
748
- # else:
749
- # Res = findResiduals(phases[0], b_Sat)
750
- #
751
- # T_Liq_mat[i, :] = T_Liq
752
- # H2O_mat[i, :] = H2O_Melt
753
- # Res_ab_mat[i, :] = Res['ab']
754
- #
755
- # if len(Phases) == 3:
756
- # Results_new = {'abc': Res_abc_mat, 'ab': Res_ab_mat, 'ac': Res_ac_mat, 'bc': Res_bc_mat, 'H2O_Sat': H2O_mat, 'T_Liq': T_Liq_mat}
757
- # else:
758
- # Results_new = {'ab': Res_ab_mat, 'H2O_Sat': H2O_mat, 'T_Liq': T_Liq_mat}
759
- #
760
- # P_mat, Fe3_mat = np.meshgrid(P, Fe3)
761
- # for Res in Res_key:
762
- # if len(Results_new[Res][np.where(~np.isnan(Results_new[Res]))]) > 0:
763
- # Results_new[Res + '_min_P'] = np.nanmin(P_mat[np.where(~np.isnan(Results_new[Res]))])
764
- # Results_new[Res + '_max_P'] = np.nanmin(P_mat[np.where(~np.isnan(Results_new[Res]))])
765
- #
766
- # Results_new[Res + '_min_Fe3'] = np.nanmin(Fe3_mat[np.where(~np.isnan(Results_new[Res]))])
767
- # Results_new[Res + '_max_Fe3'] = np.nanmin(Fe3_mat[np.where(~np.isnan(Results_new[Res]))])
768
- # else:
769
- # Results_new[Res + '_min_P'] = np.nan
770
- # Results_new[Res + '_max_P'] = np.nan
771
- #
772
- # Results_new[Res + '_min_Fe3'] = np.nan
773
- # Results_new[Res + '_max_Fe3'] = np.nan
774
- #
775
- # return Results_new
776
- #
777
- # if Fe3 is None and H2O is not None:
778
- # P_min = np.zeros(len(Res_key))
779
- # P_max = np.zeros(len(Res_key))
780
- #
781
- # H2O_min = np.zeros(len(Res_key))
782
- # H2O_max = np.zeros(len(Res_key))
783
- #
784
- # P_mat, H2O_mat = np.meshgrid(P, H2O)
785
- #
786
- # i = 0
787
- # for Res in Res_key:
788
- # if len(Results[Res][np.where(Results[Res]<T_cut*2)]) > 0:
789
- # P_min[i] = np.nanmin(P_mat[np.where(Results[Res]<T_cut*2)])
790
- # P_max[i] = np.nanmax(P_mat[np.where(Results[Res]<T_cut*2)])
791
- #
792
- # H2O_min[i] = np.nanmin(H2O_mat[np.where(Results[Res]<T_cut*2)])
793
- # H2O_max[i] = np.nanmax(H2O_mat[np.where(Results[Res]<T_cut*2)])
794
- # else:
795
- #
796
- # P_min[i] = np.nan
797
- # P_max[i] = np.nan
798
- #
799
- # H2O_min[i] = np.nan
800
- # H2O_max[i] = np.nan
801
- #
802
- # i = i + 1
803
- #
804
- # P_start = np.nanmin(P_min)
805
- # P_end = np.nanmax(P_max)
806
- #
807
- # H2O_start = np.nanmin(H2O_min)
808
- # H2O_end = np.nanmax(H2O_max)
809
- #
810
- # P = np.linspace(P_start, P_end, int(1 + 3*(P_end - P_start)/((np.max(P) - np.min(P))/(len(P)-1))))
811
- # H2O = np.linspace(H2O_start, H2O_end, int(1 + 3*(H2O_end - H2O_start)/((np.max(H2O) - np.min(H2O))/(len(H2O)-1))))
812
- #
813
- # if len(Phases) == 3:
814
- # Res_abc_mat = np.zeros((len(H2O), len(P)))
815
- # Res_ac_mat = np.zeros((len(H2O), len(P)))
816
- # Res_bc_mat = np.zeros((len(H2O), len(P)))
817
- #
818
- # Res_ab_mat = np.zeros((len(H2O), len(P)))
819
- # H2O_mat = np.zeros((len(H2O), len(P)))
820
- # T_Liq_mat = np.zeros((len(H2O), len(P)))
821
- #
822
- # for i in range(len(H2O)):
823
- # Bulk_new = bulk.copy()
824
- # Bulk_new[14] = H2O[i]
825
- #
826
- # with open('bulk.obj', 'wb') as f:
827
- # pickle.dump(Bulk_new, f)
828
- #
829
- # if len(Phases) == 3:
830
- # phases[0], b_Sat, c_Sat, T_Liq, H2O_Melt = findSat(P, Model, Phases, bulk, T_initial = T_initial, dt = T_cut, T_step = T_cut, cores = cores)
831
- # else:
832
- # phases[0], b_Sat, T_Liq, H2O_Melt = findSat(P, Model, Phases, bulk, T_initial = T_initial, dt = T_cut, T_step = T_cut, cores = cores)
833
- #
834
- # # calc residuals
835
- # if len(Phases) == 3:
836
- # Res = findResiduals(phases[0], b_Sat, c_Sat = c_Sat)
837
- # Res_abc_mat[i, :] = Res['abc']
838
- # Res_ac_mat[i, :] = Res['ac']
839
- # Res_bc_mat[i, :] = Res['bc']
840
- # else:
841
- # Res = findResiduals(phases[0], b_Sat)
842
- #
843
- # T_Liq_mat[i, :] = T_Liq
844
- # H2O_mat[i, :] = H2O_Melt
845
- # Res_ab_mat[i, :] = Res['ab']
846
- #
847
- # if len(Phases) == 3:
848
- # Results_new = {'abc': Res_abc_mat, 'ab': Res_ab_mat, 'ac': Res_ac_mat, 'bc': Res_bc_mat, 'H2O_Sat': H2O_mat, 'T_Liq': T_Liq_mat}
849
- # else:
850
- # Results_new = {'ab': Res_ab_mat, 'H2O_Sat': H2O_mat, 'T_Liq': T_Liq_mat}
851
- #
852
- # P_mat, H2O_mat = np.meshgrid(P, H2O)
853
- # for Res in Res_key:
854
- # if len(Results_new[Res][np.where(~np.isnan(Results_new[Res]))]) > 0:
855
- # Results_new[Res + '_min_P']= np.nanmin(P_mat[np.where(~np.isnan(Results_new[Res]))])
856
- # Results_new[Res + '_max_P'] = np.nanmin(P_mat[np.where(~np.isnan(Results_new[Res]))])
857
- #
858
- # Results_new[Res + '_min_H2O'] = np.nanmin(Results_new['H2O_Sat'][np.where(~np.isnan(Results_new[Res]))])
859
- # Results_new[Res + '_max_H2O'] = np.nanmin(Results_new['H2O_Sat'][np.where(~np.isnan(Results_new[Res]))])
860
- # else:
861
- # Results_new[Res + '_min_P']= np.nan
862
- # Results_new[Res + '_max_P'] = np.nan
863
- #
864
- # Results_new[Res + '_min_H2O'] = np.nan
865
- # Results_new[Res + '_max_H2O'] = np.nan
866
- #
867
- # return Results_new
868
- #
869
- # if H2O is not None and Fe3 is not None:
870
- # Results_new = {}
871
- # P_min = np.zeros(len(Res_key))
872
- # P_max = np.zeros(len(Res_key))
873
- #
874
- # Fe3_min = np.zeros(len(Res_key))
875
- # Fe3_max = np.zeros(len(Res_key))
876
- #
877
- # H2O_min = np.zeros(len(Res_key))
878
- # H2O_max = np.zeros(len(Res_key))
879
- #
880
- # Fe3_mat, H2O_mat, P_mat = np.meshgrid(Fe3, H2O, P)
881
- #
882
- # i = 0
883
- # for Res in Res_key:
884
- # if len(Results[Res][np.where(Results[Res]<T_cut*2)]) > 0:
885
- # P_min[i] = np.nanmin(P_mat[np.where(Results[Res]<T_cut*2)])
886
- # P_max[i] = np.nanmax(P_mat[np.where(Results[Res]<T_cut*2)])
887
- #
888
- # H2O_min[i] = np.nanmin(H2O_mat[np.where(Results[Res]<T_cut*2)])
889
- # H2O_max[i] = np.nanmax(H2O_mat[np.where(Results[Res]<T_cut*2)])
890
- #
891
- # Fe3_min[i] = np.nanmin(Fe3_mat[np.where(Results[Res]<T_cut*2)])
892
- # Fe3_max[i] = np.nanmax(Fe3_mat[np.where(Results[Res]<T_cut*2)])
893
- # else:
894
- #
895
- # P_min[i] = np.nan
896
- # P_max[i] = np.nan
897
- #
898
- # H2O_min[i] = np.nan
899
- # H2O_max[i] = np.nan
900
- #
901
- # Fe3_min[i] = np.nan
902
- # Fe3_max[i] = np.nan
903
- #
904
- # i = i + 1
905
- #
906
- # if findRange == 'abc':
907
- # P_start = P_min[0] - (P[1] - P[0])/3
908
- # P_end = P_max[0] + (P[1] - P[0])/3
909
- #
910
- # H2O_start = H2O_min[0] - (H2O[1] - H2O[0])/3
911
- # H2O_end = H2O_max[0] + (H2O[1] - H2O[0])/3
912
- #
913
- # Fe3_start = Fe3_min[0] - (Fe3[1] - Fe3[0])/3
914
- # Fe3_end = Fe3_max[0] + (Fe3[1] - Fe3[0])/3
915
- # else:
916
- # P_start = np.nanmin(P_min)
917
- # P_end = np.nanmax(P_max)
918
- #
919
- # H2O_start = np.nanmin(H2O_min)
920
- # H2O_end = np.nanmax(H2O_max)
921
- #
922
- # Fe3_start = np.nanmin(Fe3_min)
923
- # Fe3_end = np.nanmax(Fe3_max)
924
- #
925
- # if P_end - P_start > 0:
926
- # P = np.linspace(P_start, P_end, int(1 + 3*(P_end - P_start)/((np.max(P) - np.min(P))/(len(P)))))
927
- # else:
928
- # return Results_new
929
- #
930
- # if H2O_end - H2O_start > 0:
931
- # H2O = np.linspace(H2O_start, H2O_end, int(1 + 3*(H2O_end - H2O_start)/((np.max(H2O) - np.min(H2O))/(len(H2O)))))
932
- # else:
933
- # return Results_new
934
- #
935
- # if Fe3_end - Fe3_start > 0:
936
- # Fe3 = np.linspace(Fe3_start, Fe3_end, int(1 + 3*(Fe3_end - Fe3_start)/((np.max(Fe3) - np.min(Fe3))/(len(Fe3)))))
937
- # else:
938
- # return Results_new
939
- #
940
- # if len(Phases) == 3:
941
- # Res_abc_mat = np.zeros((len(H2O), len(Fe3), len(P)))
942
- # Res_ac_mat = np.zeros((len(H2O), len(Fe3), len(P)))
943
- # Res_bc_mat = np.zeros((len(H2O), len(Fe3), len(P)))
944
- #
945
- # Res_ab_mat = np.zeros((len(H2O), len(Fe3), len(P)))
946
- # T_Liq_3Dmat = np.zeros((len(H2O), len(Fe3), len(P)))
947
- # H2O_Liq_3Dmat = np.zeros((len(H2O), len(Fe3), len(P)))
948
- #
949
- # for i in range(len(H2O)):
950
- # Bulk_new = bulk.copy()
951
- # Bulk_new[14] = H2O[i]
952
- #
953
- # if len(Phases) == 3:
954
- # Res_abc_mat_2D = np.zeros((len(Fe3), len(P)))
955
- # Res_ac_mat_2D = np.zeros((len(Fe3), len(P)))
956
- # Res_bc_mat_2D = np.zeros((len(Fe3), len(P)))
957
- #
958
- # Res_ab_mat_2D = np.zeros((len(Fe3), len(P)))
959
- # T_Liq_mat_2D = np.zeros((len(Fe3), len(P)))
960
- # H2O_Liq_mat_2D = np.zeros((len(Fe3), len(P)))
961
- #
962
- # for j in range(len(Fe3)):
963
- #
964
- # Bulk_new[3] = Fe3[j]*((159.69/2)/71.844)*bulk[5]
965
- # Bulk_new[5] = (1-Fe3[j])*bulk[5]
966
- #
967
- # with open('bulk.obj', 'wb') as f:
968
- # pickle.dump(Bulk_new, f)
969
- #
970
- # if len(Phases) == 3:
971
- # phases[0], b_Sat, c_Sat, T_Liq, H2O_Melt = findSat(P, Model, Phases, Bulk_new, T_initial = T_initial, dt = T_cut, T_step = T_cut, cores = cores)
972
- # else:
973
- # phases[0], b_Sat, T_Liq, H2O_Melt = findSat(P, Model, Phases, Bulk_new, T_initial = T_initial, dt = T_cut, T_step = T_cut, cores = cores)
974
- #
975
- # # calc residuals
976
- # if len(Phases) == 3:
977
- # Res = findResiduals(phases[0], b_Sat, c_Sat = c_Sat)
978
- # Res_abc_mat_2D[j, :] = Res['abc']
979
- # Res_ac_mat_2D[j, :] = Res['ac']
980
- # Res_bc_mat_2D[j, :] = Res['bc']
981
- # else:
982
- # Res = findResiduals(phases[0], b_Sat)
983
- #
984
- # Res_ab_mat_2D[j, :] = Res['ab']
985
- # T_Liq_mat_2D[j, :] = T_Liq
986
- # H2O_Liq_mat_2D[j, :] = H2O_Melt
987
- #
988
- # if len(Phases) == 3:
989
- # Res_abc_mat[i,:,:] = Res_abc_mat_2D
990
- # Res_ac_mat[i,:,:] = Res_ac_mat_2D
991
- # Res_bc_mat[i,:,:] = Res_bc_mat_2D
992
- #
993
- # Res_ab_mat[i,:,:] = Res_ab_mat_2D
994
- # T_Liq_3Dmat[i,:,:] = T_Liq_mat_2D
995
- # H2O_Liq_3Dmat[i,:,:] = H2O_Liq_mat_2D
996
- #
997
- # if len(Phases) == 3:
998
- # Results_new = {'abc': Res_abc_mat, 'ab': Res_ab_mat, 'ac': Res_ac_mat, 'bc': Res_bc_mat, 'H2O_Sat': H2O_Liq_3Dmat, 'T_Liq': T_Liq_3Dmat}
999
- # else:
1000
- # Results_new = {'ab': Res_ab_mat, 'H2O_Sat': H2O_Liq_3Dmat, 'T_Liq': T_Liq_3Dmat}
1001
- #
1002
- #
1003
- # Fe3_mat, H2O_mat, P_mat = np.meshgrid(Fe3, H2O, P)
1004
- #
1005
- # for Res in Res_key:
1006
- # if len(Results_new[Res][np.where(~np.isnan(Results_new[Res]))]) > 0:
1007
- # Results_new[Res + '_min_P'] = np.nanmin(P_mat[np.where(~np.isnan(Results_new[Res]))])
1008
- # Results_new[Res + '_max_P'] = np.nanmax(P_mat[np.where(~np.isnan(Results_new[Res]))])
1009
- #
1010
- # Results_new[Res + '_min_H2O'] = np.nanmin(Results_new['H2O_Sat'][np.where(~np.isnan(Results_new[Res]))])
1011
- # Results_new[Res + '_max_H2O'] = np.nanmax(Results_new['H2O_Sat'][np.where(~np.isnan(Results_new[Res]))])
1012
- #
1013
- # Results_new[Res + '_min_Fe3'] = np.nanmin(Fe3_mat[np.where(~np.isnan(Results_new[Res]))])
1014
- # Results_new[Res + '_max_Fe3'] = np.nanmax(Fe3_mat[np.where(~np.isnan(Results_new[Res]))])
1015
- # else:
1016
- # Results_new[Res + '_min_P'] = np.nan
1017
- # Results_new[Res + '_max_P'] = np.nan
1018
- #
1019
- # Results_new[Res + '_min_H2O'] = np.nan
1020
- # Results_new[Res + '_max_H2O'] = np.nan
1021
- #
1022
- # Results_new[Res + '_min_Fe3'] = np.nan
1023
- # Results_new[Res + '_max_Fe3'] = np.nan
1024
- #
1025
- # return Results_new
1026
-
PetThermoTools/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):
810
812
  '''
811
813
  Perform a single calculation in MELTS. WARNING! Running this function directly from the command land/jupyter notebook will initiate the MELTS C library in the main python process. Once this has been initiated the MELTS C library cannot be re-loaded and failures during the calculation will likely cause a terminal error to occur.
812
814
 
@@ -946,18 +948,21 @@ def path_MELTS(Model = None, comp = None, Frac_solid = None, Frac_fluid = None,
946
948
  if P_path_bar is not None:
947
949
  try:
948
950
  if type(P_path_bar) == np.ndarray:
949
- Liq_Results = findLiq_MELTS(P_bar = P_path_bar[0], comp = bulk, melts = melts, fO2_buffer = fO2_buffer, fO2_offset = fO2_offset, T_C_init = 1400)
951
+ Liq_Results = findLiq_MELTS(P_bar = P_path_bar[0], comp = bulk, melts = melts, fO2_buffer = fO2_buffer, fO2_offset = fO2_offset, T_C_init = T_initial_C)
950
952
  else:
951
- Liq_Results = findLiq_MELTS(P_bar = P_path_bar, comp = bulk, melts = melts, fO2_buffer = fO2_buffer, fO2_offset = fO2_offset, T_C_init = 1400)
953
+ Liq_Results = findLiq_MELTS(P_bar = P_path_bar, comp = bulk, melts = melts, fO2_buffer = fO2_buffer, fO2_offset = fO2_offset, T_C_init = T_initial_C)
952
954
  except:
953
955
  return Results
954
956
  elif P_start_bar is not None:
955
957
  try:
956
- Liq_Results = findLiq_MELTS(P_bar = P_start_bar, comp = bulk, melts = melts, fO2_buffer = fO2_buffer, fO2_offset = fO2_offset, T_C_init = 1400)
958
+ Liq_Results = findLiq_MELTS(P_bar = P_start_bar, comp = bulk, melts = melts, fO2_buffer = fO2_buffer, fO2_offset = fO2_offset, T_C_init = T_initial_C)
957
959
  except:
958
960
  return Results
959
961
 
962
+ print(Liq_Results)
960
963
  T_start_C = Liq_Results['T_Liq'] + 0.1
964
+ if T_end_C is None and T_maxdrop_C is not None:
965
+ T_end_C = T_start_C - T_maxdrop_C
961
966
 
962
967
  else:
963
968
  if fO2_buffer is not None:
@@ -1155,6 +1160,15 @@ def path_MELTS(Model = None, comp = None, Frac_solid = None, Frac_fluid = None,
1155
1160
  if Volume/Total_volume > Crystallinity_limit:
1156
1161
  break
1157
1162
 
1163
+ if phases is not None:
1164
+ ll = 0
1165
+ for p in phases:
1166
+ if p in Results.keys():
1167
+ ll = ll + 1
1168
+
1169
+ if ll == len(phases):
1170
+ break
1171
+
1158
1172
  melts = melts.addNodeAfter()
1159
1173
 
1160
1174
  return Results
@@ -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.33'
@@ -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.33
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=zfRgGnqInXP1B5oG_k5ZMJH3cylHcQXWiBRz7YlQjkw,36119
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=hqc5vSDwvnCyBwD7wbEOwemUNpDQGpsWdOOoVjNnMvE,72810
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=i2Na-DPnshyTFid0Y6FmelIcA0OHEcYVuQdFt_mKzeI,296
16
+ PetThermoTools-0.2.33.dist-info/LICENSE.txt,sha256=-mkx4iEw8Pk1RZUvncBhGLW87Uur5JB7FBQtOmX-VP0,1752
17
+ PetThermoTools-0.2.33.dist-info/METADATA,sha256=MM-RsleOmZq3PfygLozR2VrdewAuBMezGJLwnGc9Km8,796
18
+ PetThermoTools-0.2.33.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
19
+ PetThermoTools-0.2.33.dist-info/top_level.txt,sha256=IqK8iYBR3YJozzMOTRZ8x8mU2k6x8ycoMBxZTm-I06U,15
20
+ PetThermoTools-0.2.33.dist-info/RECORD,,