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,97 @@
1
+ import inspect
2
+ from pathlib import Path
3
+ from typing import Any
4
+
5
+ import numpy as np
6
+ import numpy.typing as npt
7
+
8
+ INITIATE = False
9
+
10
+ SYSTEM_AND_DEBUG_FCN = [
11
+ "pydev",
12
+ "ipython-input",
13
+ "interactiveshell",
14
+ "async_helpers",
15
+ "handle_snapshots",
16
+ "run_code",
17
+ "run_ast_nodes",
18
+ "run_cell_async",
19
+ "_pseudo_sync_runner",
20
+ "_run_cell",
21
+ "run_cell",
22
+ "add_exec",
23
+ "do_add_exec",
24
+ "add_exec",
25
+ "ipython_exec_code",
26
+ "console_exec",
27
+ "do_it",
28
+ "process_internal_commands",
29
+ "_do_wait_suspend",
30
+ "do_wait_suspend",
31
+ "compare_snapshots",
32
+ "handle_snapshots",
33
+ "wrapper",
34
+ "run_tests",
35
+ "<module>",
36
+ ]
37
+
38
+
39
+ def get_snapshot_name(
40
+ step: int = 1,
41
+ include_filename: bool = True,
42
+ include_function_name: bool = True,
43
+ include_extension: bool = True,
44
+ include_snapshot_dir: bool = True,
45
+ ) -> str:
46
+ """
47
+ Parameters
48
+ ----------
49
+ step: number of steps in the trace to collect information from
50
+ include_snapshot_dir: absolute directory name included in snapshot name
51
+ include_filename: whether to include filename in snapshot name
52
+ include_function_name: whether to include function name in snapshot name
53
+ include_extension: whether to include extension in snapshot name
54
+
55
+ Returns
56
+ -------
57
+ name of snapshot file
58
+ """
59
+ trace = inspect.stack()
60
+ for frame in trace[step:]:
61
+ if not any(keyword in frame.function for keyword in SYSTEM_AND_DEBUG_FCN):
62
+ break
63
+ else:
64
+ frame = trace[step]
65
+
66
+ dir_name = Path(frame.filename).parents[1] / "data" / "snapshots"
67
+ file_name = Path(frame.filename).stem if include_filename else ""
68
+ function_name = frame.function if include_function_name else ""
69
+ extension = ".npz" if include_extension else ""
70
+ parts = [part for part in [file_name, function_name] if part]
71
+ base_name = "_".join(parts) + extension
72
+ return str(dir_name / base_name) if include_snapshot_dir else base_name
73
+
74
+
75
+ def store_snapshot(snapshot_name: str, *args: np.ndarray) -> bool:
76
+ """
77
+ Examples
78
+ --------
79
+ In case there are multiple arrays to store:
80
+ store_snapshot(snapshot_name='snap_to_store.npz', *args)
81
+
82
+ Important: If there is only one array to store:
83
+ store_snapshot(snapshot_name='snap_to_store.npz', args)
84
+ """
85
+ try:
86
+ np.savez(snapshot_name, *args)
87
+ except IOError as e:
88
+ raise IOError(f"Could not store snapshot {snapshot_name}: {e}")
89
+ return True
90
+
91
+
92
+ def read_snapshot(snapshot_name: str) -> tuple[npt.NDArray[Any], ...]:
93
+ try:
94
+ with np.load(snapshot_name) as stored_npz:
95
+ return tuple(stored_npz[arr_name] for arr_name in stored_npz.files)
96
+ except IOError as e:
97
+ raise ValueError(f"unable to load snapshot {snapshot_name}: {e}")
@@ -0,0 +1,43 @@
1
+ from .backus_ave import backus_average
2
+ from .dvorkin_nur import dvorkin_contact_cement
3
+ from .gassmann import gassmann, gassmann2, gassmann_dry
4
+ from .hashin_shtrikman import (
5
+ hashin_shtrikman,
6
+ hashin_shtrikman_average,
7
+ hashin_shtrikman_walpole,
8
+ multi_hashin_shtrikman,
9
+ )
10
+ from .hertz_mindlin import hertz_mindlin
11
+ from .moduli_velocity import moduli, velocity
12
+ from .reflection_eq import aki_richards, smith_gidlow
13
+ from .rho import rho_b, rho_m
14
+ from .voigt_reuss_hill import multi_voigt_reuss_hill, reuss, voigt, voigt_reuss_hill
15
+ from .walton import walton_smooth
16
+ from .wood_brie import brie, multi_wood, wood
17
+
18
+ __all__ = [
19
+ "backus_average",
20
+ "dvorkin_contact_cement",
21
+ "gassmann",
22
+ "gassmann2",
23
+ "gassmann_dry",
24
+ "hashin_shtrikman",
25
+ "hashin_shtrikman_average",
26
+ "hashin_shtrikman_walpole",
27
+ "multi_hashin_shtrikman",
28
+ "hertz_mindlin",
29
+ "moduli",
30
+ "velocity",
31
+ "aki_richards",
32
+ "smith_gidlow",
33
+ "rho_b",
34
+ "rho_m",
35
+ "multi_voigt_reuss_hill",
36
+ "reuss",
37
+ "voigt",
38
+ "voigt_reuss_hill",
39
+ "walton_smooth",
40
+ "brie",
41
+ "multi_wood",
42
+ "wood",
43
+ ]
@@ -0,0 +1,68 @@
1
+ import numpy as np
2
+ import numpy.typing as npt
3
+
4
+
5
+ def backus_average(
6
+ vp1: npt.NDArray[np.float64],
7
+ vs1: npt.NDArray[np.float64],
8
+ rho1: npt.NDArray[np.float64],
9
+ vp2: npt.NDArray[np.float64],
10
+ vs2: npt.NDArray[np.float64],
11
+ rho2: npt.NDArray[np.float64],
12
+ f1: npt.NDArray[np.float64],
13
+ ) -> tuple[
14
+ npt.NDArray[np.float64],
15
+ npt.NDArray[np.float64],
16
+ npt.NDArray[np.float64],
17
+ npt.NDArray[np.float64],
18
+ npt.NDArray[np.float64],
19
+ ]:
20
+ """
21
+ Backus average for a combination of two phases. The individual phases are isotropic
22
+ but the resulting effective medium is not.
23
+
24
+ Parameters
25
+ ----------
26
+ vp1 : np.ndarray
27
+ Pressure wave velocity for phase 1 [m/s].
28
+ vs1 : np.ndarray
29
+ Shear wave velocity for phase 1 [m/s].
30
+ rho1 : np.ndarray
31
+ Density for phase 1 [kg/m^3].
32
+ vp2 : np.ndarray
33
+ Pressure wave velocity for phase 2 [m/s].
34
+ vs2 : np.ndarray
35
+ Shear wave velocity for phase 2 [m/s].
36
+ rho2 : np.ndarray
37
+ Density for phase 2 [kg/m^3].
38
+ f1 : np.ndarray
39
+ Fraction of phase 1.
40
+
41
+ Returns
42
+ -------
43
+ tuple
44
+ vpv, vsv, vph, vsh, rho : np.ndarray
45
+ vpv: vertical pressure velocity, vsv: vertical shear velocity, vph: horizontal pressure velocity,
46
+ vsh: horizontal shear velocity, rho: density.
47
+ """
48
+
49
+ a = (
50
+ 4 * f1 * rho1 * vs1**2 * (1 - vs1**2 / vp1**2)
51
+ + 4 * (1 - f1) * rho2 * vs2**2 * (1 - (vs2 / vp2) ** 2)
52
+ + (f1 * (1 - 2 * (vs1 / vp1) ** 2) + (1 - f1) * (1 - 2 * (vs2 / vp2) ** 2)) ** 2
53
+ * (1 / (f1 / (rho1 * vp1**2) + (1 - f1) / (rho2 * vp2**2)))
54
+ )
55
+
56
+ c = 1 / (f1 / (rho1 * vp1**2) + (1 - f1) / (rho2 * vp2**2))
57
+ d = 1 / (f1 / (rho1 * vs1**2) + (1 - f1) / (rho2 * vs2**2))
58
+
59
+ m = f1 * rho1 * vs1**2 + (1 - f1) * rho2 * vs2**2
60
+
61
+ rho = f1 * rho1 + (1 - f1) * rho2
62
+
63
+ vpv = np.sqrt(c / rho)
64
+ vsv = np.sqrt(d / rho)
65
+ vph = np.sqrt(a / rho)
66
+ vsh = np.sqrt(m / rho)
67
+
68
+ return vpv, vsv, vph, vsh, rho
@@ -0,0 +1,77 @@
1
+ import numpy as np
2
+ import numpy.typing as npt
3
+
4
+
5
+ def dvorkin_contact_cement(
6
+ frac_cem: npt.NDArray[np.float64],
7
+ por0_sst: npt.NDArray[np.float64],
8
+ mu0_sst: npt.NDArray[np.float64],
9
+ k0_sst: npt.NDArray[np.float64],
10
+ mu0_cem: npt.NDArray[np.float64],
11
+ k0_cem: npt.NDArray[np.float64],
12
+ vs_red: npt.NDArray[np.float64],
13
+ c: float,
14
+ ) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]:
15
+ """
16
+ Dvorkin-Nur contact cement model for estimation of elastic moduli.
17
+
18
+ Parameters
19
+ ----------
20
+ frac_cem : numpy.ndarray
21
+ Cement fraction of volume [ratio].
22
+ por0_sst : numpy.ndarray
23
+ Critical porosity of sand [ratio].
24
+ mu0_sst : numpy.ndarray
25
+ Mineral shear modulus of sand [Pa].
26
+ k0_sst : numpy.ndarray
27
+ Mineral bulk modulus of sand [Pa].
28
+ mu0_cem : numpy.ndarray
29
+ Mineral shear modulus of cement [Pa].
30
+ k0_cem : numpy.ndarray
31
+ Mineral bulk modulus of cement [Pa].
32
+ vs_red : numpy.ndarray
33
+ Shear modulus reduction factor [ratio].
34
+ c : float
35
+ Coordination number (grain contacts per grain) [unitless].
36
+
37
+ Returns
38
+ -------
39
+ tuple
40
+ k_cc, mu_cc : numpy.ndarray.
41
+ k_cc: bulk modulus [Pa], mu_cc: shear modulus [Pa].
42
+ """
43
+ alpha = (2 * frac_cem / (3 * (1 - por0_sst))) ** 0.5
44
+ poiss = (3 * k0_sst - 2 * mu0_sst) / (2 * (3 * k0_sst + mu0_sst))
45
+ poiss_c = (3 * k0_cem - 2 * mu0_cem) / (2 * (3 * k0_cem + mu0_cem))
46
+ a_an = (2 * mu0_cem / (np.pi * mu0_sst)) * (
47
+ (1 - poiss) * (1 - poiss_c) / (1 - 2 * poiss_c)
48
+ )
49
+ a_at = mu0_cem / (np.pi * mu0_sst)
50
+
51
+ a_t = (
52
+ -1e-2
53
+ * (2.26 * poiss**2 + 2.07 * poiss + 2.3)
54
+ * a_at ** (0.079 * poiss**2 + 0.1754 * poiss - 1.342)
55
+ )
56
+ b_t = (0.0573 * poiss**2 + 0.0937 * poiss + 0.202) * a_at ** (
57
+ 0.0274 * poiss**2 + 0.0529 * poiss - 0.8765
58
+ )
59
+ c_t = (
60
+ 1e-4
61
+ * (9.654 * poiss**2 + 4.945 * poiss + 3.1)
62
+ * a_at ** (0.01867 * poiss**2 + 0.4011 * poiss - 1.8186)
63
+ )
64
+
65
+ s_t = a_t * alpha**2 + b_t * alpha + c_t
66
+
67
+ c_n = 0.00024649 * a_an ** (-1.9864)
68
+ b_n = 0.20405 * a_an ** (-0.89008)
69
+ a_n = -0.024153 * a_an ** (-1.3646)
70
+
71
+ s_n = a_n * alpha**2 + b_n * alpha + c_n
72
+
73
+ m0_cem = k0_cem + 4 / 3 * mu0_cem
74
+ k_cc = (1 / 6) * c * (1 - por0_sst) * m0_cem * s_n
75
+ mu_cc = (3 / 5) * k_cc + vs_red * (3 / 20) * c * (1 - por0_sst) * mu0_cem * s_t
76
+
77
+ return k_cc, mu_cc
@@ -0,0 +1,165 @@
1
+ import warnings
2
+ from typing import cast
3
+
4
+ import numpy as np
5
+ import numpy.typing as npt
6
+
7
+ from rock_physics_open.equinor_utilities.gen_utilities import dim_check_vector
8
+
9
+
10
+ def gassmann(
11
+ k_dry: npt.NDArray[np.float64],
12
+ por: npt.NDArray[np.float64],
13
+ k_fl: npt.NDArray[np.float64],
14
+ k_min: npt.NDArray[np.float64],
15
+ ) -> npt.NDArray[np.float64]:
16
+ """
17
+ Fluid substitution according to the Gassmann equation.
18
+
19
+ Parameters
20
+ ----------
21
+ k_dry : np.ndarray
22
+ Dry rock bulk modulus [Pa].
23
+ por : np.ndarray
24
+ Porosity [fraction].
25
+ k_fl : np.ndarray
26
+ Fluid bulk modulus.
27
+ k_min : np.ndarray
28
+ Mineral bulk modulus [Pa].
29
+
30
+ Returns
31
+ -------
32
+ np.ndarray
33
+ k_sat: bulk modulus for saturated rock [Pa]
34
+ """
35
+ k_dry, por, k_fl, k_min = cast(
36
+ list[npt.NDArray[np.float64]],
37
+ dim_check_vector((k_dry, por, k_fl, k_min)),
38
+ )
39
+
40
+ idx = np.logical_or(k_dry == k_min, por == 0)
41
+ k_sat = np.ones(k_dry.shape) * np.nan
42
+ b = k_dry[~idx] / (k_min[~idx] - k_dry[~idx]) + k_fl[~idx] / (
43
+ (k_min[~idx] - k_fl[~idx]) * por[~idx]
44
+ )
45
+ idx1 = b < 0
46
+ if any(idx1):
47
+ b[idx1] = np.nan
48
+
49
+ k_sat[~idx] = b / (1 + b) * k_min[~idx]
50
+ k_sat[idx] = k_min[idx]
51
+
52
+ return k_sat
53
+
54
+
55
+ def gassmann2(
56
+ k_sat_1: npt.NDArray[np.float64],
57
+ k_fl_1: npt.NDArray[np.float64],
58
+ k_fl_2: npt.NDArray[np.float64],
59
+ por: npt.NDArray[np.float64],
60
+ k_min: npt.NDArray[np.float64],
61
+ ) -> npt.NDArray[np.float64]:
62
+ """
63
+ Fluid substitution by Gassmann method with substitution of one fluid to another
64
+
65
+ Parameters
66
+ ----------
67
+ k_sat_1 : np.ndarray
68
+ bulk modulus for saturated rock with original fluid [Pa]
69
+ k_fl_1 : np.ndarray
70
+ bulk modulus for original fluid [Pa]
71
+ k_fl_2 : np.ndarray
72
+ bulk modulus for replaced fluid [Pa]
73
+ por : np.ndarray
74
+ porosity of rock [fraction]
75
+ k_min : np.ndarray
76
+ mineral bulk modulus of rock [Pa]
77
+
78
+ Returns
79
+ -------
80
+ np.ndarray
81
+ k_sat_2: bulk modulus of rock saturated with replaced fluid [Pa]
82
+ """
83
+ k_sat_1, k_fl_1, k_fl_2, por, k_min = cast(
84
+ list[npt.NDArray[np.float64]],
85
+ dim_check_vector((k_sat_1, k_fl_1, k_fl_2, por, k_min)),
86
+ )
87
+
88
+ idx = np.any(
89
+ np.array([k_sat_1 == k_min, por == 0, k_fl_1 == k_min, k_fl_2 == k_min]), axis=0
90
+ )
91
+
92
+ k_sat_2 = np.ones(k_sat_1.shape) * np.nan
93
+
94
+ b = (
95
+ k_fl_2[~idx] / (por[~idx] * (k_min[~idx] - k_fl_2[~idx]))
96
+ - k_fl_1[~idx] / (por[~idx] * (k_min[~idx] - k_fl_1[~idx]))
97
+ + k_sat_1[~idx] / (k_min[~idx] - k_sat_1[~idx])
98
+ )
99
+
100
+ idx1 = b < 0
101
+ if any(idx1):
102
+ warn_str = (
103
+ "{0:d} unstable solution(s) to Gassmann equation, changed to NaN".format(
104
+ np.sum(idx1)
105
+ )
106
+ )
107
+ warnings.warn(warn_str, UserWarning)
108
+ b[idx1] = np.nan
109
+
110
+ k_sat_2[~idx] = b / (1 + b) * k_min[~idx]
111
+ k_sat_2[idx] = k_sat_1[idx]
112
+
113
+ return k_sat_2
114
+
115
+
116
+ def gassmann_dry(
117
+ k_sat: npt.NDArray[np.float64],
118
+ por: npt.NDArray[np.float64],
119
+ k_fl: npt.NDArray[np.float64],
120
+ k_min: npt.NDArray[np.float64],
121
+ ) -> npt.NDArray[np.float64]:
122
+ """
123
+ Dry rock properties of saturated rock by Gassmann equation
124
+
125
+ Parameters
126
+ ----------
127
+ k_sat : np.ndarray
128
+ saturated rock bulk modulus [Pa]
129
+ por : np.ndarray
130
+ porosity of rock [fraction]
131
+ k_fl : np.ndarray
132
+ bulk modulus of fluid [Pa]
133
+ k_min : np.ndarray
134
+ bulk modulus of mineral [Pa]
135
+
136
+ Returns
137
+ -------
138
+ np.ndarray
139
+ k_dry: dry rock bulk modulus [Pa]
140
+ """
141
+ k_sat, por, k_fl, k_min = cast(
142
+ list[npt.NDArray[np.float64]],
143
+ dim_check_vector((k_sat, por, k_fl, k_min)),
144
+ )
145
+
146
+ idx = np.any(np.array([k_sat == k_min, por == 0, k_fl == k_min]), axis=0)
147
+ k_dry = np.ones(k_sat.shape)
148
+ b = k_sat[~idx] / (k_min[~idx] - k_sat[~idx]) - k_fl[~idx] / (
149
+ (k_min[~idx] - k_fl[~idx]) * por[~idx]
150
+ )
151
+
152
+ idx1 = b < 0
153
+ if any(idx1):
154
+ warn_str = (
155
+ "{0:d} unstable solution(s) to Gassmann equation, changed to NaN".format(
156
+ np.sum(idx1)
157
+ )
158
+ )
159
+ warnings.warn(warn_str, UserWarning)
160
+ b[idx1] = np.nan
161
+
162
+ k_dry[~idx] = b / (1 + b) * k_min[~idx]
163
+ k_dry[idx] = k_min[idx]
164
+
165
+ return k_dry
@@ -0,0 +1,224 @@
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.gen_utilities import dim_check_vector
7
+
8
+
9
+ def hashin_shtrikman(
10
+ k1: npt.NDArray[np.float64],
11
+ mu1: npt.NDArray[np.float64],
12
+ k2: npt.NDArray[np.float64],
13
+ mu2: npt.NDArray[np.float64],
14
+ f: npt.NDArray[np.float64],
15
+ ) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]:
16
+ """
17
+ Hashin-Sktrikman upper or lower according to ordering of phases.
18
+
19
+ Parameters
20
+ ----------
21
+ k1 : np.ndarray
22
+ Bulk modulus of phase 1 [Pa].
23
+ mu1 : np.ndarray
24
+ Shear modulus of phase 1 [Pa].
25
+ k2 : np.ndarray
26
+ Bulk modulus of phase 2 [Pa].
27
+ mu2 : np.ndarray
28
+ Shear modulus of phase 2 [Pa].
29
+ f : np.ndarray
30
+ Fraction of phase 1 [fraction].
31
+
32
+ Returns
33
+ -------
34
+ tuple
35
+ k, mu : np.ndarray.
36
+ k: effective bulk modulus [Pa], mu: effective shear modulus [Pa].
37
+ """
38
+ k = k1 + (1 - f) * (k2 - k1) / (1 + (k2 - k1) * f * (k1 + 4 / 3 * mu1) ** -1)
39
+ mu = mu1 + (1 - f) * (mu2 - mu1) / (
40
+ 1 + 2 * (mu2 - mu1) * f * (k1 + 2 * mu1) / (5 * mu1 * (k1 + 4 / 3 * mu1))
41
+ )
42
+
43
+ return k, mu
44
+
45
+
46
+ def hashin_shtrikman_average(
47
+ k1: npt.NDArray[np.float64],
48
+ mu1: npt.NDArray[np.float64],
49
+ k2: npt.NDArray[np.float64],
50
+ mu2: npt.NDArray[np.float64],
51
+ f: npt.NDArray[np.float64],
52
+ ) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]:
53
+ """
54
+ Average of Hashin-Shtrikman upper and lower bound.
55
+
56
+ Parameters
57
+ ----------
58
+ k1 : np.ndarray
59
+ Bulk modulus of phase 1 [Pa].
60
+ mu1 : np.ndarray
61
+ Shear modulus of phase 1 [Pa].
62
+ k2 : np.ndarray
63
+ Bulk modulus of phase 2 [Pa].
64
+ mu2 : np.ndarray
65
+ Shear modulus of phase 2 [Pa].
66
+ f : np.ndarray
67
+ Fraction of phase 1 [fraction].
68
+
69
+ Returns
70
+ -------
71
+ tuple
72
+ k_av, mu_av : np.ndarray.
73
+ k_av: effective bulk modulus [Pa], mu_av: effective shear modulus [Pa]
74
+ """
75
+ k_hs1, mu_hs1 = hashin_shtrikman(k1, mu1, k2, mu2, f)
76
+ k_hs2, mu_hs2 = hashin_shtrikman(k2, mu2, k1, mu1, 1 - f)
77
+
78
+ k_av = (k_hs1 + k_hs2) / 2
79
+ mu_av = (mu_hs1 + mu_hs2) / 2
80
+
81
+ return k_av, mu_av
82
+
83
+
84
+ def hashin_shtrikman_walpole(
85
+ k1: npt.NDArray[np.float64],
86
+ mu1: npt.NDArray[np.float64],
87
+ k2: npt.NDArray[np.float64],
88
+ mu2: npt.NDArray[np.float64],
89
+ f1: npt.NDArray[np.float64],
90
+ bound: Literal["upper", "lower"] = "lower",
91
+ ) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]:
92
+ """
93
+ Hashin-Shtrikman upper bound is obtained when the stiffest material is
94
+ termed 1 and vice versa for lower bound. Tricky in cases like Quartz -
95
+ Calcite where the K and Mu have opposed values. HS - Walpole is
96
+ generalised to regard highest and lowest values in each case. The default
97
+ is to generate lower bound.
98
+
99
+ Parameters
100
+ ----------
101
+ k1 : np.ndarray
102
+ Bulk modulus of phase 1 [Pa].
103
+ mu1 : np.ndarray
104
+ Shear modulus of phase 1 [Pa].
105
+ k2 : np.ndarray
106
+ Bulk modulus of phase 2 [Pa].
107
+ mu2 : np.ndarray
108
+ Shear modulus of phase 2 [Pa].
109
+ f1 : np.ndarray or float
110
+ Fraction of phase 1 [fraction].
111
+ bound: str
112
+ 'upper' or 'lower' selection of upper of lower bound of effective medium.
113
+ Returns
114
+ -------
115
+ tuple
116
+ k, mu : np.ndarray.
117
+ k: effective bulk modulus [Pa], mu: effective shear modulus [Pa].
118
+ """
119
+ k1, mu1, k2, mu2, f1 = cast(
120
+ list[npt.NDArray[np.float64]],
121
+ dim_check_vector((k1, mu1, k2, mu2, f1)),
122
+ )
123
+ if bound.lower() not in ["lower", "upper"]:
124
+ raise ValueError(f'{__file__}: bound must be one of "lower" or "upper"')
125
+
126
+ idx_k = k1 == k2
127
+ idx_mu = mu1 == mu2
128
+ f2 = 1 - f1
129
+
130
+ if bound.lower() == "lower":
131
+ k_m = np.minimum(k1, k2)
132
+ mu_m = np.minimum(mu1, mu2)
133
+ else:
134
+ k_m = np.maximum(k1, k2)
135
+ mu_m = np.maximum(mu1, mu2)
136
+
137
+ k = np.zeros(k1.shape)
138
+ mu = np.zeros(k1.shape)
139
+
140
+ if np.any(idx_k):
141
+ k[idx_k] = k1[idx_k]
142
+ if np.any(~idx_k):
143
+ k[~idx_k] = k1[~idx_k] + f2[~idx_k] / (
144
+ (k2[~idx_k] - k1[~idx_k]) ** -1
145
+ + f1[~idx_k] * (k1[~idx_k] + 4 / 3 * mu_m[~idx_k]) ** -1
146
+ )
147
+ if np.any(idx_mu):
148
+ mu[idx_mu] = mu1[idx_mu]
149
+ if np.any(~idx_mu):
150
+ mu[~idx_mu] = mu1[~idx_mu] + f2[~idx_mu] / (
151
+ (mu2[~idx_mu] - mu1[~idx_mu]) ** -1
152
+ + f1[~idx_mu]
153
+ * (
154
+ mu1[~idx_mu]
155
+ + mu_m[~idx_mu]
156
+ / 6
157
+ * (9 * k_m[~idx_mu] + 8 * mu_m[~idx_mu])
158
+ / (k_m[~idx_mu] + 2 * mu_m[~idx_mu])
159
+ )
160
+ ** -1
161
+ )
162
+
163
+ return k, mu
164
+
165
+
166
+ def multi_hashin_shtrikman(
167
+ *coeffs: npt.NDArray[np.float64],
168
+ mode: Literal["average", "upper", "lower"] = "average",
169
+ ) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]:
170
+ """
171
+ Hashin-Shtrikman effective medium calculation for multi-mineral case.
172
+
173
+ Parameters
174
+ ----------
175
+ coeffs : np.ndarray
176
+ Triplets of vectors with k (bulk modulus [Pa]), mu (shear modulus [Pa]) and fraction for each mineral.
177
+ mode : str
178
+ 'average', 'upper' or 'lower'.
179
+
180
+ Returns
181
+ -------
182
+ tuple
183
+ k_hs, mu_hs : np.ndarray.
184
+ k_hs, mu_hs - bulk modulus and shear modulus for effective medium [Pa].
185
+ """
186
+ if not len(coeffs) % 3 == 0:
187
+ raise ValueError(
188
+ "multi_hashin_shtrikman: inputs not vectors of k, mu and fraction for each mineral"
189
+ )
190
+
191
+ k_arr = np.array(coeffs[::3])
192
+ mu_arr = np.array(coeffs[1::3])
193
+ f = np.array(coeffs[2::3])
194
+ if not np.all(
195
+ cast(npt.NDArray[np.float64], np.around(np.sum(f, axis=0), decimals=6)) == 1.0
196
+ ):
197
+ raise ValueError("multi_hashin_shtrikman: all fractions do not add up to 1.0")
198
+
199
+ if mode.lower() not in ["average", "upper", "lower"]:
200
+ raise ValueError(
201
+ 'multi_hashin_shtrikman: mode is not one of "average", "upper" or "lower"'
202
+ )
203
+
204
+ k_min = np.min(k_arr, axis=0)
205
+ k_max = np.max(k_arr, axis=0)
206
+ mu_min = np.min(mu_arr, axis=0)
207
+ mu_max = np.max(mu_arr, axis=0)
208
+
209
+ k_hs_upper = np.sum(f / (k_arr + 4 / 3 * mu_max), axis=0) ** -1 - 4 / 3 * mu_max
210
+ k_hs_lower = np.sum(f / (k_arr + 4 / 3 * mu_min), axis=0) ** -1 - 4 / 3 * mu_min
211
+
212
+ zeta_max = mu_max / 6 * (9 * k_max + 8 * mu_max) / (k_max + 2 * mu_max)
213
+ zeta_min = mu_min / 6 * (9 * k_min + 8 * mu_min) / (k_min + 2 * mu_min)
214
+
215
+ mu_hs_upper = np.sum(f / (mu_arr + zeta_max), axis=0) ** -1 - zeta_max
216
+ mu_hs_lower = np.sum(f / (mu_arr + zeta_min), axis=0) ** -1 - zeta_min
217
+
218
+ if mode == "lower":
219
+ return k_hs_lower, mu_hs_lower
220
+ if mode == "upper":
221
+ return k_hs_upper, mu_hs_upper
222
+ k_hs = 0.5 * (k_hs_upper + k_hs_lower)
223
+ mu_hs = 0.5 * (mu_hs_upper + mu_hs_lower)
224
+ return k_hs, mu_hs