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,90 @@
1
+ import os
2
+ import sys
3
+ from collections.abc import Sequence
4
+ from typing import Any, Literal, cast
5
+
6
+ import numpy as np
7
+ import numpy.typing as npt
8
+
9
+
10
+ def disp_result_stats(
11
+ title: str, arr: Sequence[Any], names_arr: list[str], **kwargs: Any
12
+ ) -> None:
13
+ """
14
+ Display results utilizing tkinter.
15
+
16
+ Parameters
17
+ ----------
18
+ title : Title.
19
+ arr : items to display
20
+ names_arr : array of names.
21
+ """
22
+ from tkinter import END, Entry, PhotoImage, Tk
23
+
24
+ class Table:
25
+ def __init__(
26
+ self, tk_root: Tk, no_rows: int, no_cols: int, info: npt.NDArray[Any]
27
+ ):
28
+ # code for creating table
29
+ str_len = np.vectorize(len)
30
+ text_justify: list[Literal["center", "left"]] = ["center", "left"]
31
+ text_weight: list[str] = ["bold", "normal"]
32
+ for i in range(no_rows):
33
+ weigh = text_weight[cast(int, np.sign(i))]
34
+ for j in range(no_cols):
35
+ just = text_justify[cast(int, np.sign(i))]
36
+ max_len = np.max(str_len(info[:, j]))
37
+ self.e: Entry = Entry(
38
+ tk_root,
39
+ width=max_len + 2,
40
+ fg="black",
41
+ font=("Consolas", 12, weigh),
42
+ justify=just,
43
+ )
44
+ self.e.grid(row=i, column=j)
45
+ self.e.insert(END, info[i][j])
46
+
47
+ values_only = kwargs.pop("values_only", False)
48
+ root = Tk(**kwargs)
49
+ root.title(title)
50
+ if values_only:
51
+ info_array = np.zeros((len(arr) + 1, 2)).astype(str)
52
+ info_array[0, :] = ["Property", "Value"]
53
+ for k in range(len(arr)):
54
+ info_array[k + 1, 0] = f"{names_arr[k]}"
55
+ info_array[k + 1, 1] = f"{arr[k]:.3g}"
56
+ else:
57
+ info_array = np.zeros((len(arr) + 1, 6)).astype(str)
58
+ info_array[0, :] = ["Var", "Min", "Mean", "Max", "No. NaN", "No. of Inf"]
59
+ for k in range(len(arr)):
60
+ info_array[k + 1, 0] = f"{names_arr[k]}"
61
+ info_array[k + 1, 1] = f"{np.nanmin(np.asarray(arr[k])):.3g}"
62
+ info_array[k + 1, 2] = f"{np.nanmean(np.asarray(arr[k])):.3g}"
63
+ info_array[k + 1, 3] = f"{np.nanmax(np.asarray(arr[k])):.3g}"
64
+ info_array[k + 1, 4] = f"{np.sum(np.isnan(np.asarray(arr[k])))}"
65
+ info_array[k + 1, 5] = f"{np.sum(np.isinf(np.asarray(arr[k])))}"
66
+
67
+ _ = Table(root, info_array.shape[0], info_array.shape[1], info_array)
68
+
69
+ root.update_idletasks()
70
+ window_height = root.winfo_height()
71
+ window_width = root.winfo_width()
72
+ screen_width = root.winfo_screenwidth()
73
+ screen_height = root.winfo_screenheight()
74
+
75
+ x_coordinate = int((screen_width / 2) - (window_width / 2))
76
+ y_coordinate = int((screen_height / 2) - (window_height / 2))
77
+
78
+ root.geometry(
79
+ "{}x{}+{}+{}".format(window_width, window_height, x_coordinate, y_coordinate)
80
+ )
81
+
82
+ if sys.platform.startswith("win"):
83
+ root.iconbitmap(os.path.join(os.path.dirname(__file__), "Equinor_logo.ico"))
84
+ else:
85
+ logo = PhotoImage(
86
+ file=os.path.join(os.path.dirname(__file__), "Equinor_logo.gif")
87
+ )
88
+ root.wm_iconphoto(True, logo)
89
+
90
+ root.mainloop()
@@ -0,0 +1,56 @@
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 gassmann_dry_model(
8
+ k_min: npt.NDArray[np.float64],
9
+ k_fl: npt.NDArray[np.float64],
10
+ rho_fl: npt.NDArray[np.float64],
11
+ k_sat: npt.NDArray[np.float64],
12
+ mu: npt.NDArray[np.float64],
13
+ rho_sat: npt.NDArray[np.float64],
14
+ por: npt.NDArray[np.float64],
15
+ ) -> tuple[
16
+ npt.NDArray[np.float64],
17
+ npt.NDArray[np.float64],
18
+ npt.NDArray[np.float64],
19
+ npt.NDArray[np.float64],
20
+ npt.NDArray[np.float64],
21
+ npt.NDArray[np.float64],
22
+ npt.NDArray[np.float64],
23
+ ]:
24
+ """
25
+ Gassmann model to go from saturated rock to dry state.
26
+
27
+ Parameters
28
+ ----------
29
+ k_min : np.ndarray
30
+ Mineral bulk modulus [Pa].
31
+ k_fl : np.ndarray
32
+ Fluid bulk modulus [Pa].
33
+ rho_fl : np.ndarray
34
+ Fluid density [lg/m^3].
35
+ k_sat : np.ndarray
36
+ Saturated rock bulk modulus [Pa].
37
+ mu : np.ndarray
38
+ Saturated rock shear modulus [Pa].
39
+ rho_sat : np.ndarray
40
+ Saturated rock density [kg/m^3].
41
+ por : np.ndarray
42
+ Porosity [fraction].
43
+
44
+ Returns
45
+ -------
46
+ tuple
47
+ vp_dry, vs_dry, rho_dry, ai_dry, vpvs_dry, k_dry, mu : np.ndarray
48
+ vp_dry, vs_dry: dry velocities [m/s], rho_dry: dry density [kg/m^3], ai_dry: dry acoustic impedance
49
+ [kg/m^3 x m/s], vpvs_dry: dry velocity ratio [unitless], k_dry, mu: dry bulk modulus and shear modulus (the
50
+ latter unchanged from saturated state) [Pa].
51
+ """
52
+ rho_dry = rho_sat - por * rho_fl
53
+ k_dry = std_functions.gassmann_dry(k_sat, por, k_fl, k_min)
54
+ vp_dry, vs_dry, ai_dry, vpvs_dry = std_functions.velocity(k_dry, mu, rho_dry)
55
+
56
+ return vp_dry, vs_dry, rho_dry, ai_dry, vpvs_dry, k_dry, mu
@@ -0,0 +1,56 @@
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 gassmann_model(
8
+ k_min: npt.NDArray[np.float64],
9
+ k_fl: npt.NDArray[np.float64],
10
+ rho_fl: npt.NDArray[np.float64],
11
+ k_dry: npt.NDArray[np.float64],
12
+ mu: npt.NDArray[np.float64],
13
+ rho_dry: npt.NDArray[np.float64],
14
+ por: npt.NDArray[np.float64],
15
+ ) -> tuple[
16
+ npt.NDArray[np.float64],
17
+ npt.NDArray[np.float64],
18
+ npt.NDArray[np.float64],
19
+ npt.NDArray[np.float64],
20
+ npt.NDArray[np.float64],
21
+ npt.NDArray[np.float64],
22
+ npt.NDArray[np.float64],
23
+ ]:
24
+ """
25
+ Gassmann model to go from dry rock to saturated state.
26
+
27
+ Parameters
28
+ ----------
29
+ k_min : np.ndarray
30
+ Mineral bulk modulus [Pa].
31
+ k_fl : np.ndarray
32
+ Fluid bulk modulus [Pa].
33
+ rho_fl : np.ndarray
34
+ Fluid density [lg/m^3].
35
+ k_dry : np.ndarray
36
+ Dry rock bulk modulus [Pa].
37
+ mu : np.ndarray
38
+ Dry rock shear modulus [Pa].
39
+ rho_dry : np.ndarray
40
+ Dry rock density [kg/m^3].
41
+ por : np.ndarray
42
+ Porosity [fraction].
43
+
44
+ Returns
45
+ -------
46
+ tuple
47
+ vp_sat, vs_sat, rho_sat, ai_sat, vpvs_sat, k_sat, mu : np.ndarray
48
+ vp_sat, vs_sat: saturated velocities [m/s], rho_sat: saturated density [kg/m^3], ai_sat: saturated acoustic
49
+ impedance [kg/m^3 x m/s], vpvs_sat: saturated velocity ratio [unitless], k_sat, mu: saturated bulk modulus and
50
+ shear modulus (the latter unchanged from dry state) [Pa].
51
+ """
52
+ rho_sat = rho_dry + por * rho_fl
53
+ k_sat = std_functions.gassmann(k_dry, por, k_fl, k_min)
54
+ vp_sat, vs_sat, ai_sat, vpvs_sat = std_functions.velocity(k_sat, mu, rho_sat)
55
+
56
+ return vp_sat, vs_sat, rho_sat, ai_sat, vpvs_sat, k_sat, mu
@@ -0,0 +1,64 @@
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 gassmann_sub_model(
8
+ k_min: npt.NDArray[np.float64],
9
+ k_fl_orig: npt.NDArray[np.float64],
10
+ rho_fl_orig: npt.NDArray[np.float64],
11
+ k_fl_sub: npt.NDArray[np.float64],
12
+ rho_fl_sub: npt.NDArray[np.float64],
13
+ k_sat_orig: npt.NDArray[np.float64],
14
+ mu: npt.NDArray[np.float64],
15
+ rho_sat_orig: npt.NDArray[np.float64],
16
+ por: npt.NDArray[np.float64],
17
+ ) -> tuple[
18
+ npt.NDArray[np.float64],
19
+ npt.NDArray[np.float64],
20
+ npt.NDArray[np.float64],
21
+ npt.NDArray[np.float64],
22
+ npt.NDArray[np.float64],
23
+ npt.NDArray[np.float64],
24
+ npt.NDArray[np.float64],
25
+ ]:
26
+ """
27
+ Gassmann model to go from one saturated state to another.
28
+
29
+ Parameters
30
+ ----------
31
+ k_min : np.ndarray
32
+ Mineral bulk modulus [Pa].
33
+ k_fl_orig : np.ndarray
34
+ Original fluid bulk modulus [Pa].
35
+ rho_fl_orig : np.ndarray
36
+ Original fluid density [lg/m^3].
37
+ k_fl_sub : np.ndarray
38
+ Substituted fluid bulk modulus [Pa].
39
+ rho_fl_sub : np.ndarray
40
+ Substituted fluid density [lg/m^3].
41
+ k_sat_orig : np.ndarray
42
+ Saturated rock bulk modulus with original fluid [Pa].
43
+ mu : np.ndarray
44
+ Rock shear modulus [Pa].
45
+ rho_sat_orig : np.ndarray
46
+ Saturated rock density with original fluid [kg/m^3].
47
+ por : np.ndarray
48
+ Porosity [fraction].
49
+
50
+ Returns
51
+ -------
52
+ tuple
53
+ vp_sat, vs_sat, rho_sat, ai_sat, vpvs_sat, k_sat, mu : np.ndarray
54
+ vp_sat, vs_sat: saturated velocities [m/s], rho_sat: saturated density [kg/m^3], ai_sat: saturated acoustic
55
+ impedance [kg/m^3 x m/s], vpvs_sat: saturated velocity ratio [unitless], k_sat, mu: saturated bulk modulus and
56
+ shear modulus (the latter unchanged from dry state) [Pa].
57
+ """
58
+ rho_sat_sub = rho_sat_orig + por * (rho_fl_sub - rho_fl_orig)
59
+ k_sat_sub = std_functions.gassmann2(k_sat_orig, k_fl_orig, k_fl_sub, por, k_min)
60
+ vp_sat_sub, vs_sat_sub, ai_sat_sub, vpvs_sat_sub = std_functions.velocity(
61
+ k_sat_sub, mu, rho_sat_sub
62
+ )
63
+
64
+ return vp_sat_sub, vs_sat_sub, rho_sat_sub, ai_sat_sub, vpvs_sat_sub, k_sat_sub, mu
@@ -0,0 +1,59 @@
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 hs_average(
8
+ k1: npt.NDArray[np.float64],
9
+ mu1: npt.NDArray[np.float64],
10
+ rhob1: npt.NDArray[np.float64],
11
+ k2: npt.NDArray[np.float64],
12
+ mu2: npt.NDArray[np.float64],
13
+ rhob2: npt.NDArray[np.float64],
14
+ f: npt.NDArray[np.float64],
15
+ ) -> tuple[
16
+ npt.NDArray[np.float64],
17
+ npt.NDArray[np.float64],
18
+ npt.NDArray[np.float64],
19
+ npt.NDArray[np.float64],
20
+ npt.NDArray[np.float64],
21
+ npt.NDArray[np.float64],
22
+ npt.NDArray[np.float64],
23
+ ]:
24
+ """
25
+ BMix of two phases by Hashin-Shtrikman model. Derived properties are also returned.
26
+
27
+ Parameters
28
+ ----------
29
+ k1 : np.ndarray
30
+ k1 array.
31
+ mu1 : np.ndarray
32
+ mu1 array.
33
+ rhob1 : np.ndarray
34
+ rhob1 array.
35
+ k2 : np.ndarray
36
+ k2 array.
37
+ mu2 : np.ndarray
38
+ mu2 array.
39
+ rhob2 : np.ndarray
40
+ rhob2 array.
41
+ f : float or np.ndarray
42
+ f value or array.
43
+
44
+ Returns
45
+ -------
46
+ tuple
47
+ vp, vs, rhob, ai, vp_vs, k, mu : np.ndarray
48
+ vp: compressional wave velocity [m/s], vs: shear wave velocity [m/s], ai: acoustic impedance [m/s x kg/m^3],
49
+ vp_vs: velocity ratio [ratio], k: bulk modulus [Pa], mu: shear modulus [Pa]
50
+
51
+ """
52
+
53
+ k, mu = std_functions.hashin_shtrikman_average(k1, mu1, k2, mu2, f)
54
+
55
+ rhob = rhob1 * f + rhob2 * (1 - f)
56
+
57
+ vp, vs, ai, vp_vs = std_functions.velocity(k, mu, rhob)
58
+
59
+ return vp, vs, rhob, ai, vp_vs, k, mu
@@ -0,0 +1,96 @@
1
+ import numpy as np
2
+ import numpy.typing as npt
3
+
4
+
5
+ def pressure(
6
+ rho: npt.NDArray[np.float64],
7
+ tvd_msl: npt.NDArray[np.float64],
8
+ water_depth: float,
9
+ p_form: float,
10
+ tvd_p_form: float,
11
+ n: float,
12
+ ) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]:
13
+ """
14
+ Function to estimate overburden pressure and vertical effective stress (lithostatic pressure)
15
+ based on density.
16
+
17
+ Parameters
18
+ ----------
19
+ rho : np.ndarray
20
+ Density log [kg/m3].
21
+ tvd_msl : np.ndarray
22
+ Vertical depth log [m].
23
+ water_depth : float
24
+ Down to this point the difference between formation pressure and overburden pressure shall be zero [m].
25
+ p_form : float
26
+ Formation pressure [Pa].
27
+ tvd_p_form : float
28
+ Depth of formation pressure point [m].
29
+ n: float
30
+ Biot coefficient [unitless].
31
+
32
+ Returns
33
+ -------
34
+ tuple
35
+ p_eff, p_lith : np.ndarray.
36
+ p_eff [Pa] - effective pressure,
37
+ p_lith [Pa] - overburden pressure.
38
+ """
39
+
40
+ # Standard brine density with salinity 40000 ppm, 2 MPa and 4 deg. C
41
+ rho_brine = 1.03e3
42
+ # Gravity constant
43
+ g = 9.80665
44
+ # Input log length
45
+ log_length = len(rho)
46
+
47
+ # Allocate output logs
48
+ p_eff = np.ones(log_length) * np.nan
49
+ p_lith = np.ones(log_length) * np.nan
50
+
51
+ # Does the depth log start at, above or below the sea bottom? We want it to
52
+ # start at sea bottom, so we get rid of values above this point.
53
+ # Also, as the tvd log normally is calculated by calling application, there can be
54
+ # undefined values, flagged as negative or NaN
55
+ idx = np.ones_like(rho, dtype=bool)
56
+ idx_inf_nan = np.any(
57
+ [np.isnan(rho), np.isinf(rho), np.isnan(tvd_msl), np.isinf(tvd_msl)], axis=0
58
+ )
59
+ idx[idx_inf_nan] = False
60
+ idx[~idx_inf_nan] = np.logical_and(
61
+ tvd_msl[~idx_inf_nan] >= water_depth, rho[~idx_inf_nan] > 0
62
+ )
63
+
64
+ # We need a starting point for pressure at water bottom - use a standard
65
+ # density value
66
+ p_wb = g * rho_brine * water_depth
67
+
68
+ # p_form is a single value. No functionality is added at present to handle p_form in log version
69
+ # Find which depth in the log that matches the calibration point best
70
+ calib_point = np.argmin(abs(tvd_msl[idx] - tvd_p_form))
71
+
72
+ # Overburden pressure
73
+ dz = np.diff(tvd_msl[idx])
74
+ # Append one sample to match the density log length
75
+ dz = np.append(dz, dz[-1])
76
+
77
+ # Find a starting point for the litho pressure at the start of the depth log
78
+ # Density at water bottom is assumed to be for a sand with 40% porosity. Take the average
79
+ # of this and the first observation of density log
80
+ ave_dens = 0.5 * ((2650 * 0.6 + rho_brine * 0.4) + rho[0])
81
+ p_lith_start = ave_dens * g * (tvd_msl[0] - water_depth)
82
+
83
+ # Estimate the overburden pressure as the gravity of the cumulative bulk
84
+ # density plus the calculated starting point and the fluid pressure at sea bottom
85
+ p_lith[idx] = np.cumsum(g * dz * rho[idx]) + p_lith_start + p_wb
86
+
87
+ # Find the effective/differential pressure at the calibration point
88
+ p_eff_calib = p_lith[idx][calib_point] - n * p_form
89
+ # In the absence of any better alternative - make a linear interpolation
90
+ # from zero at water bottom to the calculated effective pressure at the
91
+ # calibration point
92
+ p_eff[idx] = np.interp(tvd_msl[idx], [water_depth, tvd_p_form], [0, p_eff_calib])
93
+
94
+ p_lith[idx] = np.interp(tvd_msl[idx], tvd_msl[idx], p_lith[idx])
95
+
96
+ return p_eff, p_lith
@@ -0,0 +1,101 @@
1
+ from typing import Literal, cast
2
+
3
+ import numpy as np
4
+ import numpy.typing as npt
5
+
6
+ from rock_physics_open.equinor_utilities import gen_utilities, std_functions
7
+
8
+
9
+ def reflectivity(
10
+ vp_inp: npt.NDArray[np.float64],
11
+ vs_inp: npt.NDArray[np.float64],
12
+ rho_inp: npt.NDArray[np.float64],
13
+ theta: float = 0.0,
14
+ k: float = 2.0,
15
+ model: Literal["AkiRichards", "SmithGidlow"] = "AkiRichards",
16
+ ) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.bool_]]:
17
+ """
18
+ Reflectivity model according to Aki and Richards or Smith and Gidlow for weak contrasts
19
+ and angles less than critical angle.
20
+
21
+ In this function it is not allowed to have any missing values in the input logs.
22
+ Instead of interpolating here without the user knowing, raise an input value
23
+ exception and leave it to the user to provide complete logs.
24
+
25
+ Parameters
26
+ ----------
27
+ vp_inp : np.ndarray
28
+ Compressional wave velocity [m/s].
29
+ vs_inp : np.ndarray
30
+ Shear wave velocity [m/s].
31
+ rho_inp : np.ndarray
32
+ Bulk density [kg/m^3].
33
+ theta : float
34
+ Incidence angle [radians] (default value 0).
35
+ k : float
36
+ Background Vp/Vs ratio [ratio] (default value 2.0).
37
+ model : str
38
+ One of 'AkiRichards' (default) or 'SmithGidlow'.
39
+
40
+ Returns
41
+ -------
42
+ tuple
43
+ refl_coef, idx_inp : np.ndarray.
44
+ refl_coef: reflection coefficient [ratio],
45
+ idx_inp: index to accepted part of the input arrays [bool].
46
+ """
47
+
48
+ vp, vs, rho, theta_, k_ = cast(
49
+ list[npt.NDArray[np.float64]],
50
+ gen_utilities.dim_check_vector((vp_inp, vs_inp, rho_inp, theta, k)),
51
+ )
52
+
53
+ idx_inp, (vp, vs, rho, theta_, k_) = cast(
54
+ tuple[npt.NDArray[np.bool_], list[npt.NDArray[np.float64]]],
55
+ gen_utilities.filter_input_log(
56
+ [vp, vs, rho, theta_, k_],
57
+ positive=True,
58
+ ),
59
+ )
60
+
61
+ if np.any(~idx_inp):
62
+ # Only NaNs at the start or end? Find the first and last valid sample and check
63
+ # if there are any invalid samples in between
64
+ first_samp = np.where(idx_inp)[0][0]
65
+ last_samp = np.where(idx_inp)[0][-1]
66
+ if np.any(~idx_inp[first_samp : last_samp + 1]):
67
+ # Find the culprit(s)
68
+ idx_vp = gen_utilities.filter_input_log(
69
+ [vp_inp[first_samp : last_samp + 1]], positive=True
70
+ )[0]
71
+ idx_vs = gen_utilities.filter_input_log(
72
+ [vs_inp[first_samp : last_samp + 1]], positive=True
73
+ )[0]
74
+ idx_rho = gen_utilities.filter_input_log(
75
+ [rho_inp[first_samp : last_samp + 1]], positive=True
76
+ )[0]
77
+ log_str = (
78
+ int(np.any(~idx_vp)) * "Vp, "
79
+ + int(np.any(~idx_vs)) * "Vs, "
80
+ + int(np.any(~idx_rho)) * "Rho, "
81
+ )
82
+ pl_str = (
83
+ (int(np.any(~idx_vp)) + int(np.any(~idx_vs)) + int(np.any(~idx_rho)))
84
+ > 1
85
+ ) * "s"
86
+ raise ValueError(
87
+ "{0:} reflectivity: Missing or illegal values in input log{1:}: {2:}interpolation of input log{1:} is needed\n".format(
88
+ model, log_str, pl_str
89
+ )
90
+ )
91
+
92
+ if model == "AkiRichards":
93
+ refl_coef = std_functions.aki_richards(vp, vs, rho, theta_, k_)
94
+ elif model == "SmithGidlow":
95
+ refl_coef = std_functions.smith_gidlow(vp, vs, rho, theta_, k_)
96
+ else:
97
+ raise ValueError( # pyright: ignore[reportUnreachable] | Kept for backward compatibility
98
+ f'{__file__}: unknown model: {model}, should be one of "AkiRichards", "SmithGidlow"'
99
+ )
100
+
101
+ return refl_coef, idx_inp
@@ -0,0 +1,104 @@
1
+ import numpy as np
2
+ import numpy.typing as npt
3
+
4
+
5
+ def time_shift_pp(
6
+ tvd: npt.NDArray[np.float64],
7
+ vp_base: npt.NDArray[np.float64],
8
+ vp_mon: npt.NDArray[np.float64],
9
+ multiplier: int,
10
+ ) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]:
11
+ """
12
+ Cumulative time shift calculation for 4D case. According to Equinor standard
13
+ the time shift is negative for an increase in velocity from base to monitor
14
+ survey.
15
+
16
+ Parameters
17
+ ----------
18
+ tvd : np.ndarray
19
+ True vertical depth along wellbore [m].
20
+ vp_base : np.ndarray
21
+ Initial Vp [m/s].
22
+ vp_mon : np.ndarray
23
+ vp at time of monitor survey [m/s].
24
+ multiplier : int
25
+ Time shift multiplier.
26
+
27
+ Returns
28
+ -------
29
+ tuple
30
+ owt_pp_shift, twt_pp_shift : np.ndarray.
31
+ owt_pp_shift: one way time shift [ms],
32
+ twt_pp_shift: two way time shift [ms].
33
+
34
+ Notes
35
+ -----
36
+ Original function by Sascha Bussat, Equinor
37
+ Ported to Python by Harald Flesche, Equinor 2016.
38
+
39
+ """
40
+ dx = np.diff(tvd)
41
+ dx = np.append(dx, dx[-1])
42
+
43
+ time_base = np.cumsum(dx / vp_base)
44
+ time_monitor = np.cumsum(dx / vp_mon)
45
+
46
+ owt_pp_shift = (time_monitor - time_base) * 1000 * multiplier
47
+ twt_pp_shift = 2 * owt_pp_shift
48
+
49
+ return owt_pp_shift, twt_pp_shift
50
+
51
+
52
+ def time_shift_ps(
53
+ tvd: npt.NDArray[np.float64],
54
+ vp_base: npt.NDArray[np.float64],
55
+ vp_mon: npt.NDArray[np.float64],
56
+ vs_base: npt.NDArray[np.float64],
57
+ vs_mon: npt.NDArray[np.float64],
58
+ multiplier: int,
59
+ ) -> npt.NDArray[np.float64]:
60
+ """
61
+ Cumulative time shift calculation for 4D case. According to Equinor standard
62
+ the time shift is negative for an increase in velocity from base to monitor
63
+ survey.
64
+
65
+ Parameters
66
+ ----------
67
+ tvd : np.ndarray
68
+ True vertical depth along wellbore [m].
69
+ vp_base : np.ndarray
70
+ Initial vp [m/s].
71
+ vp_mon : np.ndarray
72
+ vs at time of monitor survey [m/s].
73
+ vs_base : np.ndarray
74
+ Initial vp [m/s].
75
+ vs_mon : np.ndarray
76
+ vs at time of monitor survey [m/s].
77
+ multiplier : int
78
+ Time shift multiplier.
79
+
80
+ Returns
81
+ -------
82
+ np.ndarray
83
+ twt_ps_shift: two way time shift [ms]
84
+
85
+ Notes
86
+ -----
87
+ Original function by Sascha Bussat, Equinor
88
+ Ported to Python by Harald Flesche, Equinor 2016.
89
+
90
+ """
91
+ dx = np.diff(tvd)
92
+ dx = np.append(dx, dx[-1])
93
+
94
+ time_base_vp = np.cumsum(dx / vp_base)
95
+ time_monitor_vp = np.cumsum(dx / vp_mon)
96
+
97
+ time_base_vs = np.cumsum(dx / vs_base)
98
+ time_monitor_vs = np.cumsum(dx / vs_mon)
99
+
100
+ return (
101
+ ((time_monitor_vp - time_base_vp) + (time_monitor_vs - time_base_vs))
102
+ * 1000
103
+ * multiplier
104
+ )