DiadFit 0.0.84__py3-none-any.whl → 0.0.88__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.
Files changed (35) hide show
  1. DiadFit/CO2_EOS.py +2 -2
  2. DiadFit/CO2_H2O_EOS.py +173 -90
  3. DiadFit/CO2_in_bubble_error.py +217 -115
  4. DiadFit/Highrho_polyfit_dataUCB_1117_1400.pkl +0 -0
  5. DiadFit/Highrho_polyfit_dataUCB_1117_1447.pkl +0 -0
  6. DiadFit/Highrho_polyfit_dataUCB_1220_1400.pkl +0 -0
  7. DiadFit/Highrho_polyfit_dataUCB_1220_1447.pkl +0 -0
  8. DiadFit/Highrho_polyfit_dataUCB_1220_1567.pkl +0 -0
  9. DiadFit/Highrho_polyfit_data_CMASS_24C.pkl +0 -0
  10. DiadFit/Lowrho_polyfit_dataUCB_1117_1400.pkl +0 -0
  11. DiadFit/Lowrho_polyfit_dataUCB_1117_1447.pkl +0 -0
  12. DiadFit/Lowrho_polyfit_dataUCB_1220_1400.pkl +0 -0
  13. DiadFit/Lowrho_polyfit_dataUCB_1220_1447.pkl +0 -0
  14. DiadFit/Lowrho_polyfit_dataUCB_1220_1567.pkl +0 -0
  15. DiadFit/Lowrho_polyfit_data_CMASS_24C.pkl +0 -0
  16. DiadFit/Mediumrho_polyfit_dataUCB_1117_1400.pkl +0 -0
  17. DiadFit/Mediumrho_polyfit_dataUCB_1117_1447.pkl +0 -0
  18. DiadFit/Mediumrho_polyfit_dataUCB_1220_1400.pkl +0 -0
  19. DiadFit/Mediumrho_polyfit_dataUCB_1220_1447.pkl +0 -0
  20. DiadFit/Mediumrho_polyfit_dataUCB_1220_1567.pkl +0 -0
  21. DiadFit/_version.py +1 -1
  22. DiadFit/densimeter_fitting.py +7 -1
  23. DiadFit/densimeters.py +182 -40
  24. DiadFit/density_depth_crustal_profiles.py +37 -5
  25. DiadFit/diads.py +85 -48
  26. DiadFit/error_propagation.py +141 -229
  27. DiadFit/importing_data_files.py +81 -15
  28. DiadFit/lookup_table.csv +64001 -0
  29. DiadFit/lookup_table_noneg.csv +63707 -0
  30. DiadFit/ne_lines.py +58 -29
  31. {DiadFit-0.0.84.dist-info → DiadFit-0.0.88.dist-info}/METADATA +1 -1
  32. DiadFit-0.0.88.dist-info/RECORD +50 -0
  33. {DiadFit-0.0.84.dist-info → DiadFit-0.0.88.dist-info}/WHEEL +1 -1
  34. DiadFit-0.0.84.dist-info/RECORD +0 -40
  35. {DiadFit-0.0.84.dist-info → DiadFit-0.0.88.dist-info}/top_level.txt +0 -0
DiadFit/CO2_EOS.py CHANGED
@@ -829,7 +829,7 @@ def calculate_SP19942(T_K, target_pressure_MPa):
829
829
  target_p=np.array(target_pressure_MPa)
830
830
  Density=calculate_Density_Sterner_Pitzer_1994(T_K=T_K, target_pressure_MPa=target_p)
831
831
  else:
832
- Density=np.empty(len(target_pressure_MPa))
832
+ Density=np.zeros(len(target_pressure_MPa))
833
833
  for i in range(0, len(target_pressure_MPa)):
834
834
  Density[i]=calculate_Density_Sterner_Pitzer_1994(T_K=T_K, target_pressure_MPa=target_pressure_MPa[i])
835
835
  return Density
@@ -860,7 +860,7 @@ def calculate_SP1994_Temp(CO2_dens_gcm3, target_pressure_MPa):
860
860
  target_p=np.array(target_pressure_MPa)
861
861
  Density=calculate_Temp_Sterner_Pitzer_1994(CO2_dens_gcm3=CO2_dens_gcm3, target_pressure_MPa=target_p)
862
862
  else:
863
- Density=np.empty(len(target_pressure_MPa))
863
+ Density=np.zeros(len(target_pressure_MPa))
864
864
  for i in range(0, len(target_pressure_MPa)):
865
865
  Density[i]=calculate_Temp_Sterner_Pitzer_1994(CO2_dens_gcm3=CO2_dens_gcm3, target_pressure_MPa=target_pressure_MPa[i])
866
866
  return Density
DiadFit/CO2_H2O_EOS.py CHANGED
@@ -102,45 +102,7 @@ aH2[13] = -4.13039220 / 10**1 # alpha for CO2
102
102
  aH2[14] = -8.47988634 # beta for CO2
103
103
  aH2[15] = 2.800 / 10**2 # gamma for CO2
104
104
 
105
- ## This is for when you only feed a numpy array
106
- # def ensure_series(a, b, c):
107
- # # Determine the target length
108
- # lengths = [len(a) if isinstance(a, pd.Series) else None,
109
- # len(b) if isinstance(b, pd.Series) else None,
110
- # len(c) if isinstance(c, pd.Series) else None]
111
- # lengths = [l for l in lengths if l is not None]
112
- # target_length = max(lengths) if lengths else 1
113
- #
114
- # # Convert each input to a Series of the target length
115
- # if not isinstance(a, pd.Series):
116
- # a = pd.Series([a] * target_length)
117
- # if not isinstance(b, pd.Series):
118
- # b = pd.Series([b] * target_length)
119
- # if not isinstance(c, pd.Series):
120
- # c = pd.Series([c] * target_length)
121
- #
122
- # return a, b, c
123
- #
124
- #
125
- # def ensure_series_4(a, b, c, d):
126
- # # Determine the target length
127
- # lengths = [len(a) if isinstance(a, pd.Series) else None,
128
- # len(b) if isinstance(b, pd.Series) else None,
129
- # len(c) if isinstance(c, pd.Series) else None,
130
- # len(d) if isinstance(d, pd.Series) else None]
131
- # lengths = [l for l in lengths if l is not None]
132
- # target_length = max(lengths) if lengths else 1
133
- #
134
- # # Convert each input to a Series of the target length
135
- # if not isinstance(a, pd.Series):
136
- # a = pd.Series([a] * target_length)
137
- # if not isinstance(b, pd.Series):
138
- # b = pd.Series([b] * target_length)
139
- # if not isinstance(c, pd.Series):
140
- # c = pd.Series([c] * target_length)
141
- # if not isinstance(d, pd.Series):
142
- # d = pd.Series([d] * target_length)
143
- # return a, b, c, d
105
+
144
106
 
145
107
  import pandas as pd
146
108
  import numpy as np
@@ -257,7 +219,7 @@ def pureEOS_CF(i, V, P, B, C, D, E, F, Vc, TK, b, g):
257
219
 
258
220
  # Volume iterative function using Netwon-Raphson method.
259
221
  def purevolume(i, V, P, B, C, D, E, F, Vc, TK, b, g):
260
- """ Using the pure EOS, this function solves for the best volume using the pureEOS residual calculated above
222
+ """ Using the pure EOS, this function solves for the best molar volume (in cm3/mol) using the pureEOS residual calculated above
261
223
 
262
224
  It returns the volume.
263
225
 
@@ -280,9 +242,9 @@ def purevolume(i, V, P, B, C, D, E, F, Vc, TK, b, g):
280
242
  return V
281
243
 
282
244
  def purepressure(i, V, P, TK):
283
- """ Using the pure EOS, this function solves for the best pressure using the pureEOS residual calculated above
245
+ """ Using the pure EOS, this function solves for the best pressure (in bars) using the pureEOS residual calculated above
284
246
 
285
- It returns the pressure.
247
+ It returns the pressure in bars
286
248
 
287
249
  """
288
250
  for iter in range(1, 51):
@@ -294,6 +256,10 @@ def purepressure(i, V, P, TK):
294
256
  # Update the pressure using the Newton-Raphson method
295
257
  Pnew = P - pureEOS(i, V, P, B, C, D, E, F, Vc, TK, b, g) / diff
296
258
 
259
+ # Dont allow negative solutions
260
+ if Pnew < 0:
261
+ Pnew = 30000
262
+
297
263
  # Check if the update is within the tolerance (0.000001)
298
264
  if abs(Pnew - P) <= 0.000001:
299
265
  break
@@ -308,13 +274,13 @@ def purepressure(i, V, P, TK):
308
274
 
309
275
 
310
276
  def mol_vol_to_density(mol_vol, XH2O):
311
- """ Converts molar mass to molar density for a given XH2O"""
277
+ """ Converts molar volume (cm3/mol) to density (g/cm3) for a given XH2O"""
312
278
  density=((1-XH2O)*44 + (XH2O)*18)/mol_vol
313
279
  return density
314
280
 
315
281
  def pure_lnphi(i, Z, B, Vc, V, C, D, E, F, g, b):
316
282
  """
317
- This function calculates the fugacity coefficient from the equation of state for a pure fluid
283
+ This function calculates the fugacity coefficient (kbar) from the equation of state for a pure fluid
318
284
 
319
285
  """
320
286
  lnph = Z[i] - 1.0 - math.log(Z[i]) + (B[i] * Vc[i] / V[i]) + (C[i] * Vc[i] * Vc[i] / (2.0 * V[i] * V[i]))
@@ -358,7 +324,7 @@ def mixEOS_CF(V, P, BVc, CVc2, DVc4, EVc5, FVc2, bmix, gVc2, TK):
358
324
 
359
325
 
360
326
  def mixvolume(V, P, BVc, CVc2, DVc4, EVc5, FVc2, bmix, gVc2, TK):
361
- """ This function iterates in volume space to get the best match to the entered pressure using the mixEOS function above.
327
+ """ This function iterates in volume space to get the best match volume (cm3/mol) to the entered pressure using the mixEOS function above.
362
328
 
363
329
  """
364
330
  for iter in range(1, 51):
@@ -371,10 +337,61 @@ def mixvolume(V, P, BVc, CVc2, DVc4, EVc5, FVc2, bmix, gVc2, TK):
371
337
 
372
338
  return V
373
339
 
340
+ import warnings as w
341
+
342
+ ## We are going to have to use a look up table to help the netwon raphson converge.
343
+
344
+ # Load the lookup table from the CSV file
345
+ DiadFit_dir=Path(__file__).parent
346
+ file_str='lookup_table_noneg.csv'
347
+ dz06_lookuptable=pd.read_csv(DiadFit_dir/file_str)
348
+ #df = pd.read_csv('lookup_table_noneg.csv')
349
+
350
+
351
+
352
+
353
+
354
+ def get_initial_guess(V_target, T_K_target, XH2O_target):
355
+ # Calculate the Euclidean distance from the target point to all points in the table
356
+ # We normalize each dimension by its range to give equal weight to all parameters
357
+
358
+
359
+ df=dz06_lookuptable
360
+
361
+ # code to find best value
362
+
363
+ P_range = df['P_kbar'].max() - df['P_kbar'].min()
364
+ T_K_range = df['T_K'].max() - df['T_K'].min()
365
+ XH2O_range = df['XH2O'].max() - df['XH2O'].min()
366
+ V_range = df['V'].max() - df['V'].min()
367
+
368
+ # Calculate normalized distances
369
+ distances = np.sqrt(
370
+ ((df['P_kbar'] - df['P_kbar'].mean()) / P_range) ** 2 +
371
+ ((df['T_K'] - T_K_target) / T_K_range) ** 2 +
372
+ ((df['XH2O'] - XH2O_target) / XH2O_range) ** 2 +
373
+ ((df['V'] - V_target) / V_range) ** 2
374
+ )
375
+
376
+ # Find the index of the closest row in the DataFrame
377
+ closest_index = distances.argmin()
378
+
379
+ # Retrieve the P_kbar value from the closest row
380
+ initial_guess_P = df.iloc[closest_index]['P_kbar']
381
+
382
+
383
+
384
+ return initial_guess_P
385
+
386
+
387
+
388
+
374
389
  def mixpressure(P, V, TK, Y):
375
- """ This function iterates in pressure space to get the best match to the entered volume using the mixEOS function above.
390
+ """ This function iterates in pressure space to get the best match in bars to the entered volume in cm3/mol using the mixEOS function above.
376
391
 
377
392
  """
393
+
394
+
378
395
  for iter in range(1, 51):
379
396
  k1_temperature, k2_temperature, k3_temperature, a1, a2, g, b, Vc, B, C, D, E, F, Vguess=get_EOS_params(P, TK)
380
397
  Bij, Vcij, BVc_prm, BVc, Cijk, Vcijk, CVc2_prm, CVc2, Dijklm, Vcijklm, DVc4_prm, DVc4, Eijklmn, Vcijklmn, EVc5_prm, EVc5, Fij, FVc2_prm, FVc2, bmix, b_prm, gijk, gVc2_prm, gVc2=mixing_rules(B, C,D, E, F, Vc, Y, b, g, k1_temperature, k2_temperature, k3_temperature)
@@ -382,15 +399,63 @@ def mixpressure(P, V, TK, Y):
382
399
  diff = ((mixEOS(V, P + 0.0001, BVc, CVc2, DVc4, EVc5, FVc2, bmix, gVc2, TK)
383
400
  - mixEOS(V, P, BVc, CVc2, DVc4, EVc5, FVc2, bmix, gVc2, TK)) / 0.0001)
384
401
  Pnew = P - mixEOS(V, P, BVc, CVc2, DVc4, EVc5, FVc2, bmix, gVc2, TK) / diff
402
+
403
+
404
+
405
+
385
406
  if abs(Pnew - P) <= 0.000001:
386
407
  break
408
+
387
409
  P = Pnew
388
410
 
389
411
  return P
390
412
 
413
+ # # Dont allow negative solutions
414
+ # if Pnew<0:
415
+ # Pnew = 3000
416
+
417
+ # if Pnew < 10000 and Pnew>0 and V<50:
418
+ # w.warn('Sometimes the adapted Newton Raphson method will find a second root at lower (or negative pressure). This initially found a root at P=' + str(np.round(Pnew, 2)) + ', V=' + str(np.round(V)) + '. The algorithm has started its search again at P=3000 bars. Double check your results make sense')
419
+ #
420
+ # Pnew = 10000 # Replace 0.0001 with a small positive value that makes sense for your system
421
+ #
422
+
423
+
424
+ # def mixpressure(P_init, V, TK, Y, max_restarts=3):
425
+ # """This function iterates in pressure space to get the best match to the entered volume using the mixEOS function above."""
426
+ #
427
+ # restarts = 0
428
+ # while restarts <= max_restarts:
429
+ # P = P_init
430
+ # for iter in range(1, 51):
431
+ # # Your EOS parameters and mixing rules calculations here
432
+ #
433
+ # diff = ((mixEOS(V, P + 0.0001, BVc, CVc2, DVc4, EVc5, FVc2, bmix, gVc2, TK) - mixEOS(V, P, BVc, CVc2, DVc4, EVc5, FVc2, bmix, gVc2, TK)) / 0.0001)
434
+ # Pnew = P - mixEOS(V, P, BVc, CVc2, DVc4, EVc5, FVc2, bmix, gVc2, TK) / diff
435
+ #
436
+ # # Don't allow unrealistic solutions but provide a chance to reset
437
+ # if Pnew < 5000 and V > 10:
438
+ # warnings.warn('Root forced above 5000 bars due to conditions, attempting restart...')
439
+ # Pnew = 5000 # Force the pressure up due to your condition
440
+ # break # Break out of the current iteration loop to allow for a restart
441
+ #
442
+ # if abs(Pnew - P) <= 0.000001: # Convergence criterion
443
+ # return Pnew # Return the converged value
444
+ # P = Pnew
445
+ #
446
+ # restarts += 1 # Increment the number of restarts attempted
447
+ # P_init = 5000 # Set a new starting point that might be closer to the suspected real root
448
+ #
449
+ # warnings.warn('Max restarts reached, solution may not be optimal.')
450
+ # return P # Return the last computed pressure if all restart attempts fail
451
+
452
+
453
+
454
+
391
455
 
392
456
 
393
457
  def mix_lnphi(i, Zmix, BVc_prm, CVc2_prm, DVc4_prm, EVc5_prm, FVc2_prm, FVc2, bmix, b_prm, gVc2, gVc2_prm, Vmix):
458
+ """ This function calculates lnphi values"""
394
459
  lnph=0
395
460
 
396
461
  lnph = -math.log(Zmix)
@@ -562,6 +627,8 @@ def mix_fugacity_ind(*, P_kbar, T_K, XH2O, Vmix):
562
627
 
563
628
 
564
629
  def mixing_rules(B, C, D, E, F, Vc, Y, b, g, k1_temperature, k2_temperature, k3_temperature):
630
+ """ This function applies the DZ06 mixing rules"""
631
+
565
632
  Bij = np.zeros((2, 2))
566
633
  Vcij = np.zeros((2, 2))
567
634
  BVc_prm = np.zeros(2)
@@ -739,7 +806,7 @@ def mixing_rules(B, C, D, E, F, Vc, Y, b, g, k1_temperature, k2_temperature, k3_
739
806
  ## Getting EOS contsants themselves
740
807
 
741
808
  def get_EOS_params(P, TK):
742
- """ This function returns the EOS 'constants' if you know the pressure and temperature
809
+ """ This function returns the EOS 'constants' if you know the pressure (in bars) and temperature (in Kelvin)
743
810
 
744
811
  """
745
812
 
@@ -813,7 +880,7 @@ def get_EOS_params(P, TK):
813
880
  ## Lets wrap all these functions up.
814
881
 
815
882
  def calculate_molar_volume_ind_DZ2006(*, P_kbar, T_K, XH2O):
816
- """ This function calculates molar volume for a known pressure, T in K and XH2O (mol frac) for a single value
883
+ """ This function calculates molar volume (cm3/mol) for a known pressure (kbar), T in K and XH2O (mol frac) for a single value
817
884
  """
818
885
 
819
886
  P=P_kbar*1000
@@ -838,11 +905,14 @@ def calculate_molar_volume_ind_DZ2006(*, P_kbar, T_K, XH2O):
838
905
 
839
906
  mol_vol=mixvolume(Vguess, P, BVc, CVc2, DVc4, EVc5, FVc2, bmix, gVc2, T_K)
840
907
 
908
+ if mol_vol<0:
909
+ mol_vol=np.nan
910
+
841
911
  return mol_vol
842
912
 
843
913
 
844
914
  def calculate_molar_volume_DZ2006(*, P_kbar, T_K, XH2O):
845
- """ Used to calculate molar volume in a loop for multiple inputs
915
+ """ Used to calculate molar volume (cm3/mol) in a loop for multiple inputs
846
916
 
847
917
 
848
918
  """
@@ -855,7 +925,7 @@ def calculate_molar_volume_DZ2006(*, P_kbar, T_K, XH2O):
855
925
  raise ValueError("All input Pandas Series must have the same length.")
856
926
 
857
927
  # Set up loop
858
- mol_vol=np.empty(len(P_kbar), float)
928
+ mol_vol=np.zeros(len(P_kbar), float)
859
929
 
860
930
  for i in range(0, len(P_kbar)):
861
931
  mol_vol[i]=calculate_molar_volume_ind_DZ2006(P_kbar=P_kbar.iloc[i].astype(float), T_K=T_K.iloc[i].astype(float), XH2O=XH2O.iloc[i].astype(float))
@@ -867,40 +937,50 @@ def calculate_molar_volume_DZ2006(*, P_kbar, T_K, XH2O):
867
937
  return mol_vol
868
938
 
869
939
  def calculate_Pressure_ind_DZ2006(*, mol_vol, T_K, XH2O, Pguess=None):
870
- """ This function calculates pressure for a known molar volume, T in K and XH2O (mol frac) for a single value
940
+ """ This function calculates pressure (in bars) for a known molar volume, T in K and XH2O (mol frac) for a single value. It uses a look up table to get pressure, then a newton and raphson method (implemented in the function mixpressure) to find the best fit pressure. There are some densities, T_K and XH2O values where the volume is negative.
871
941
  """
872
942
  V=mol_vol
873
- if Pguess is None:
874
- if V>1000:
875
- Pguess=1000
876
- elif V<10:
877
- Pguess=20000
878
- else:
879
- Pguess=200
943
+ # if Pguess is None:
944
+ # if V>1000:
945
+ # Pguess=1000
946
+ # elif V<10:
947
+ # Pguess=20000
948
+ # else:
949
+ # Pguess=200
950
+
951
+ # Lets get P guess from a look up table
952
+ # uses a look up table
953
+ Pguess=get_initial_guess(V_target=V, T_K_target=T_K, XH2O_target=XH2O)*1000
954
+
955
+ if Pguess <= 0:
956
+ return np.nan
957
+
880
958
 
881
959
  TK=T_K
882
960
 
883
961
  # lets do for low pressure initially
884
962
 
885
963
 
886
- if XH2O==0:
887
- P=purepressure(1, V, Pguess, TK)
964
+ # if XH2O==0:
965
+ # P=purepressure(1, V, Pguess, TK)
966
+ #
967
+ # elif XH2O==1:
968
+ # P=purepressure(0, V, Pguess, TK)
969
+ #
970
+ # else:
971
+ XCO2=1-XH2O
972
+ Y = [0] * 2
973
+ Y[0]=XH2O
974
+ Y[1]=XCO2
888
975
 
889
- elif XH2O==1:
890
- P=purepressure(0, V, Pguess, TK)
976
+ # Now iteratively solve for pressure starting from this initial guess.
891
977
 
892
- else:
893
- XCO2=1-XH2O
894
- Y = [0] * 2
895
- Y[0]=XH2O
896
- Y[1]=XCO2
897
-
898
- P=mixpressure(Pguess, V, T_K, Y)
978
+ P=mixpressure(Pguess, V, T_K, Y)
899
979
 
900
980
  return P
901
981
 
902
982
  def calculate_Pressure_DZ2006(*, mol_vol=None, density=None, T_K, XH2O):
903
- """ Used to calculate molar volume in a loop for multiple inputs
983
+ """ Used to calculate pressure in a loop for multiple inputs. Dens - bulk density.
904
984
 
905
985
 
906
986
  """
@@ -919,7 +999,7 @@ def calculate_Pressure_DZ2006(*, mol_vol=None, density=None, T_K, XH2O):
919
999
  raise ValueError("All input Pandas Series must have the same length.")
920
1000
 
921
1001
  # Set up loop
922
- P=np.empty(len(mol_vol), float)
1002
+ P=np.zeros(len(mol_vol), float)
923
1003
 
924
1004
  for i in range(0, len(mol_vol)):
925
1005
  P[i]=calculate_Pressure_ind_DZ2006(mol_vol=mol_vol.iloc[i].astype(float), T_K=T_K.iloc[i].astype(float), XH2O=XH2O.iloc[i].astype(float))
@@ -945,12 +1025,12 @@ def mix_fugacity(*, P_kbar, T_K, XH2O, Vmix):
945
1025
  if len(set(lengths)) != 1:
946
1026
  raise ValueError("All input Pandas Series must have the same length.")
947
1027
 
948
- f=np.empty(len(P_kbar), float)
949
- a_CO2=np.empty(len(P_kbar), float)
950
- a_H2O=np.empty(len(P_kbar), float)
951
- f_CO2=np.empty(len(P_kbar), float)
952
- f_H2O=np.empty(len(P_kbar), float)
953
- Zmix=np.empty(len(P_kbar), float)
1028
+ f=np.zeros(len(P_kbar), float)
1029
+ a_CO2=np.zeros(len(P_kbar), float)
1030
+ a_H2O=np.zeros(len(P_kbar), float)
1031
+ f_CO2=np.zeros(len(P_kbar), float)
1032
+ f_H2O=np.zeros(len(P_kbar), float)
1033
+ Zmix=np.zeros(len(P_kbar), float)
954
1034
  for i in range(0, len(P_kbar)):
955
1035
 
956
1036
  f_H2O[i], f_CO2[i], a_H2O[i], a_CO2[i], Zmix[i]=mix_fugacity_ind(P_kbar=P_kbar.iloc[i].astype(float), T_K=T_K.iloc[i].astype(float), XH2O=XH2O.iloc[i].astype(float), Vmix=Vmix.iloc[i].astype(float))
@@ -1059,7 +1139,7 @@ def calculate_entrapment_P_XH2O(*, XH2O, CO2_dens_gcm3, T_K, T_K_ambient=37+273.
1059
1139
  P_kbar_mixCO2_DZ06_Hloss: Pressure calculated from the reconstructed mixed fluid density using the mixed EOS from Duan and Zhang (2006) assuming H loss
1060
1140
  P_kbar_mixCO2_DZ06_noHloss: Pressure calculated from the reconstructed mixed fluid density using the mixed EOS from Duan and Zhang (2006) assuming H loss
1061
1141
  P Mix_Hloss/P Pure DZ06: Correction factor - e.g. how much deeper the pressure is from the mixed EOS with H loss
1062
- P Mix_noHloss/P Pure DZ06: Correction factor - e.g. how much deeper the pressure is from the mixed EOS with H loss
1142
+ P Mix_noHloss/P Pure DZ06: Correction factor - e.g. how much deeper the pressure is from the mixed EOS (assuming no H loss)
1063
1143
  rho_mix_calc_noHloss: Bulk density calculated (C+H)
1064
1144
  rho_mix_calc_Hloss: Bulk density calculated (C+H) after h loss
1065
1145
  CO2_dens_gcm3: Input CO2 density
@@ -1079,26 +1159,28 @@ def calculate_entrapment_P_XH2O(*, XH2O, CO2_dens_gcm3, T_K, T_K_ambient=37+273.
1079
1159
  # IF water isnt lost
1080
1160
 
1081
1161
  # Calculate mass ratio from molar ratio
1082
- mass_ratio=(XH2O*18)/((1-XH2O)*44)
1083
- # Calculate pressure in CO2 fluid
1084
- P=calculate_P_for_rho_T_SW96(CO2_dens_gcm3, T_K_ambient)
1162
+ XH2O_mass=(XH2O*18)/((1-XH2O)*44 +(XH2O*18) )
1163
+ # Calculate pressure in CO2 fluid - returns answer in kbar
1164
+ P_CO2=calculate_P_for_rho_T_SW96(CO2_dens_gcm3, T_K_ambient)['P_kbar']
1085
1165
  # Now calculate density of H2O fluid
1086
1166
 
1087
- # Calculate density of H2O
1088
- rho_H2O=calculate_rho_for_P_T_H2O(P['P_kbar'], T_K_ambient)
1167
+ # See https://www.youtube.com/watch?v=6wE4Tk6OjGY
1168
+ Ptotal=P_CO2/(1-XH2O) # Calculate the total pressure from the pressure we know for CO2.
1169
+ P_H2O=Ptotal*XH2O # Now calculate the pressure of H2O. You could also do this as PTot*XH2O
1170
+
1171
+ # calculate density of H2O using EOS
1172
+ H2O_dens=calculate_rho_for_P_T_H2O(P_kbar=P_H2O,T_K=T_K_ambient)
1089
1173
 
1174
+ # Calculate the bulk density by re-arranging the two volume equations
1175
+ rho_orig_no_H_loss=(CO2_dens_gcm3*H2O_dens)/((1-XH2O_mass)*H2O_dens+XH2O_mass*CO2_dens_gcm3)
1090
1176
 
1091
1177
 
1092
- # Assume a system of unit 1. Calculate volume of CO2
1093
- VolCO2=(1-mass_ratio)/CO2_dens_gcm3
1094
- VolH2O=mass_ratio/rho_H2O
1095
- rho_orig_no_H_loss=1/(VolH2O+VolCO2)
1096
1178
 
1097
1179
  if fast_calcs is True:
1098
1180
  if Hloss is True:
1099
1181
  P=calculate_Pressure_DZ2006(density=rho_orig_H_loss, T_K=T_K, XH2O=XH2O)
1100
1182
  if Hloss is False:
1101
- P=calculate_Pressure_DZ2006(density=rho_orig_H_loss, T_K=T_K, XH2O=XH2O)
1183
+ P=calculate_Pressure_DZ2006(density=rho_orig_no_H_loss, T_K=T_K, XH2O=XH2O)
1102
1184
  return P/1000
1103
1185
 
1104
1186
  else:
@@ -1106,9 +1188,10 @@ def calculate_entrapment_P_XH2O(*, XH2O, CO2_dens_gcm3, T_K, T_K_ambient=37+273.
1106
1188
  # Lets calculate the pressure using SW96
1107
1189
  P_SW=calculate_P_for_rho_T(T_K=T_K, CO2_dens_gcm3=rho_meas, EOS='SW96')
1108
1190
  P_SP=calculate_P_for_rho_T(T_K=T_K, CO2_dens_gcm3=rho_meas, EOS='SP94')
1109
- # Same for DZ2006
1191
+ # Run Duan and Zhang with no XHO@ to start with
1110
1192
  P_DZ=calculate_Pressure_DZ2006(density=rho_meas, T_K=T_K, XH2O=XH2O*0)
1111
- # Now doing it with XH2O
1193
+ # Now doing it with XH2O for two different densities
1194
+
1112
1195
  P_DZ_mix_H_loss=calculate_Pressure_DZ2006(density=rho_orig_H_loss, T_K=T_K, XH2O=XH2O)
1113
1196
  P_DZ_mix_noH_loss=calculate_Pressure_DZ2006(density=rho_orig_no_H_loss, T_K=T_K, XH2O=XH2O)
1114
1197