rock-physics-open 0.3.2__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 (145) 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 +211 -0
  4. rock_physics_open/equinor_utilities/classification_functions/__init__.py +17 -0
  5. rock_physics_open/equinor_utilities/classification_functions/class_stats.py +68 -0
  6. rock_physics_open/equinor_utilities/classification_functions/lin_class.py +53 -0
  7. rock_physics_open/equinor_utilities/classification_functions/mahal_class.py +63 -0
  8. rock_physics_open/equinor_utilities/classification_functions/norm_class.py +73 -0
  9. rock_physics_open/equinor_utilities/classification_functions/poly_class.py +45 -0
  10. rock_physics_open/equinor_utilities/classification_functions/post_prob.py +27 -0
  11. rock_physics_open/equinor_utilities/classification_functions/two_step_classification.py +60 -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 +38 -0
  15. rock_physics_open/equinor_utilities/gen_utilities/dim_check_vector.py +113 -0
  16. rock_physics_open/equinor_utilities/gen_utilities/filter_input.py +131 -0
  17. rock_physics_open/equinor_utilities/gen_utilities/filter_output.py +88 -0
  18. rock_physics_open/equinor_utilities/machine_learning_utilities/__init__.py +15 -0
  19. rock_physics_open/equinor_utilities/machine_learning_utilities/base_pressure_model.py +170 -0
  20. rock_physics_open/equinor_utilities/machine_learning_utilities/dummy_vars.py +53 -0
  21. rock_physics_open/equinor_utilities/machine_learning_utilities/exponential_model.py +137 -0
  22. rock_physics_open/equinor_utilities/machine_learning_utilities/import_ml_models.py +77 -0
  23. rock_physics_open/equinor_utilities/machine_learning_utilities/polynomial_model.py +132 -0
  24. rock_physics_open/equinor_utilities/machine_learning_utilities/run_regression.py +209 -0
  25. rock_physics_open/equinor_utilities/machine_learning_utilities/sigmoidal_model.py +241 -0
  26. rock_physics_open/equinor_utilities/optimisation_utilities/__init__.py +19 -0
  27. rock_physics_open/equinor_utilities/optimisation_utilities/opt_subst_utilities.py +455 -0
  28. rock_physics_open/equinor_utilities/snapshot_test_utilities/__init__.py +10 -0
  29. rock_physics_open/equinor_utilities/snapshot_test_utilities/compare_snapshots.py +184 -0
  30. rock_physics_open/equinor_utilities/snapshot_test_utilities/snapshots.py +97 -0
  31. rock_physics_open/equinor_utilities/std_functions/__init__.py +43 -0
  32. rock_physics_open/equinor_utilities/std_functions/backus_ave.py +68 -0
  33. rock_physics_open/equinor_utilities/std_functions/dvorkin_nur.py +77 -0
  34. rock_physics_open/equinor_utilities/std_functions/gassmann.py +165 -0
  35. rock_physics_open/equinor_utilities/std_functions/hashin_shtrikman.py +224 -0
  36. rock_physics_open/equinor_utilities/std_functions/hertz_mindlin.py +51 -0
  37. rock_physics_open/equinor_utilities/std_functions/moduli_velocity.py +67 -0
  38. rock_physics_open/equinor_utilities/std_functions/reflection_eq.py +120 -0
  39. rock_physics_open/equinor_utilities/std_functions/rho.py +69 -0
  40. rock_physics_open/equinor_utilities/std_functions/voigt_reuss_hill.py +149 -0
  41. rock_physics_open/equinor_utilities/std_functions/walton.py +45 -0
  42. rock_physics_open/equinor_utilities/std_functions/wood_brie.py +94 -0
  43. rock_physics_open/equinor_utilities/various_utilities/Equinor_logo.gif +0 -0
  44. rock_physics_open/equinor_utilities/various_utilities/Equinor_logo.ico +0 -0
  45. rock_physics_open/equinor_utilities/various_utilities/__init__.py +24 -0
  46. rock_physics_open/equinor_utilities/various_utilities/display_result_statistics.py +90 -0
  47. rock_physics_open/equinor_utilities/various_utilities/gassmann_dry_mod.py +56 -0
  48. rock_physics_open/equinor_utilities/various_utilities/gassmann_mod.py +56 -0
  49. rock_physics_open/equinor_utilities/various_utilities/gassmann_sub_mod.py +64 -0
  50. rock_physics_open/equinor_utilities/various_utilities/hs_average.py +59 -0
  51. rock_physics_open/equinor_utilities/various_utilities/pressure.py +96 -0
  52. rock_physics_open/equinor_utilities/various_utilities/reflectivity.py +101 -0
  53. rock_physics_open/equinor_utilities/various_utilities/timeshift.py +104 -0
  54. rock_physics_open/equinor_utilities/various_utilities/vp_vs_rho_set_statistics.py +170 -0
  55. rock_physics_open/equinor_utilities/various_utilities/vrh_3_min.py +83 -0
  56. rock_physics_open/fluid_models/__init__.py +9 -0
  57. rock_physics_open/fluid_models/brine_model/__init__.py +5 -0
  58. rock_physics_open/fluid_models/brine_model/brine_properties.py +178 -0
  59. rock_physics_open/fluid_models/gas_model/__init__.py +5 -0
  60. rock_physics_open/fluid_models/gas_model/gas_properties.py +319 -0
  61. rock_physics_open/fluid_models/oil_model/__init__.py +5 -0
  62. rock_physics_open/fluid_models/oil_model/dead_oil_density.py +65 -0
  63. rock_physics_open/fluid_models/oil_model/dead_oil_velocity.py +30 -0
  64. rock_physics_open/fluid_models/oil_model/live_oil_density.py +82 -0
  65. rock_physics_open/fluid_models/oil_model/live_oil_velocity.py +24 -0
  66. rock_physics_open/fluid_models/oil_model/oil_bubble_point.py +69 -0
  67. rock_physics_open/fluid_models/oil_model/oil_properties.py +146 -0
  68. rock_physics_open/sandstone_models/__init__.py +59 -0
  69. rock_physics_open/sandstone_models/cemented_shalysand_sandyshale_models.py +304 -0
  70. rock_physics_open/sandstone_models/constant_cement_models.py +204 -0
  71. rock_physics_open/sandstone_models/constant_cement_optimisation.py +125 -0
  72. rock_physics_open/sandstone_models/contact_cement_model.py +138 -0
  73. rock_physics_open/sandstone_models/curvefit_sandstone_models.py +143 -0
  74. rock_physics_open/sandstone_models/friable_models.py +177 -0
  75. rock_physics_open/sandstone_models/friable_optimisation.py +115 -0
  76. rock_physics_open/sandstone_models/friable_shalysand_sandyshale_models.py +235 -0
  77. rock_physics_open/sandstone_models/patchy_cement_fluid_substitution_model.py +477 -0
  78. rock_physics_open/sandstone_models/patchy_cement_model.py +384 -0
  79. rock_physics_open/sandstone_models/patchy_cement_optimisation.py +254 -0
  80. rock_physics_open/sandstone_models/unresolved_cemented_sandshale_models.py +134 -0
  81. rock_physics_open/sandstone_models/unresolved_friable_sandshale_models.py +126 -0
  82. rock_physics_open/shale_models/__init__.py +19 -0
  83. rock_physics_open/shale_models/dem.py +174 -0
  84. rock_physics_open/shale_models/dem_dual_por.py +61 -0
  85. rock_physics_open/shale_models/kus_tok.py +59 -0
  86. rock_physics_open/shale_models/multi_sca.py +133 -0
  87. rock_physics_open/shale_models/pq.py +102 -0
  88. rock_physics_open/shale_models/sca.py +90 -0
  89. rock_physics_open/shale_models/shale4_mineral.py +147 -0
  90. rock_physics_open/shale_models/shale4_mineral_dem_overlay.py +92 -0
  91. rock_physics_open/span_wagner/__init__.py +5 -0
  92. rock_physics_open/span_wagner/co2_properties.py +444 -0
  93. rock_physics_open/span_wagner/coefficients.py +165 -0
  94. rock_physics_open/span_wagner/equations.py +104 -0
  95. rock_physics_open/span_wagner/tables/__init__.py +0 -0
  96. rock_physics_open/span_wagner/tables/carbon_dioxide_density.npz +0 -0
  97. rock_physics_open/span_wagner/tables/lookup_table.py +33 -0
  98. rock_physics_open/t_matrix_models/Equinor_logo.ico +0 -0
  99. rock_physics_open/t_matrix_models/__init__.py +35 -0
  100. rock_physics_open/t_matrix_models/carbonate_pressure_substitution.py +124 -0
  101. rock_physics_open/t_matrix_models/curvefit_t_matrix_exp.py +123 -0
  102. rock_physics_open/t_matrix_models/curvefit_t_matrix_min.py +86 -0
  103. rock_physics_open/t_matrix_models/parse_t_matrix_inputs.py +297 -0
  104. rock_physics_open/t_matrix_models/run_t_matrix.py +243 -0
  105. rock_physics_open/t_matrix_models/t_matrix_C.py +210 -0
  106. rock_physics_open/t_matrix_models/t_matrix_opt_fluid_sub_exp.py +137 -0
  107. rock_physics_open/t_matrix_models/t_matrix_opt_fluid_sub_petec.py +167 -0
  108. rock_physics_open/t_matrix_models/t_matrix_opt_forward_model_exp.py +76 -0
  109. rock_physics_open/t_matrix_models/t_matrix_opt_forward_model_min.py +89 -0
  110. rock_physics_open/t_matrix_models/t_matrix_parameter_optimisation_exp.py +176 -0
  111. rock_physics_open/t_matrix_models/t_matrix_parameter_optimisation_min.py +162 -0
  112. rock_physics_open/t_matrix_models/t_matrix_vector/__init__.py +12 -0
  113. rock_physics_open/t_matrix_models/t_matrix_vector/array_functions.py +75 -0
  114. rock_physics_open/t_matrix_models/t_matrix_vector/calc_c_eff.py +163 -0
  115. rock_physics_open/t_matrix_models/t_matrix_vector/calc_isolated.py +95 -0
  116. rock_physics_open/t_matrix_models/t_matrix_vector/calc_kd.py +40 -0
  117. rock_physics_open/t_matrix_models/t_matrix_vector/calc_kd_eff.py +116 -0
  118. rock_physics_open/t_matrix_models/t_matrix_vector/calc_kd_uuv.py +18 -0
  119. rock_physics_open/t_matrix_models/t_matrix_vector/calc_pressure.py +140 -0
  120. rock_physics_open/t_matrix_models/t_matrix_vector/calc_t.py +71 -0
  121. rock_physics_open/t_matrix_models/t_matrix_vector/calc_td.py +42 -0
  122. rock_physics_open/t_matrix_models/t_matrix_vector/calc_theta.py +43 -0
  123. rock_physics_open/t_matrix_models/t_matrix_vector/calc_x.py +33 -0
  124. rock_physics_open/t_matrix_models/t_matrix_vector/calc_z.py +50 -0
  125. rock_physics_open/t_matrix_models/t_matrix_vector/check_and_tile.py +43 -0
  126. rock_physics_open/t_matrix_models/t_matrix_vector/g_tensor.py +140 -0
  127. rock_physics_open/t_matrix_models/t_matrix_vector/iso_av.py +60 -0
  128. rock_physics_open/t_matrix_models/t_matrix_vector/iso_ave_all.py +55 -0
  129. rock_physics_open/t_matrix_models/t_matrix_vector/pressure_input.py +44 -0
  130. rock_physics_open/t_matrix_models/t_matrix_vector/t_matrix_vec.py +278 -0
  131. rock_physics_open/t_matrix_models/t_matrix_vector/velocity_vti_angles.py +81 -0
  132. rock_physics_open/t_matrix_models/tmatrix_python.dll +0 -0
  133. rock_physics_open/t_matrix_models/tmatrix_python.so +0 -0
  134. rock_physics_open/ternary_plots/__init__.py +3 -0
  135. rock_physics_open/ternary_plots/gen_ternary_plot.py +73 -0
  136. rock_physics_open/ternary_plots/shale_prop_ternary.py +337 -0
  137. rock_physics_open/ternary_plots/ternary_patches.py +277 -0
  138. rock_physics_open/ternary_plots/ternary_plot_utilities.py +197 -0
  139. rock_physics_open/ternary_plots/unconventionals_ternary.py +75 -0
  140. rock_physics_open/version.py +34 -0
  141. rock_physics_open-0.3.2.dist-info/METADATA +90 -0
  142. rock_physics_open-0.3.2.dist-info/RECORD +145 -0
  143. rock_physics_open-0.3.2.dist-info/WHEEL +5 -0
  144. rock_physics_open-0.3.2.dist-info/licenses/LICENSE +165 -0
  145. rock_physics_open-0.3.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,170 @@
1
+ import os
2
+ from typing import Literal, cast
3
+
4
+ import numpy as np
5
+ import numpy.typing as npt
6
+ import pandas as pd
7
+ from sklearn.metrics import r2_score
8
+
9
+ from .display_result_statistics import disp_result_stats
10
+
11
+
12
+ def vp_vs_rho_stats(
13
+ vp_observed: npt.NDArray[np.float64] | list[npt.NDArray[np.float64]],
14
+ vs_observed: npt.NDArray[np.float64] | list[npt.NDArray[np.float64]],
15
+ rho_observed: npt.NDArray[np.float64] | list[npt.NDArray[np.float64]],
16
+ vp_estimated: npt.NDArray[np.float64] | list[npt.NDArray[np.float64]],
17
+ vs_estimated: npt.NDArray[np.float64] | list[npt.NDArray[np.float64]],
18
+ rho_estimated: npt.NDArray[np.float64] | list[npt.NDArray[np.float64]],
19
+ fname: str,
20
+ estimated_set_names: str | list[str],
21
+ well_names: str | list[str],
22
+ file_mode: Literal["a", "w"] = "a",
23
+ disp_results: bool = True,
24
+ ) -> None:
25
+ """
26
+ Utility to estimate statistics between vp-vs-rho sets - observed and estimated values. The results are displayed
27
+ on screen (optional) and saved to a .csv file. If the file exists, the results will be appended.
28
+ The statistics consists of RAE (relative absolute error) [fraction], RRMSE (relative root mean squared error)
29
+ [fraction] and R^2 (coefficient of determination) [fraction].
30
+
31
+
32
+ Parameters
33
+ ----------
34
+ vp_observed : np.ndarray or list
35
+ Observed vp [m/s].
36
+ vs_observed : np.ndarray or list
37
+ Observed vs [m/s].
38
+ rho_observed : np.ndarray or list
39
+ Observed density [kg/m^3].
40
+ vp_estimated : np.ndarray or list
41
+ Estimated vp [m/s].
42
+ vs_estimated : np.ndarray or list
43
+ Estimated vs [m/s].
44
+ rho_estimated : np.ndarray or list
45
+ Estimated density [kg/m^3].
46
+ fname : str
47
+ File name for saved results.
48
+ estimated_set_names : str or list
49
+ Name of the estimated vp-vs-rho set(s).
50
+ well_names : str or list
51
+ Well name of the vp-vs-rho set(s).
52
+ file_mode : str
53
+ File open mode, default append.
54
+ disp_results : bool
55
+ Display results on screen.
56
+ """
57
+ if isinstance(estimated_set_names, str):
58
+ estimated_set_names = [estimated_set_names]
59
+ if isinstance(well_names, str):
60
+ well_names = [well_names]
61
+
62
+ _verify(
63
+ vp_observed,
64
+ vs_observed,
65
+ rho_observed,
66
+ vp_estimated,
67
+ vs_estimated,
68
+ rho_estimated,
69
+ set_names=estimated_set_names,
70
+ well_names=well_names,
71
+ file_mode=file_mode,
72
+ )
73
+
74
+ est_frame_columns = [
75
+ "Well",
76
+ "Vp RMAE",
77
+ "Vp RRMSE",
78
+ "Vp R2",
79
+ "Vs RMAE",
80
+ "Vs RRMSE",
81
+ "Vs R2",
82
+ "Rho RMAE",
83
+ "Rho RRMSE",
84
+ "Rho R2",
85
+ ]
86
+ est_frame = pd.DataFrame(columns=est_frame_columns, index=estimated_set_names)
87
+ est_frame.index.name = "Estimated set name"
88
+ est_frame.iloc[:, 0] = well_names # pyright: ignore[reportArgumentType]
89
+
90
+ # If inputs are found to satisfy expectations in _verify, and they are numpy arrays, cast to lists, and run through
91
+ if isinstance(vp_observed, np.ndarray):
92
+ vp_observed = [vp_observed]
93
+ if isinstance(vs_observed, np.ndarray):
94
+ vs_observed = [vs_observed]
95
+ if isinstance(rho_observed, np.ndarray):
96
+ rho_observed = [rho_observed]
97
+ if isinstance(vp_estimated, np.ndarray):
98
+ vp_estimated = [vp_estimated]
99
+ if isinstance(vs_estimated, np.ndarray):
100
+ vs_estimated = [vs_estimated]
101
+ if isinstance(rho_estimated, np.ndarray):
102
+ rho_estimated = [rho_estimated]
103
+
104
+ for i in range(len(vp_observed)):
105
+ res: list[float] = []
106
+ for obs, est in zip(
107
+ [vp_observed[i], vs_observed[i], rho_observed[i]],
108
+ [vp_estimated[i], vs_estimated[i], rho_estimated[i]],
109
+ ):
110
+ rmae = float(
111
+ np.mean(np.abs((est.flatten() - obs.flatten()) / obs.flatten()))
112
+ )
113
+ rrmse: float = np.sqrt(
114
+ np.mean(np.square((est.flatten() - obs.flatten()) / obs.flatten()))
115
+ )
116
+ r2 = cast(float, r2_score(obs.flatten(), est.flatten()))
117
+
118
+ res.append(rmae)
119
+ res.append(rrmse)
120
+ res.append(r2)
121
+
122
+ res_dict = dict(zip(est_frame_columns[1:], res))
123
+ est_frame.iloc[i, 1:] = res_dict # pyright: ignore[reportArgumentType]
124
+ if disp_results:
125
+ disp_result_stats(
126
+ estimated_set_names[i], res, est_frame_columns[1:], values_only=True
127
+ )
128
+ # Test if the file already exists. If so, and the file_mode is set to 'a', drop the column headers when writing
129
+ # the file
130
+ if os.path.exists(fname) and file_mode == "a":
131
+ est_frame.to_csv(fname, mode=file_mode, header=False)
132
+ else:
133
+ est_frame.to_csv(fname, mode=file_mode)
134
+
135
+
136
+ def _verify(
137
+ *args: npt.NDArray[np.float64] | list[npt.NDArray[np.float64]],
138
+ set_names: list[str],
139
+ well_names: list[str],
140
+ file_mode: Literal["a", "w"],
141
+ ):
142
+ """Verify that arguments are either numpy arrays or lists of numpy arrays.
143
+ Raises
144
+ ------
145
+ ValueError
146
+ If not np.ndarray or list of such.
147
+ ValueError
148
+ If an entry contains NaNs.
149
+ ValueError
150
+ If an entry contains Infs.
151
+ ValueError
152
+ If mismatch in argument lengths.
153
+ ValueError
154
+ If file mode not 'a' or 'w'.
155
+ """
156
+ # Verify that args are either numpy arrays or list of arrays
157
+ for arg in args:
158
+ if isinstance(arg, np.ndarray):
159
+ arg = [arg]
160
+ for this_arg in arg:
161
+ if not isinstance(this_arg, np.ndarray): # pyright: ignore[reportUnnecessaryIsInstance] | For backward compatibility
162
+ raise ValueError(f"{__file__}: input not numpy array: {type(arg)}")
163
+ if np.any(np.isnan(this_arg)):
164
+ raise ValueError(f"{__file__}: input contains NaNs")
165
+ if np.any(np.isinf(this_arg)):
166
+ raise ValueError(f"{__file__}: input contains Infs")
167
+ if not len(arg) == len(set_names) == len(well_names):
168
+ raise ValueError(f"{__file__}: mismatch in argument lengths")
169
+ if not (file_mode == "a" or file_mode == "w"):
170
+ raise ValueError(f'{__file__}: file_mode must be one of ["a", "w"]') # pyright: ignore[reportUnreachable] | For backward compatibility
@@ -0,0 +1,83 @@
1
+ import numpy as np
2
+ import numpy.typing as npt
3
+
4
+ from rock_physics_open.equinor_utilities import std_functions
5
+
6
+
7
+ def min_3_voigt_reuss_hill(
8
+ vp1: npt.NDArray[np.float64],
9
+ vs1: npt.NDArray[np.float64],
10
+ rhob1: npt.NDArray[np.float64],
11
+ f1: npt.NDArray[np.float64],
12
+ vp2: npt.NDArray[np.float64],
13
+ vs2: npt.NDArray[np.float64],
14
+ rhob2: npt.NDArray[np.float64],
15
+ f2: npt.NDArray[np.float64],
16
+ vp3: npt.NDArray[np.float64],
17
+ vs3: npt.NDArray[np.float64],
18
+ rhob3: npt.NDArray[np.float64],
19
+ f3: npt.NDArray[np.float64],
20
+ ) -> tuple[
21
+ npt.NDArray[np.float64],
22
+ npt.NDArray[np.float64],
23
+ npt.NDArray[np.float64],
24
+ npt.NDArray[np.float64],
25
+ npt.NDArray[np.float64],
26
+ npt.NDArray[np.float64],
27
+ npt.NDArray[np.float64],
28
+ ]:
29
+ """
30
+ Mix of three phases by Voigt-Reuss-Hill model. The fractions should add up to 1 with input of vp, vs and rho.
31
+
32
+ Parameters
33
+ ----------
34
+ vp1 : np.ndarray
35
+ Pressure wave velocity of phase 1 [m/s].
36
+ vs1 : np.ndarray
37
+ Shear wave velocity of phase 1 [m/s].
38
+ rhob1 : np.ndarray
39
+ Bulk density of phase 1 [kg/m^3].
40
+ f1 : np.ndarray
41
+ Fraction of phase 1 [fraction].
42
+ vp2 : np.ndarray
43
+ Pressure wave velocity of phase 2 [m/s].
44
+ vs2 : np.ndarray
45
+ Shear wave velocity of phase 2 [m/s].
46
+ rhob2 : np.ndarray
47
+ Bulk density of phase 2 [kg/m^3].
48
+ f2 : np.ndarray
49
+ Fraction of phase 2 [fraction].
50
+ vp3 : np.ndarray
51
+ Pressure wave velocity of phase 3 [m/s].
52
+ vs3 : np.ndarray
53
+ Shear wave velocity of phase 3 [m/s].
54
+ rhob3 : np.ndarray
55
+ Bulk density of phase 3 [kg/m^3].
56
+ f3 : np.ndarray
57
+ Fraction of phase 3 [fraction].
58
+
59
+ Returns
60
+ -------
61
+ tuple
62
+ vp, vs, rhob, ai, vp_vs, k, mu : np.ndarray.
63
+ vp: pressure wave velocity [m/s], vs: shear wave velocity [m/s], rhob: bulk density [kg/m^3],
64
+ ai: acoustic impedance [m/s x kg/m^3], vp_vs: velocity ratio [ratio],
65
+ k: effective bulk modulus [Pa], mu: effective shear modulus [Pa].
66
+ """
67
+ k1, mu1 = std_functions.moduli(vp1, vs1, rhob1)
68
+ k2, mu2 = std_functions.moduli(vp2, vs2, rhob2)
69
+ k3, mu3 = std_functions.moduli(vp3, vs3, rhob3)
70
+
71
+ # Normalise the fractions to make sure they sum to one
72
+ tot = f1 + f2 + f3
73
+ f1 = f1 / tot
74
+ f2 = f2 / tot
75
+ f3 = f3 / tot
76
+
77
+ k, mu = std_functions.multi_voigt_reuss_hill(k1, mu1, f1, k2, mu2, f2, k3, mu3, f3)
78
+
79
+ rhob = rhob1 * f1 + rhob2 * f2 + rhob3 * f3
80
+
81
+ vp, vs, ai, vp_vs = std_functions.velocity(k, mu, rhob)
82
+
83
+ 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,178 @@
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]
19
+ :param temperature: Temperature [°C]
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: Brine velocity vel_b [m/s], brine density den_b [kg/m^3], brine bulk modulus k_b [Pa]
24
+ """
25
+ vel_b = brine_primary_velocity(temperature, pressure, salinity)
26
+ den_b = brine_density(temperature, pressure, salinity)
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 in ppm
39
+ :param pressure: Pressure [Pa]
40
+ :param temperature: Temperature [°C]
41
+ :return: density of solution in [kg/m^3].
42
+ """
43
+ # Change unit of pressure to MPa
44
+ pressure_mpa = pressure / 1.0e6
45
+ # Change unit of salinity to fraction
46
+ salinity_frac = salinity / 1.0e6
47
+
48
+ coefficients = [
49
+ [[0.668, 3e-4], [8e-5, -13e-6], [3e-6, 0.0]],
50
+ [[0.44, -24e-4], [-33e-4, 47e-6], [0.0, 0.0]],
51
+ ]
52
+ water_den = water_density(temperature, pressure)
53
+ brine_correction = (
54
+ salinity_frac
55
+ * polyval3d(salinity_frac, temperature, pressure_mpa, coefficients)
56
+ * 1000.0
57
+ )
58
+ return water_den + brine_correction
59
+
60
+
61
+ def brine_primary_velocity(
62
+ temperature: np.ndarray | float,
63
+ pressure: np.ndarray | float,
64
+ salinity: np.ndarray | float,
65
+ ) -> np.ndarray | float:
66
+ """
67
+ Primary wave velocity of sodium chloride solutions, equation 29 in Batzle & Wang [1]
68
+
69
+ :param salinity: Salinity of solution as [ppm] of sodium chloride
70
+ :param pressure: Pressure [Pa]
71
+ :param temperature: Temperature [°C]
72
+ :return: velocity of solution in m/s.
73
+ """
74
+ # Change unit for salinity from ppm to fraction
75
+ salinity_frac = salinity / 1.0e6
76
+ # Change the unit for pressure from Pa to MPa
77
+ pressure_mpa = pressure / 1.0e6
78
+
79
+ coefficients = np.zeros((3, 4, 3))
80
+ coefficients[0, 0, 0] = 1170
81
+ coefficients[0, 1, 0] = -9.6
82
+ coefficients[0, 2, 0] = 0.055
83
+ coefficients[0, 3, 0] = -8.5e-5
84
+ coefficients[0, 0, 1] = 2.6
85
+ coefficients[0, 1, 1] = -29e-4
86
+ coefficients[0, 0, 2] = -0.0476
87
+ coefficients[1, 0, 0] = 780
88
+ coefficients[1, 0, 1] = -10
89
+ coefficients[1, 0, 2] = 0.16
90
+ coefficients[2, 0, 0] = -820
91
+
92
+ return water_primary_velocity(temperature, pressure) + salinity_frac * polyval3d(
93
+ sqrt(salinity_frac), temperature, pressure_mpa, coefficients
94
+ )
95
+
96
+
97
+ def water_density(
98
+ temperature: np.ndarray | float,
99
+ pressure: np.ndarray | float,
100
+ ) -> np.ndarray | float:
101
+ """
102
+ Density of water,, equation 27a in Batzle & Wang [1].
103
+ :param pressure: Pressure [Pa]
104
+ :param temperature: Temperature [°C]
105
+ :return: Density of water in [kg/m^3].
106
+ """
107
+ # Change unit of pressure from Pa to MPa
108
+ pressure_mpa = pressure / 1.0e6
109
+
110
+ coefficients = [
111
+ [1.0, 489e-6, -333e-9],
112
+ [-8e-5, -2e-6, -2e-09],
113
+ [-33e-7, 16e-9, 0.0],
114
+ [1.75e-9, -13e-12, 0.0],
115
+ ]
116
+ return polyval2d(temperature, pressure_mpa, coefficients) * 1000.0
117
+
118
+
119
+ def water_primary_velocity(
120
+ temperature: np.ndarray | float,
121
+ pressure: np.ndarray | float,
122
+ ) -> np.ndarray | float:
123
+ """
124
+ Primary wave velocity of water, table 1 and equation 28 in Batzle & Wang [1].
125
+ :param pressure: Pressure [Pa]
126
+ :param temperature: Temperature [°C]
127
+ :return: primary wave velocity of water in m/s.
128
+ """
129
+ # Change unit of pressure from Pa to MPa
130
+ pressure_mpa = pressure / 1.0e6
131
+
132
+ if np.any(pressure_mpa > 100):
133
+ warnings.warn(
134
+ "Calculations for water velocity is not precise for\n"
135
+ + "pressure outside [0,100]MPa"
136
+ + f"pressure given: {pressure}MPa",
137
+ stacklevel=1,
138
+ )
139
+ coefficients = [
140
+ [1402.85, 1.524, 3.437e-3, -1.197e-5],
141
+ [4.871, -1.11e-2, 1.739e-4, -1.628e-6],
142
+ [-4.783e-2, 2.747e-4, -2.135e-6, 1.237e-8],
143
+ [1.487e-4, -6.503e-7, -1.455e-8, 1.327e-10],
144
+ [-2.197e-7, 7.987e-10, 5.23e-11, -4.614e-13],
145
+ ]
146
+ return polyval2d(temperature, pressure_mpa, coefficients)
147
+
148
+
149
+ def water(
150
+ temperature: np.ndarray | float, pressure: np.ndarray | float
151
+ ) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
152
+ """
153
+ :param pressure: Pressure [Pa]
154
+ :param temperature: Temperature [°C]
155
+ :return: water_velocity [m/s], water_density [kg/m^3], water_bulk_modulus [Pa]
156
+ """
157
+ water_den = water_density(temperature, pressure)
158
+ water_vel = water_primary_velocity(temperature, pressure)
159
+ water_k = water_vel**2 * water_den
160
+ return water_vel, water_den, water_k
161
+
162
+
163
+ def brine_viscosity(
164
+ temperature: np.ndarray | float,
165
+ salinity: np.ndarray | float,
166
+ ) -> np.ndarray | float:
167
+ """
168
+ Brine viscosity according to Batzle & Wang [1].
169
+
170
+ Based on equation 32.
171
+ """
172
+ salinity_frac = salinity / 1.0e6
173
+ return (
174
+ 0.1
175
+ + 0.333 * salinity_frac
176
+ + (1.65 + 91.9 * salinity_frac**3)
177
+ * np.exp(-(0.42 * (salinity_frac**0.8 - 0.17) ** 2 + 0.045) * temperature**0.8)
178
+ )
@@ -0,0 +1,5 @@
1
+ from .gas_properties import gas_properties
2
+
3
+ __all__ = [
4
+ "gas_properties",
5
+ ]