rock-physics-open 0.0__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.

Potentially problematic release.


This version of rock-physics-open might be problematic. Click here for more details.

Files changed (142) hide show
  1. rock_physics_open/__init__.py +0 -0
  2. rock_physics_open/equinor_utilities/__init__.py +0 -0
  3. rock_physics_open/equinor_utilities/anisotropy.py +162 -0
  4. rock_physics_open/equinor_utilities/classification_functions/__init__.py +17 -0
  5. rock_physics_open/equinor_utilities/classification_functions/class_stats.py +58 -0
  6. rock_physics_open/equinor_utilities/classification_functions/lin_class.py +47 -0
  7. rock_physics_open/equinor_utilities/classification_functions/mahal_class.py +56 -0
  8. rock_physics_open/equinor_utilities/classification_functions/norm_class.py +65 -0
  9. rock_physics_open/equinor_utilities/classification_functions/poly_class.py +40 -0
  10. rock_physics_open/equinor_utilities/classification_functions/post_prob.py +26 -0
  11. rock_physics_open/equinor_utilities/classification_functions/two_step_classification.py +46 -0
  12. rock_physics_open/equinor_utilities/conversions.py +10 -0
  13. rock_physics_open/equinor_utilities/gen_utilities/__init__.py +11 -0
  14. rock_physics_open/equinor_utilities/gen_utilities/dict_to_float.py +33 -0
  15. rock_physics_open/equinor_utilities/gen_utilities/dim_check_vector.py +83 -0
  16. rock_physics_open/equinor_utilities/gen_utilities/filter_input.py +126 -0
  17. rock_physics_open/equinor_utilities/gen_utilities/filter_output.py +78 -0
  18. rock_physics_open/equinor_utilities/machine_learning_utilities/__init__.py +14 -0
  19. rock_physics_open/equinor_utilities/machine_learning_utilities/dummy_vars.py +42 -0
  20. rock_physics_open/equinor_utilities/machine_learning_utilities/exponential_model.py +119 -0
  21. rock_physics_open/equinor_utilities/machine_learning_utilities/import_ml_models.py +61 -0
  22. rock_physics_open/equinor_utilities/machine_learning_utilities/run_regression.py +151 -0
  23. rock_physics_open/equinor_utilities/machine_learning_utilities/sigmoidal_model.py +188 -0
  24. rock_physics_open/equinor_utilities/snapshot_test_utilities/__init__.py +10 -0
  25. rock_physics_open/equinor_utilities/snapshot_test_utilities/compare_snapshots.py +145 -0
  26. rock_physics_open/equinor_utilities/snapshot_test_utilities/snapshots.py +54 -0
  27. rock_physics_open/equinor_utilities/std_functions/__init__.py +43 -0
  28. rock_physics_open/equinor_utilities/std_functions/backus_ave.py +53 -0
  29. rock_physics_open/equinor_utilities/std_functions/dvorkin_nur.py +69 -0
  30. rock_physics_open/equinor_utilities/std_functions/gassmann.py +140 -0
  31. rock_physics_open/equinor_utilities/std_functions/hashin_shtrikman.py +195 -0
  32. rock_physics_open/equinor_utilities/std_functions/hertz_mindlin.py +43 -0
  33. rock_physics_open/equinor_utilities/std_functions/moduli_velocity.py +51 -0
  34. rock_physics_open/equinor_utilities/std_functions/reflection_eq.py +98 -0
  35. rock_physics_open/equinor_utilities/std_functions/rho.py +59 -0
  36. rock_physics_open/equinor_utilities/std_functions/voigt_reuss_hill.py +128 -0
  37. rock_physics_open/equinor_utilities/std_functions/walton.py +38 -0
  38. rock_physics_open/equinor_utilities/std_functions/wood_brie.py +77 -0
  39. rock_physics_open/equinor_utilities/various_utilities/Equinor_logo.gif +0 -0
  40. rock_physics_open/equinor_utilities/various_utilities/Equinor_logo.ico +0 -0
  41. rock_physics_open/equinor_utilities/various_utilities/__init__.py +24 -0
  42. rock_physics_open/equinor_utilities/various_utilities/display_result_statistics.py +83 -0
  43. rock_physics_open/equinor_utilities/various_utilities/gassmann_dry_mod.py +37 -0
  44. rock_physics_open/equinor_utilities/various_utilities/gassmann_mod.py +37 -0
  45. rock_physics_open/equinor_utilities/various_utilities/gassmann_sub_mod.py +53 -0
  46. rock_physics_open/equinor_utilities/various_utilities/hs_average.py +40 -0
  47. rock_physics_open/equinor_utilities/various_utilities/pressure.py +88 -0
  48. rock_physics_open/equinor_utilities/various_utilities/reflectivity.py +85 -0
  49. rock_physics_open/equinor_utilities/various_utilities/timeshift.py +91 -0
  50. rock_physics_open/equinor_utilities/various_utilities/vp_vs_rho_set_statistics.py +154 -0
  51. rock_physics_open/equinor_utilities/various_utilities/vrh_3_min.py +61 -0
  52. rock_physics_open/fluid_models/__init__.py +9 -0
  53. rock_physics_open/fluid_models/brine_model/__init__.py +5 -0
  54. rock_physics_open/fluid_models/brine_model/brine_properties.py +143 -0
  55. rock_physics_open/fluid_models/gas_model/__init__.py +5 -0
  56. rock_physics_open/fluid_models/gas_model/gas_properties.py +277 -0
  57. rock_physics_open/fluid_models/oil_model/__init__.py +5 -0
  58. rock_physics_open/fluid_models/oil_model/dead_oil_density.py +60 -0
  59. rock_physics_open/fluid_models/oil_model/dead_oil_velocity.py +28 -0
  60. rock_physics_open/fluid_models/oil_model/live_oil_density.py +79 -0
  61. rock_physics_open/fluid_models/oil_model/live_oil_velocity.py +24 -0
  62. rock_physics_open/fluid_models/oil_model/oil_bubble_point.py +69 -0
  63. rock_physics_open/fluid_models/oil_model/oil_properties.py +114 -0
  64. rock_physics_open/sandstone_models/__init__.py +57 -0
  65. rock_physics_open/sandstone_models/cemented_shalysand_sandyshale_models.py +304 -0
  66. rock_physics_open/sandstone_models/constant_cement_models.py +204 -0
  67. rock_physics_open/sandstone_models/constant_cement_optimisation.py +122 -0
  68. rock_physics_open/sandstone_models/contact_cement_model.py +138 -0
  69. rock_physics_open/sandstone_models/curvefit_sandstone_models.py +143 -0
  70. rock_physics_open/sandstone_models/friable_models.py +178 -0
  71. rock_physics_open/sandstone_models/friable_optimisation.py +112 -0
  72. rock_physics_open/sandstone_models/friable_shalysand_sandyshale_models.py +235 -0
  73. rock_physics_open/sandstone_models/patchy_cement_fluid_substitution_model.py +477 -0
  74. rock_physics_open/sandstone_models/patchy_cement_model.py +286 -0
  75. rock_physics_open/sandstone_models/patchy_cement_optimisation.py +251 -0
  76. rock_physics_open/sandstone_models/unresolved_cemented_sandshale_models.py +134 -0
  77. rock_physics_open/sandstone_models/unresolved_friable_sandshale_models.py +126 -0
  78. rock_physics_open/shale_models/__init__.py +19 -0
  79. rock_physics_open/shale_models/dem.py +174 -0
  80. rock_physics_open/shale_models/dem_dual_por.py +61 -0
  81. rock_physics_open/shale_models/kus_tok.py +59 -0
  82. rock_physics_open/shale_models/multi_sca.py +133 -0
  83. rock_physics_open/shale_models/pq.py +102 -0
  84. rock_physics_open/shale_models/sca.py +90 -0
  85. rock_physics_open/shale_models/shale4_mineral.py +147 -0
  86. rock_physics_open/shale_models/shale4_mineral_dem_overlay.py +92 -0
  87. rock_physics_open/span_wagner/__init__.py +5 -0
  88. rock_physics_open/span_wagner/co2_properties.py +438 -0
  89. rock_physics_open/span_wagner/coefficients.py +165 -0
  90. rock_physics_open/span_wagner/equations.py +104 -0
  91. rock_physics_open/span_wagner/tables/__init__.py +0 -0
  92. rock_physics_open/span_wagner/tables/carbon_dioxide_density.npz +0 -0
  93. rock_physics_open/span_wagner/tables/lookup_table.py +33 -0
  94. rock_physics_open/t_matrix_models/Equinor_logo.ico +0 -0
  95. rock_physics_open/t_matrix_models/__init__.py +45 -0
  96. rock_physics_open/t_matrix_models/carbonate_pressure_substitution.py +124 -0
  97. rock_physics_open/t_matrix_models/curvefit_t_matrix_exp.py +124 -0
  98. rock_physics_open/t_matrix_models/curvefit_t_matrix_min.py +86 -0
  99. rock_physics_open/t_matrix_models/opt_subst_utilities.py +415 -0
  100. rock_physics_open/t_matrix_models/parse_t_matrix_inputs.py +297 -0
  101. rock_physics_open/t_matrix_models/run_t_matrix.py +243 -0
  102. rock_physics_open/t_matrix_models/t_matrix_C.py +210 -0
  103. rock_physics_open/t_matrix_models/t_matrix_opt_fluid_sub_exp.py +137 -0
  104. rock_physics_open/t_matrix_models/t_matrix_opt_fluid_sub_petec.py +163 -0
  105. rock_physics_open/t_matrix_models/t_matrix_opt_forward_model_exp.py +72 -0
  106. rock_physics_open/t_matrix_models/t_matrix_opt_forward_model_min.py +86 -0
  107. rock_physics_open/t_matrix_models/t_matrix_parameter_optimisation_exp.py +172 -0
  108. rock_physics_open/t_matrix_models/t_matrix_parameter_optimisation_min.py +159 -0
  109. rock_physics_open/t_matrix_models/t_matrix_vector/__init__.py +12 -0
  110. rock_physics_open/t_matrix_models/t_matrix_vector/array_functions.py +75 -0
  111. rock_physics_open/t_matrix_models/t_matrix_vector/calc_c_eff.py +163 -0
  112. rock_physics_open/t_matrix_models/t_matrix_vector/calc_isolated.py +95 -0
  113. rock_physics_open/t_matrix_models/t_matrix_vector/calc_kd.py +40 -0
  114. rock_physics_open/t_matrix_models/t_matrix_vector/calc_kd_eff.py +116 -0
  115. rock_physics_open/t_matrix_models/t_matrix_vector/calc_kd_uuv.py +18 -0
  116. rock_physics_open/t_matrix_models/t_matrix_vector/calc_pressure.py +140 -0
  117. rock_physics_open/t_matrix_models/t_matrix_vector/calc_t.py +71 -0
  118. rock_physics_open/t_matrix_models/t_matrix_vector/calc_td.py +42 -0
  119. rock_physics_open/t_matrix_models/t_matrix_vector/calc_theta.py +43 -0
  120. rock_physics_open/t_matrix_models/t_matrix_vector/calc_x.py +33 -0
  121. rock_physics_open/t_matrix_models/t_matrix_vector/calc_z.py +50 -0
  122. rock_physics_open/t_matrix_models/t_matrix_vector/check_and_tile.py +43 -0
  123. rock_physics_open/t_matrix_models/t_matrix_vector/g_tensor.py +140 -0
  124. rock_physics_open/t_matrix_models/t_matrix_vector/iso_av.py +60 -0
  125. rock_physics_open/t_matrix_models/t_matrix_vector/iso_ave_all.py +55 -0
  126. rock_physics_open/t_matrix_models/t_matrix_vector/pressure_input.py +44 -0
  127. rock_physics_open/t_matrix_models/t_matrix_vector/t_matrix_vec.py +278 -0
  128. rock_physics_open/t_matrix_models/t_matrix_vector/velocity_vti_angles.py +81 -0
  129. rock_physics_open/t_matrix_models/tmatrix_python.dll +0 -0
  130. rock_physics_open/t_matrix_models/tmatrix_python.so +0 -0
  131. rock_physics_open/ternary_plots/__init__.py +3 -0
  132. rock_physics_open/ternary_plots/gen_ternary_plot.py +73 -0
  133. rock_physics_open/ternary_plots/shale_prop_ternary.py +337 -0
  134. rock_physics_open/ternary_plots/ternary_patches.py +277 -0
  135. rock_physics_open/ternary_plots/ternary_plot_utilities.py +197 -0
  136. rock_physics_open/ternary_plots/unconventionals_ternary.py +75 -0
  137. rock_physics_open/version.py +21 -0
  138. rock_physics_open-0.0.dist-info/METADATA +92 -0
  139. rock_physics_open-0.0.dist-info/RECORD +142 -0
  140. rock_physics_open-0.0.dist-info/WHEEL +5 -0
  141. rock_physics_open-0.0.dist-info/licenses/LICENSE +165 -0
  142. rock_physics_open-0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,154 @@
1
+ import os
2
+
3
+ import numpy as np
4
+ import pandas as pd
5
+ from sklearn.metrics import r2_score
6
+
7
+ from .display_result_statistics import disp_result_stats
8
+
9
+
10
+ def vp_vs_rho_stats(
11
+ vp_observed,
12
+ vs_observed,
13
+ rho_observed,
14
+ vp_estimated,
15
+ vs_estimated,
16
+ rho_estimated,
17
+ fname,
18
+ estimated_set_names,
19
+ well_names,
20
+ file_mode="a",
21
+ disp_results=True,
22
+ ):
23
+ """
24
+ Utility to estimate statistics between vp-vs-rho sets - observed and estimated values. The results are displayed
25
+ on screen (optional) and saved to a .csv file. If the file exists, the results will be appended.
26
+ The statistics consists of RAE (relative absolute error) [fraction], RRMSE (relative root mean squared error)
27
+ [fraction] and R^2 (coefficient of determination) [fraction].
28
+
29
+
30
+ Parameters
31
+ ----------
32
+ vp_observed : np.ndarray or list
33
+ Observed vp [m/s].
34
+ vs_observed : np.ndarray or list
35
+ Observed vs [m/s].
36
+ rho_observed : np.ndarray or list
37
+ Observed density [kg/m^3].
38
+ vp_estimated : np.ndarray or list
39
+ Estimated vp [m/s].
40
+ vs_estimated : np.ndarray or list
41
+ Estimated vs [m/s].
42
+ rho_estimated : np.ndarray or list
43
+ Estimated density [kg/m^3].
44
+ fname : str
45
+ File name for saved results.
46
+ estimated_set_names : str or list
47
+ Name of the estimated vp-vs-rho set(s).
48
+ well_names : str or list
49
+ Well name of the vp-vs-rho set(s).
50
+ file_mode : str
51
+ File open mode, default append.
52
+ disp_results : bool
53
+ Display results on screen.
54
+ """
55
+ if isinstance(estimated_set_names, str):
56
+ estimated_set_names = [estimated_set_names]
57
+ if isinstance(well_names, str):
58
+ well_names = [well_names]
59
+
60
+ _verify(
61
+ vp_observed,
62
+ vs_observed,
63
+ rho_observed,
64
+ vp_estimated,
65
+ vs_estimated,
66
+ rho_estimated,
67
+ set_names=estimated_set_names,
68
+ well_names=well_names,
69
+ file_mode=file_mode,
70
+ )
71
+
72
+ est_frame_columns = [
73
+ "Well",
74
+ "Vp RMAE",
75
+ "Vp RRMSE",
76
+ "Vp R2",
77
+ "Vs RMAE",
78
+ "Vs RRMSE",
79
+ "Vs R2",
80
+ "Rho RMAE",
81
+ "Rho RRMSE",
82
+ "Rho R2",
83
+ ]
84
+ est_frame = pd.DataFrame(columns=est_frame_columns, index=estimated_set_names)
85
+ est_frame.index.name = "Estimated set name"
86
+ est_frame.iloc[:, 0] = well_names
87
+
88
+ # If inputs are found to satisfy expectations in _verify, and they are numpy arrays, cast to lists, and run through
89
+ if isinstance(vp_observed, np.ndarray):
90
+ vp_observed = [vp_observed]
91
+ vs_observed = [vs_observed]
92
+ rho_observed = [rho_observed]
93
+ vp_estimated = [vp_estimated]
94
+ vs_estimated = [vs_estimated]
95
+ rho_estimated = [rho_estimated]
96
+
97
+ for i in range(len(vp_observed)):
98
+ res = []
99
+ for obs, est in zip(
100
+ [vp_observed[i], vs_observed[i], rho_observed[i]],
101
+ [vp_estimated[i], vs_estimated[i], rho_estimated[i]],
102
+ ):
103
+ res.append(np.mean(np.abs((est.flatten() - obs.flatten()) / obs.flatten())))
104
+ res.append(
105
+ np.sqrt(
106
+ np.mean(np.square((est.flatten() - obs.flatten()) / obs.flatten()))
107
+ )
108
+ )
109
+ res.append(r2_score(obs.flatten(), est.flatten()))
110
+
111
+ res_dict = dict(zip(est_frame_columns[1:], res))
112
+ est_frame.iloc[i, 1:] = res_dict
113
+ if disp_results:
114
+ disp_result_stats(
115
+ estimated_set_names[i], res, est_frame_columns[1:], values_only=True
116
+ )
117
+ # Test if the file already exists. If so, and the file_mode is set to 'a', drop the column headers when writing
118
+ # the file
119
+ if os.path.exists(fname) and file_mode == "a":
120
+ est_frame.to_csv(fname, mode=file_mode, header=False)
121
+ else:
122
+ est_frame.to_csv(fname, mode=file_mode)
123
+
124
+
125
+ def _verify(*args, set_names=None, well_names=None, file_mode=None):
126
+ """Verify that arguments are either numpy arrays or lists of numpy arrays.
127
+ Raises
128
+ ------
129
+ ValueError
130
+ If not np.ndarray or list of such.
131
+ ValueError
132
+ If an entry contains NaNs.
133
+ ValueError
134
+ If an entry contains Infs.
135
+ ValueError
136
+ If mismatch in argument lengths.
137
+ ValueError
138
+ If file mode not 'a' or 'w'.
139
+ """
140
+ # Verify that args are either numpy arrays or list of arrays
141
+ for arg in args:
142
+ if isinstance(arg, np.ndarray):
143
+ arg = [arg]
144
+ for this_arg in arg:
145
+ if not isinstance(this_arg, np.ndarray):
146
+ raise ValueError(f"{__file__}: input not numpy array: {type(arg)}")
147
+ if np.any(np.isnan(this_arg)):
148
+ raise ValueError(f"{__file__}: input contains NaNs")
149
+ if np.any(np.isinf(this_arg)):
150
+ raise ValueError(f"{__file__}: input contains Infs")
151
+ if not len(arg) == len(set_names) == len(well_names):
152
+ raise ValueError(f"{__file__}: mismatch in argument lengths")
153
+ if not (file_mode == "a" or file_mode == "w"):
154
+ raise ValueError(f'{__file__}: file_mode must be one of ["a", "w"]')
@@ -0,0 +1,61 @@
1
+ from rock_physics_open.equinor_utilities import std_functions
2
+
3
+
4
+ def min_3_voigt_reuss_hill(
5
+ vp1, vs1, rhob1, f1, vp2, vs2, rhob2, f2, vp3, vs3, rhob3, f3
6
+ ):
7
+ """
8
+ Mix of three phases by Voigt-Reuss-Hill model. The fractions should add up to 1 with input of vp, vs and rho.
9
+
10
+ Parameters
11
+ ----------
12
+ vp1 : np.ndarray
13
+ Pressure wave velocity of phase 1 [m/s].
14
+ vs1 : np.ndarray
15
+ Shear wave velocity of phase 1 [m/s].
16
+ rhob1 : np.ndarray
17
+ Bulk density of phase 1 [kg/m^3].
18
+ f1 : np.ndarray
19
+ Fraction of phase 1 [fraction].
20
+ vp2 : np.ndarray
21
+ Pressure wave velocity of phase 2 [m/s].
22
+ vs2 : np.ndarray
23
+ Shear wave velocity of phase 2 [m/s].
24
+ rhob2 : np.ndarray
25
+ Bulk density of phase 2 [kg/m^3].
26
+ f2 : np.ndarray
27
+ Fraction of phase 2 [fraction].
28
+ vp3 : np.ndarray
29
+ Pressure wave velocity of phase 3 [m/s].
30
+ vs3 : np.ndarray
31
+ Shear wave velocity of phase 3 [m/s].
32
+ rhob3 : np.ndarray
33
+ Bulk density of phase 3 [kg/m^3].
34
+ f3 : np.ndarray
35
+ Fraction of phase 3 [fraction].
36
+
37
+ Returns
38
+ -------
39
+ tuple
40
+ vp, vs, rhob, ai, vp_vs, k, mu : np.ndarray.
41
+ vp: pressure wave velocity [m/s], vs: shear wave velocity [m/s], rhob: bulk density [kg/m^3],
42
+ ai: acoustic impedance [m/s x kg/m^3], vp_vs: velocity ratio [ratio],
43
+ k: effective bulk modulus [Pa], mu: effective shear modulus [Pa].
44
+ """
45
+ k1, mu1 = std_functions.moduli(vp1, vs1, rhob1)
46
+ k2, mu2 = std_functions.moduli(vp2, vs2, rhob2)
47
+ k3, mu3 = std_functions.moduli(vp3, vs3, rhob3)
48
+
49
+ # Normalise the fractions to make sure they sum to one
50
+ tot = f1 + f2 + f3
51
+ f1 = f1 / tot
52
+ f2 = f2 / tot
53
+ f3 = f3 / tot
54
+
55
+ k, mu = std_functions.multi_voigt_reuss_hill(k1, mu1, f1, k2, mu2, f2, k3, mu3, f3)
56
+
57
+ rhob = rhob1 * f1 + rhob2 * f2 + rhob3 * f3
58
+
59
+ vp, vs, ai, vp_vs = std_functions.velocity(k, mu, rhob)
60
+
61
+ return vp, vs, rhob, ai, vp_vs, k, mu
@@ -0,0 +1,9 @@
1
+ from .brine_model import brine_properties
2
+ from .gas_model import gas_properties
3
+ from .oil_model import oil_properties
4
+
5
+ __all__ = [
6
+ "brine_properties",
7
+ "gas_properties",
8
+ "oil_properties",
9
+ ]
@@ -0,0 +1,5 @@
1
+ from .brine_properties import brine_properties
2
+
3
+ __all__ = [
4
+ "brine_properties",
5
+ ]
@@ -0,0 +1,143 @@
1
+ import warnings
2
+
3
+ import numpy as np
4
+ from numpy import sqrt
5
+ from numpy.polynomial.polynomial import polyval2d, polyval3d
6
+
7
+
8
+ def brine_properties(
9
+ temperature: np.ndarray | float,
10
+ pressure: np.ndarray | float,
11
+ salinity: np.ndarray | float,
12
+ p_nacl: np.ndarray | float | None = None,
13
+ p_kcl: np.ndarray | float | None = None,
14
+ p_cacl: np.ndarray | float | None = None,
15
+ ) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
16
+ """
17
+ :param salinity: Salinity of solution as ppm of NaCl.
18
+ :param pressure: Pressure (Pa) of oil
19
+ :param temperature: Temperature (Celsius) of oil.
20
+ :param p_nacl: NaCl percentage, for future use
21
+ :param p_kcl: KCl percentage, for future use
22
+ :param p_cacl: CaCl percentage, for future use
23
+ :return: vel_b [m/s], den_b [kg/m^3], k_b [Pa]
24
+ """
25
+ vel_b = brine_primary_velocity(temperature, pressure * 1e-6, salinity * 1e-6)
26
+ den_b = brine_density(temperature, pressure * 1e-6, salinity * 1e-6) * 1000
27
+ k_b = vel_b**2 * den_b
28
+ return vel_b, den_b, k_b
29
+
30
+
31
+ def brine_density(
32
+ temperature: np.ndarray | float,
33
+ pressure: np.ndarray | float,
34
+ salinity: np.ndarray | float,
35
+ ) -> np.ndarray | float:
36
+ """
37
+ density of sodium chloride solutions, equation 27 in Batzle & Wang [1].
38
+ :param salinity: Salinity of solution as weight fraction (ppm/1000000) of
39
+ sodium chloride.
40
+ :param pressure: Pressure (MPa) of oil
41
+ :param temperature: Temperature (Celsius) of oil.
42
+ :return: density of solution in g/cc.
43
+ """
44
+ coefficients = [
45
+ [[0.668, 3e-4], [8e-5, -13e-6], [3e-6, 0.0]],
46
+ [[0.44, -24e-4], [-33e-4, 47e-6], [0.0, 0.0]],
47
+ ]
48
+ return water_density(temperature, pressure) + salinity * polyval3d(
49
+ salinity, temperature, pressure, coefficients
50
+ )
51
+
52
+
53
+ def brine_primary_velocity(
54
+ temperature: np.ndarray | float,
55
+ pressure: np.ndarray | float,
56
+ salinity: np.ndarray | float,
57
+ ) -> np.ndarray | float:
58
+ """
59
+ Primary wave velocity of sodium chloride solutions, equation 29 in Batzle & Wang [1]
60
+
61
+ :param salinity: Salinity of solution as weight fraction (ppm/1000000) of
62
+ sodium chloride.
63
+ :param pressure: Pressure (MPa) of oil
64
+ :param temperature: Temperature (Celsius) of oil.
65
+ :return: velocity of solution in m/s.
66
+ """
67
+ coefficients = np.zeros((3, 4, 3))
68
+ coefficients[0, 0, 0] = 1170
69
+ coefficients[0, 1, 0] = -9.6
70
+ coefficients[0, 2, 0] = 0.055
71
+ coefficients[0, 3, 0] = -8.5e-5
72
+ coefficients[0, 0, 1] = 2.6
73
+ coefficients[0, 1, 1] = -29e-4
74
+ coefficients[0, 0, 2] = -0.0476
75
+ coefficients[1, 0, 0] = 780
76
+ coefficients[1, 0, 1] = -10
77
+ coefficients[1, 0, 2] = 0.16
78
+ coefficients[2, 0, 0] = -820
79
+
80
+ return water_primary_velocity(temperature, pressure) + salinity * polyval3d(
81
+ sqrt(salinity), temperature, pressure, coefficients
82
+ )
83
+
84
+
85
+ def water_density(
86
+ temperature: np.ndarray | float,
87
+ pressure: np.ndarray | float,
88
+ ) -> np.ndarray | float:
89
+ """
90
+ Density of water,, equation 27a in Batzle & Wang [1].
91
+ :param pressure: Pressure (MPa) of oil
92
+ :param temperature: Temperature (Celsius) of oil.
93
+ :return: Density of water in g/cc.
94
+ """
95
+ coefficients = [
96
+ [1.0, 489e-6, -333e-9],
97
+ [-8e-5, -2e-6, -2e-09],
98
+ [-33e-7, 16e-9, 0.0],
99
+ [1.75e-9, -13e-12, 0.0],
100
+ ]
101
+ return polyval2d(temperature, pressure, coefficients)
102
+
103
+
104
+ def water_primary_velocity(
105
+ temperature: np.ndarray | float,
106
+ pressure: np.ndarray | float,
107
+ ) -> np.ndarray | float:
108
+ """
109
+ Primary wave velocity of water, table 1 and equation 28 in Batzle & Wang [1].
110
+ :param pressure: Pressure (MPa) of oil
111
+ :param temperature: Temperature (Celsius) of oil.
112
+ :return: primary wave velocity of water in m/s.
113
+ """
114
+ if np.any(pressure > 100):
115
+ warnings.warn(
116
+ "Calculations for water velocity is not precise for\n"
117
+ + "pressure outside [0,100]MPa"
118
+ + f"pressure given: {pressure}MPa",
119
+ stacklevel=1,
120
+ )
121
+ coefficients = [
122
+ [1402.85, 1.524, 3.437e-3, -1.197e-5],
123
+ [4.871, -1.11e-2, 1.739e-4, -1.628e-6],
124
+ [-4.783e-2, 2.747e-4, -2.135e-6, 1.237e-8],
125
+ [1.487e-4, -6.503e-7, -1.455e-8, 1.327e-10],
126
+ [-2.197e-7, 7.987e-10, 5.23e-11, -4.614e-13],
127
+ ]
128
+ return polyval2d(temperature, pressure, coefficients)
129
+
130
+
131
+ def water(
132
+ temperature: np.ndarray | float, pressure: np.ndarray | float
133
+ ) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
134
+ """
135
+ :param pressure: Pressure (Pa) of oil
136
+ :param temperature: Temperature (Celsius) of oil.
137
+ :return: water_density [kg/m^3], water_velocity [m/s], water_bulk_modulus [Pa]
138
+ """
139
+ pressure_mpa = pressure * 1.0e-6
140
+ water_den = water_density(temperature, pressure_mpa)
141
+ water_vel = water_primary_velocity(temperature, pressure_mpa)
142
+ water_k = water_vel**2 * water_den * 1000.0
143
+ return water_den, water_vel, water_k
@@ -0,0 +1,5 @@
1
+ from .gas_properties import gas_properties
2
+
3
+ __all__ = [
4
+ "gas_properties",
5
+ ]
@@ -0,0 +1,277 @@
1
+ import numpy as np
2
+ from numpy import exp, sqrt
3
+ from scipy.constants import gas_constant
4
+
5
+ from rock_physics_open.equinor_utilities.conversions import celsius_to_kelvin
6
+
7
+ AIR_WEIGHT = 28.8 # g/mol
8
+
9
+
10
+ def gas_properties(
11
+ temperature: np.ndarray | float,
12
+ pressure: np.ndarray | float,
13
+ gas_gravity: np.ndarray | float,
14
+ model: str | None = None,
15
+ ) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
16
+ """
17
+ :param gas_gravity: molar mass of gas relative to air molar mas.
18
+ :param pressure: Confining pressure (Pa)
19
+ :param temperature: Temperature (Celsius).
20
+ :param model: for future use
21
+ :return: vel_gas [m/s], den_gas [kg/m^3], k_gas [Pa], eta_gas [cP]
22
+ """
23
+ den_gas = gas_density(celsius_to_kelvin(temperature), pressure * 1e-6, gas_gravity)
24
+ k_gas = gas_bulk_modulus(
25
+ celsius_to_kelvin(temperature), pressure * 1e-6, gas_gravity
26
+ )
27
+ vel_gas = (k_gas / den_gas) ** 0.5
28
+
29
+ eta_gas = lee_gas_viscosity(celsius_to_kelvin(temperature), pressure, gas_gravity)
30
+
31
+ return vel_gas, den_gas, k_gas, eta_gas
32
+
33
+
34
+ def molecular_weight(gas_gravity: np.ndarray | float) -> np.ndarray | float:
35
+ """
36
+ calculates molecluar weight of a gas from gas gravity.
37
+ :param gas_gravity: molar mass of gas relative to air molar mas.
38
+ :return: The volume of the gas in g/mol.
39
+ """
40
+ return gas_gravity * AIR_WEIGHT
41
+
42
+
43
+ def molar_volume(
44
+ absolute_temperature: np.ndarray | float,
45
+ pressure: np.ndarray | float,
46
+ ) -> np.ndarray | float:
47
+ """
48
+ calculates molar volume using the ideal gas law.
49
+ :param absolute_temperature: The absolute temperature of the gas in kelvin.
50
+ :param pressure: Confining pressure in MPa.
51
+ :return: The volume of the gas in cc/mol.
52
+ """
53
+ return gas_constant * absolute_temperature / pressure
54
+
55
+
56
+ def ideal_gas_density(
57
+ absolute_temperature: np.ndarray | float,
58
+ pressure: np.ndarray | float,
59
+ gas_gravity: np.ndarray | float,
60
+ ) -> np.ndarray | float:
61
+ """
62
+ calculates molar volume using the ideal gas law.
63
+ :param gas_gravity: molar mass of gas relative to air molar mas.
64
+ :param absolute_temperature: The absolute temperature of the gas in kelvin.
65
+ :param pressure: Confining pressure in MPa.
66
+ :return: The density of the gas in g/cc
67
+ """
68
+ return molecular_weight(gas_gravity) / molar_volume(absolute_temperature, pressure)
69
+
70
+
71
+ def ideal_gas_primary_velocity(
72
+ absolute_temperature: np.ndarray | float,
73
+ gas_gravity: np.ndarray | float,
74
+ ) -> np.ndarray | float:
75
+ """
76
+ :param gas_gravity: molar mass of gas relative to air molar mas.
77
+ :param absolute_temperature: The absolute temperature of the gas in kelvin.
78
+ :return: The compressional wave velocity of the gas in m/s.
79
+ """
80
+ return sqrt(gas_constant * absolute_temperature / molecular_weight(gas_gravity))
81
+
82
+
83
+ def ideal_gas(
84
+ absolute_temperature: np.ndarray | float,
85
+ pressure: np.ndarray | float,
86
+ gas_gravity: np.ndarray | float,
87
+ ) -> tuple[np.ndarray | float, np.ndarray | float]:
88
+ """
89
+ :param gas_gravity: molar mass of gas relative to air molar mas.
90
+ :param absolute_temperature: The absolute temperature of the gas in kelvin.
91
+ :param pressure: Confining pressure in Pa.
92
+ :return: ideal_gas_density, ideal_gas_velocity
93
+ """
94
+ ideal_gas_den = 1000 * ideal_gas_density(
95
+ absolute_temperature, pressure * 1e6, gas_gravity
96
+ )
97
+ ideal_gas_vel = ideal_gas_primary_velocity(absolute_temperature, gas_gravity)
98
+ return ideal_gas_den, ideal_gas_vel
99
+
100
+
101
+ def pseudoreduced_temperature(
102
+ absolute_temperature: np.ndarray | float,
103
+ gas_gravity: np.ndarray | float,
104
+ ) -> np.ndarray | float:
105
+ """
106
+ calculates pseudoreduced temperature, equation 9a from Batzle & Wang [1].
107
+
108
+ Uses relationship from
109
+
110
+ Thomas, L. K., Hankinson, R. W., and Phillips, K. A., 1970,
111
+ Determination of acoustic velocities for natural gas: J. Petr.
112
+ Tech., 22, 889-892.
113
+
114
+ :param gas_gravity: molar mass of gas relative to air molar mas.
115
+ :param absolute_temperature: The absolute temperature of the gas in kelvin.
116
+ :return: Pseudoreduced temperature in kelvin.
117
+ """
118
+ return absolute_temperature / (94.72 + 170.75 * gas_gravity)
119
+
120
+
121
+ def pseudoreduced_pressure(
122
+ pressure: np.ndarray | float,
123
+ gas_gravity: np.ndarray | float,
124
+ ) -> np.ndarray | float:
125
+ """
126
+ calculates pseudoreduced pressure, equation 9a from Batzle & Wang [1].
127
+
128
+ Uses relationship from
129
+
130
+ Thomas, L. K., Hankinson, R. W., and Phillips, K. A., 1970,
131
+ Determination of acoustic velocities for natural gas: J. Petr.
132
+ Tech., 22, 889-892.
133
+
134
+ :param gas_gravity: molar mass of gas relative to air molar mas.
135
+ :param pressure: Confining pressure in MPa.
136
+ :return: Pseudoreduced pressure in MPa.
137
+ """
138
+ return pressure / (4.892 - 0.4048 * gas_gravity)
139
+
140
+
141
+ def compressability_factor(
142
+ absolute_temperature: np.ndarray | float,
143
+ pressure: np.ndarray | float,
144
+ gas_gravity: np.ndarray | float,
145
+ ) -> np.ndarray | float:
146
+ """
147
+ calculates compressability hydro-carbon gas, equation 10b and 10c from
148
+ Batzle & Wang [1].
149
+
150
+ :param gas_gravity: molar mass of gas relative to air molar mas.
151
+ :param absolute_temperature: The absolute temperature of the gas in kelvin.
152
+ :param pressure: Confining pressure in MPa.
153
+ :return: The density of the gas in g/cc
154
+ """
155
+ tpr = pseudoreduced_temperature(absolute_temperature, gas_gravity)
156
+ ppr = pseudoreduced_pressure(pressure, gas_gravity)
157
+
158
+ return (
159
+ (0.03 + 0.00527 * (3.5 - tpr) ** 3) * ppr
160
+ + 0.642 * tpr
161
+ - 0.007 * tpr**4
162
+ - 0.52
163
+ + 0.109
164
+ * (3.85 - tpr) ** 2
165
+ / exp((0.45 + 8 * (0.56 - 1 / tpr) ** 2) * ppr**1.2 / tpr)
166
+ )
167
+
168
+
169
+ def gas_density(
170
+ absolute_temperature: np.ndarray | float,
171
+ pressure: np.ndarray | float,
172
+ gas_gravity: np.ndarray | float,
173
+ ) -> np.ndarray | float:
174
+ """
175
+ The density of hydro-carbon gas, using equation 10 from Batzle & Wang [1].
176
+
177
+ :param gas_gravity: molar mass of gas relative to air molar mas.
178
+ :param absolute_temperature: The absolute temperature of the gas in kelvin.
179
+ :param pressure: Confining pressure in MPa.
180
+ :return: The density of the gas in g/cc
181
+ """
182
+ ideal_gas_den, ideal_gas_vel = ideal_gas(
183
+ absolute_temperature, pressure * 1e-6, gas_gravity
184
+ )
185
+ return ideal_gas_den / compressability_factor(
186
+ absolute_temperature, pressure, gas_gravity
187
+ )
188
+
189
+
190
+ def compressability_rate_per_pseudoreduced_pressure(
191
+ absolute_temperature: np.ndarray | float,
192
+ pressure: np.ndarray | float,
193
+ gas_gravity: np.ndarray | float,
194
+ ) -> np.ndarray | float:
195
+ """
196
+ Derivate of compressability_factor with respect to pressure.
197
+
198
+ :param gas_gravity: molar mass of gas relative to air molar mas.
199
+ :param absolute_temperature: The absolute temperature of the gas in kelvin.
200
+ :param pressure: Confining pressure in MPa.
201
+ :return: The density of the gas in g/cc
202
+ """
203
+ tpr = pseudoreduced_temperature(absolute_temperature, gas_gravity)
204
+ ppr = pseudoreduced_pressure(pressure, gas_gravity)
205
+
206
+ return (
207
+ 0.03
208
+ + 0.00527 * (3.5 - tpr) ** 3
209
+ - (
210
+ 0.1308
211
+ * (0.45 + 8 * (0.56 - tpr ** (-1)) ** 2)
212
+ * (3.85 - tpr) ** 2
213
+ * ppr**0.2
214
+ )
215
+ / (exp(((0.45 + 8 * (0.56 - tpr ** (-1)) ** 2) * ppr**1.2) / tpr) * tpr)
216
+ )
217
+
218
+
219
+ def gas_bulk_modulus(
220
+ absolute_temperature: np.ndarray | float,
221
+ pressure: np.ndarray | float,
222
+ gas_gravity: np.ndarray | float,
223
+ ) -> np.ndarray | float:
224
+ """
225
+ The bulk modulus of hydro-carbon gas, using equation 11 from Batzle & Wang [1].
226
+
227
+ :param gas_gravity: molar mass of gas relative to air molar mas.
228
+ :param absolute_temperature: The absolute temperature of the gas in kelvin.
229
+ :param pressure: Confining pressure in MPa.
230
+ :return: The bulk modulus of the gas in MPa.
231
+ """
232
+ z = compressability_factor(absolute_temperature, pressure, gas_gravity)
233
+ dz_dppr = compressability_rate_per_pseudoreduced_pressure(
234
+ absolute_temperature, pressure, gas_gravity
235
+ )
236
+
237
+ ppr = pseudoreduced_pressure(pressure, gas_gravity)
238
+
239
+ # Equation 11b
240
+ gamma_0 = (
241
+ 0.85
242
+ + 5.6 / (ppr + 2)
243
+ + 27.1 / ((ppr + 3.5) ** 2)
244
+ - 8.7 * exp(-0.65 * (ppr + 1))
245
+ )
246
+
247
+ return gamma_0 * pressure / (1 - dz_dppr * ppr / z)
248
+
249
+
250
+ def lee_gas_viscosity(
251
+ absolute_temperature: np.ndarray | float,
252
+ pressure: np.ndarray | float,
253
+ gas_gravity: np.ndarray | float,
254
+ ) -> np.ndarray:
255
+ """
256
+ :param absolute_temperature: Absolute temperature of the gas in kelvin.
257
+ :param pressure: Confining pressure in Pa.
258
+ :param gas_gravity: specific gravity of gas relative to air.
259
+ :return: gas viscosity in cP
260
+
261
+ Reference
262
+ ---------
263
+ Lee, J. D., et al. (1966). "Viscosity of Natural Gas." In The American Institute of
264
+ Chemical Engineers Journal, Volume 12, Issue 6, pp. 1058-1062.
265
+
266
+ Original equation is given in imperial units. Inputs are transformed to temperature
267
+ in Farenheit and pressure in psi
268
+ """
269
+ temp_far = (absolute_temperature - 273.15) * 9.0 / 5.0 + 32.0
270
+ pres_psi = pressure / 6894.757
271
+ return (
272
+ 0.001
273
+ * (temp_far + 459.67) ** 0.5
274
+ / pres_psi
275
+ * (0.7 + 1.5 * gas_gravity)
276
+ / (gas_gravity + 1) ** 1.5
277
+ )
@@ -0,0 +1,5 @@
1
+ from .oil_properties import oil_properties
2
+
3
+ __all__ = [
4
+ "oil_properties",
5
+ ]