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,146 @@
1
+ import warnings
2
+
3
+ import numpy as np
4
+
5
+ from .dead_oil_density import dead_oil_density
6
+ from .dead_oil_velocity import dead_oil_velocity
7
+ from .live_oil_density import live_oil_density
8
+ from .live_oil_velocity import live_oil_velocity
9
+ from .oil_bubble_point import bp_standing
10
+
11
+
12
+ def oil_properties(
13
+ temperature: np.ndarray | float,
14
+ pressure: np.ndarray | float,
15
+ rho0: np.ndarray | float,
16
+ gas_oil_ratio: np.ndarray | float,
17
+ gas_gravity: np.ndarray | float,
18
+ ) -> np.ndarray | float:
19
+ """
20
+ :param temperature: Temperature [°C] of oil.
21
+ :param pressure: Pressure [Pa] of oil
22
+ :param rho0: Density of the oil without dissolved gas at 15.6 degrees Celsius and
23
+ atmospheric pressure. [kg/m^3]
24
+ :param gas_oil_ratio: The volume ratio of gas to oil [l/l]
25
+ :param gas_gravity: Gas Gravity, molar mass of gas relative to air molar mas.
26
+ :return: vel_oil [m/s], den_oil [kg/m^3], k_oil [Pa]
27
+ """
28
+ # Since live_oil with gas_oil_ratio=0.0 is not equal to dead oil
29
+ # we use an apodization function to interpolate between the two
30
+
31
+ def triangular_window(x, length=2):
32
+ """
33
+ A triangular window function around the origin, 1.0 at x=0.0, linear
34
+ and 0.0 outside the window.
35
+ :param length: total length of the window, ie., function is nonzero in
36
+ [-length/2, length/2].
37
+ :param x: numpy array containing x'es to evaluate the window at
38
+ :return: value of window function at x.
39
+ """
40
+ x = np.asarray(x) # Ensure x is a numpy array
41
+ window = np.clip((np.abs(x) - length / 2) / (length / 2), 0, 1)
42
+ return 1 - window
43
+
44
+ (
45
+ loil_vel,
46
+ loil_den,
47
+ ) = live_oil(temperature, pressure, rho0, gas_oil_ratio, gas_gravity)
48
+ doil_vel, doil_den = dead_oil(temperature, pressure, rho0)
49
+ window = triangular_window(gas_oil_ratio)
50
+ den_oil = doil_den * window + (1 - window) * loil_den
51
+ vel_oil = doil_vel * window + (1 - window) * loil_vel
52
+ k_oil = vel_oil**2 * den_oil
53
+ return vel_oil, den_oil, k_oil
54
+
55
+
56
+ def dead_oil(
57
+ temperature: np.ndarray | float,
58
+ pressure: np.ndarray | float,
59
+ reference_density: np.ndarray | float,
60
+ ) -> tuple[np.ndarray | float, np.ndarray | float]:
61
+ """
62
+ :param reference_density: Density of the oil without dissolved gas
63
+ at 15.6 degrees Celsius and atmospheric pressure. [kg/m^3]
64
+ :param gas_oil_ratio: The volume ratio of gas to oil [l/l]
65
+ :param gas_gravity: molar mass of gas relative to air molar mas.
66
+ :param pressure: Pressure [Pa] of oil
67
+ :param temperature: Temperature [°C] of oil.
68
+ :return: dead_oil_density [kg/m^3], dead_oil_velocity [m/s]
69
+ """
70
+ dead_oil_den = dead_oil_density(temperature, pressure, reference_density)
71
+ dead_oil_vel = dead_oil_velocity(temperature, pressure, reference_density)
72
+ return dead_oil_vel, dead_oil_den
73
+
74
+
75
+ def live_oil(
76
+ temperature: np.ndarray | float,
77
+ pressure: np.ndarray | float,
78
+ reference_density: np.ndarray | float,
79
+ gas_oil_ratio: np.ndarray | float,
80
+ gas_gravity: np.ndarray | float,
81
+ ) -> tuple[np.ndarray | float, np.ndarray | float]:
82
+ """
83
+ :param reference_density: Density of the oil without dissolved gas
84
+ at 15.6 degrees Celsius and atmospheric pressure. [kg/m^3]
85
+ :param gas_oil_ratio: The volume ratio of gas to oil [l/l]
86
+ :param gas_gravity: molar mass of gas relative to air molar mas.
87
+ :param pressure: Pressure [Pa] of oil
88
+ :param temperature: Temperature [°C] of oil.
89
+ :return: live_oil_density , live_oil_velocity
90
+ """
91
+ if np.any(
92
+ pressure
93
+ < bp_standing(reference_density, gas_oil_ratio, gas_gravity, temperature)
94
+ ):
95
+ warnings.warn(
96
+ "Pressure is below bubble point of oil, estimated elastic properties can be inaccurate",
97
+ stacklevel=1,
98
+ )
99
+ live_oil_den = live_oil_density(
100
+ temperature,
101
+ pressure,
102
+ reference_density,
103
+ gas_oil_ratio,
104
+ gas_gravity,
105
+ )
106
+ live_oil_vel = live_oil_velocity(
107
+ temperature,
108
+ pressure,
109
+ reference_density,
110
+ gas_oil_ratio,
111
+ gas_gravity,
112
+ )
113
+ return (
114
+ live_oil_vel,
115
+ live_oil_den,
116
+ )
117
+
118
+
119
+ def oil_viscosity(
120
+ temperature: np.ndarray | float,
121
+ pressure: np.ndarray | float,
122
+ reference_density: np.ndarray | float,
123
+ ) -> np.ndarray | float:
124
+ """
125
+ Calculate dead oil viscosity. If dissolved gas is present in the oil, the reference density
126
+ should be substituted by live oil density.
127
+
128
+ Equations 25a, 25b, 26a & 26b in Batzle and Wang 1992
129
+
130
+ Based on Beggs and Robinson 1975
131
+
132
+ :param temperature: Temperature [°C] of oil
133
+ :param pressure: Pressure [Pa] of oil
134
+ :param reference_density: Density of the oil without dissolved gas
135
+ """
136
+ # Change unit in pressure to MPa
137
+ pressure_mpa = pressure / 1.0e6
138
+ # Change unit in density to g/cc
139
+ density_gcc = reference_density / 1000.0
140
+
141
+ y_factor = 10 ** (5.693 - 2.863 / density_gcc)
142
+ eta_t = -1.0 + 10 ** (0.505 * y_factor * (17.8 + temperature) ** -1.163)
143
+ i_factor = 10 ** (
144
+ 18.6 * (0.1 * np.log10(eta_t) + (np.log10(eta_t) + 2) ** -0.1 - 0.985)
145
+ )
146
+ return eta_t + 0.145 * pressure_mpa * i_factor
@@ -0,0 +1,59 @@
1
+ from .cemented_shalysand_sandyshale_models import cemented_shaly_sand_sandy_shale_model
2
+ from .constant_cement_models import (
3
+ constant_cement_model,
4
+ constant_cement_model_dry,
5
+ )
6
+ from .constant_cement_optimisation import constant_cement_model_optimisation
7
+ from .contact_cement_model import contact_cement_model
8
+ from .curvefit_sandstone_models import (
9
+ curvefit_constant_cement,
10
+ curvefit_friable,
11
+ curvefit_patchy_cement,
12
+ )
13
+ from .friable_models import (
14
+ friable_model,
15
+ friable_model_dry,
16
+ )
17
+ from .friable_optimisation import friable_model_optimisation
18
+ from .friable_shalysand_sandyshale_models import friable_shaly_sand_sandy_shale_model
19
+ from .patchy_cement_fluid_substitution_model import (
20
+ patchy_cement_pressure_fluid_substitution,
21
+ )
22
+ from .patchy_cement_model import (
23
+ constant_cement_model_pcm,
24
+ patchy_cement_model_cem_frac,
25
+ patchy_cement_model_dry,
26
+ patchy_cement_model_weight,
27
+ )
28
+ from .patchy_cement_optimisation import (
29
+ patchy_cement_model_optimisation,
30
+ patchy_cement_model_optimisation_multiwell,
31
+ )
32
+ from .unresolved_cemented_sandshale_models import (
33
+ unresolved_constant_cement_sand_shale_model,
34
+ )
35
+ from .unresolved_friable_sandshale_models import unresolved_friable_sand_shale_model
36
+
37
+ __all__ = [
38
+ "cemented_shaly_sand_sandy_shale_model",
39
+ "constant_cement_model",
40
+ "constant_cement_model_dry",
41
+ "constant_cement_model_optimisation",
42
+ "contact_cement_model",
43
+ "curvefit_constant_cement",
44
+ "curvefit_friable",
45
+ "curvefit_patchy_cement",
46
+ "friable_model",
47
+ "friable_model_dry",
48
+ "friable_model_optimisation",
49
+ "friable_shaly_sand_sandy_shale_model",
50
+ "patchy_cement_pressure_fluid_substitution",
51
+ "constant_cement_model_pcm",
52
+ "patchy_cement_model_dry",
53
+ "patchy_cement_model_cem_frac",
54
+ "patchy_cement_model_weight",
55
+ "patchy_cement_model_optimisation",
56
+ "patchy_cement_model_optimisation_multiwell",
57
+ "unresolved_constant_cement_sand_shale_model",
58
+ "unresolved_friable_sand_shale_model",
59
+ ]
@@ -0,0 +1,304 @@
1
+ import numpy as np
2
+
3
+ from rock_physics_open import sandstone_models
4
+ from rock_physics_open.equinor_utilities import gen_utilities, std_functions
5
+
6
+
7
+ def cemented_shaly_sand_sandy_shale_model(
8
+ k_sst,
9
+ mu_sst,
10
+ rho_sst,
11
+ k_cem,
12
+ mu_cem,
13
+ rho_cem,
14
+ k_mud,
15
+ mu_mud,
16
+ rho_mud,
17
+ k_fl_sst,
18
+ rho_fl_sst,
19
+ k_fl_mud,
20
+ rho_fl_mud,
21
+ phi,
22
+ p_eff_mud,
23
+ shale_frac,
24
+ frac_cem,
25
+ phi_c_sst,
26
+ n_sst,
27
+ shear_red_sst,
28
+ phi_c_mud,
29
+ phi_intr_mud,
30
+ coord_num_func_mud,
31
+ n_mud,
32
+ shear_red_mud,
33
+ ):
34
+ """
35
+ Model for mixing of cemented sand and friable shale.
36
+
37
+ It is no point to use this model to calculate the shale response only,
38
+ in that case Friable Model with shale parameters does the job
39
+
40
+ The shale fluid should be brine.
41
+
42
+ Shale fraction shaleFrac is in the range 0 to 1. For shaleFrac = 0 we
43
+ have a pure sand end member with phi =< phi_c for sand. For shaleFrac = 1
44
+ we have pure shale with phi = intrinsic porosity. For shaleFrac < phi_c
45
+ the model is on the shaly sand trend, for shaleFrac > phi_c it is on the
46
+ sandy shale trend.
47
+
48
+ Parameters
49
+ ----------
50
+ k_sst : np.ndarray
51
+ Sandstone matrix bulk modulus [Pa].
52
+ mu_sst : np.ndarray
53
+ Sandstone matrix shear modulus [Pa].
54
+ rho_sst : np.ndarray
55
+ Sandstone matrix bulk density [kg/m^3].
56
+ k_cem : np.ndarray
57
+ Sandstone cement bulk modulus [Pa].
58
+ mu_cem : np.ndarray
59
+ Sandstone cement shear modulus [Pa].
60
+ rho_cem : np.ndarray
61
+ Sandstone cement bulk density [kg/m^3].
62
+ k_mud : np.ndarray
63
+ Shale bulk modulus [Pa].
64
+ mu_mud : np.ndarray
65
+ Shale shear modulus [Pa].
66
+ rho_mud : np.ndarray
67
+ Shale bulk density [kg/m^3].
68
+ k_fl_sst : np.ndarray
69
+ Fluid bulk modulus for sandstone fluid [Pa].
70
+ rho_fl_sst : np.ndarray
71
+ Fluid bulk density for sandstone fluid [kg/m^3].
72
+ k_fl_mud : np.ndarray
73
+ Fluid bulk modulus for shale fluid [Pa].
74
+ rho_fl_mud : np.ndarray
75
+ Fluid bulk density for shale fluid[kg/m^3].
76
+ phi : np.ndarray
77
+ Total porosity [fraction].
78
+ p_eff_mud : np.ndarray
79
+ Effective pressure in mud [Pa].
80
+ shale_frac : np.ndarray
81
+ Shale fraction [fraction].
82
+ frac_cem : np.ndarray
83
+ Cement volume fraction [fraction].
84
+ phi_c_sst : float
85
+ Critical porosity for sandstone[fraction].
86
+ phi_c_mud : float
87
+ Critical porosity for mud [fraction].
88
+ phi_intr_mud : float
89
+ Intrinsic porosity for mud [fraction].
90
+ n_sst : float
91
+ Coordination number for sandstone [unitless].
92
+ n_mud : float
93
+ Coordination number for shale [unitless].
94
+ coord_num_func_mud : str
95
+ Indication if coordination number should be calculated from porosity or kept constant for shale.
96
+ shear_red_sst : float
97
+ Shear reduction factor for sandstone [fraction].
98
+ shear_red_mud : float
99
+ Shear reduction factor for mud [fraction].
100
+
101
+ Returns
102
+ -------
103
+ tuple
104
+ vp, vs, rho, ai, vpvs : (np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray)
105
+ vp [m/s] and vs [m/s], bulk density [kg/m^3], ai [m/s x kg/m^3], vpvs [ratio] of saturated rock.
106
+ """
107
+
108
+ # Valid porosity values must not exceed (phi_c - frac_cem)
109
+ # Assume that this only needs to be considered for the sandstone fraction
110
+ (
111
+ k_sst,
112
+ mu_sst,
113
+ rho_sst,
114
+ k_cem,
115
+ mu_cem,
116
+ rho_cem,
117
+ k_mud,
118
+ mu_mud,
119
+ rho_mud,
120
+ k_fl_sst,
121
+ rho_fl_sst,
122
+ k_fl_mud,
123
+ rho_fl_mud,
124
+ phi,
125
+ p_eff_mud,
126
+ shale_frac,
127
+ frac_cem,
128
+ ) = gen_utilities.dim_check_vector(
129
+ (
130
+ k_sst,
131
+ mu_sst,
132
+ rho_sst,
133
+ k_cem,
134
+ mu_cem,
135
+ rho_cem,
136
+ k_mud,
137
+ mu_mud,
138
+ rho_mud,
139
+ k_fl_sst,
140
+ rho_fl_sst,
141
+ k_fl_mud,
142
+ rho_fl_mud,
143
+ phi,
144
+ p_eff_mud,
145
+ shale_frac,
146
+ frac_cem,
147
+ )
148
+ )
149
+ (
150
+ idx_phi,
151
+ (
152
+ k_sst,
153
+ mu_sst,
154
+ rho_sst,
155
+ k_cem,
156
+ mu_cem,
157
+ rho_cem,
158
+ k_mud,
159
+ mu_mud,
160
+ rho_mud,
161
+ k_fl_sst,
162
+ rho_fl_sst,
163
+ k_fl_mud,
164
+ rho_fl_mud,
165
+ phi,
166
+ p_eff_mud,
167
+ shale_frac,
168
+ frac_cem,
169
+ _,
170
+ _,
171
+ ),
172
+ ) = gen_utilities.filter_input_log(
173
+ (
174
+ k_sst,
175
+ mu_sst,
176
+ rho_sst,
177
+ k_cem,
178
+ mu_cem,
179
+ rho_cem,
180
+ k_mud,
181
+ mu_mud,
182
+ rho_mud,
183
+ k_fl_sst,
184
+ rho_fl_sst,
185
+ k_fl_mud,
186
+ rho_fl_mud,
187
+ phi,
188
+ p_eff_mud,
189
+ shale_frac,
190
+ frac_cem,
191
+ phi_c_sst - frac_cem - phi,
192
+ phi - phi_intr_mud,
193
+ ),
194
+ no_zero=False,
195
+ )
196
+
197
+ # Reduce range of porosity by frac_cem
198
+ phi_c = phi_c_sst - frac_cem
199
+
200
+ sandy_shale_idx = shale_frac > phi
201
+ shaly_sand_idx = ~sandy_shale_idx
202
+
203
+ # Fraction of silt in silt - shale trend
204
+ frac_silt = (1 - shale_frac) / (1 - phi)
205
+ # Fraction of sand in sand - silt trend
206
+ frac_sand = 1 - shale_frac / phi
207
+
208
+ # Shale properties for intrinsic porosity point NB! The phi_intr_mud is
209
+ # normally a parameter, but the assumption in Friable model is that it is a
210
+ # log. Make sure that it is of the same length as the other
211
+
212
+ # Expand the needed variables from float to numpy array
213
+ phi, phi_intr_mud = gen_utilities.dim_check_vector((phi, phi_intr_mud))
214
+
215
+ vp_sat_mud, vs_sat_mud, rho_b_mud = sandstone_models.friable_model(
216
+ k_mud,
217
+ mu_mud,
218
+ rho_mud,
219
+ k_fl_mud,
220
+ rho_fl_mud,
221
+ phi_intr_mud,
222
+ p_eff_mud,
223
+ phi_c_mud,
224
+ coord_num_func_mud,
225
+ n_mud,
226
+ shear_red_mud,
227
+ )[0:3]
228
+ k_sat_mud, mu_sat_mud = std_functions.moduli(vp_sat_mud, vs_sat_mud, rho_b_mud)
229
+
230
+ # Calculate cemented zero-porosity sand
231
+ k_zero, mu_zero = std_functions.hashin_shtrikman_walpole(
232
+ k_cem, mu_cem, k_sst, mu_sst, frac_cem, bound="lower"
233
+ )
234
+ rho_zero = rho_cem * frac_cem + (1 - frac_cem) * rho_sst
235
+
236
+ # Silt end member
237
+ k_silt, mu_silt = std_functions.hashin_shtrikman_walpole(
238
+ k_sat_mud, mu_sat_mud, k_zero, mu_zero, phi_c
239
+ )
240
+ rho_silt = rho_b_mud * phi + rho_zero * (1 - phi)
241
+
242
+ # Estimate the sand end member through the constant cement model with phi =
243
+ # phiCSst <= maybe dubious to expand parameter to vector with assumption
244
+ # that kSst has the correct size
245
+
246
+ vp_sat_sst, vs_sat_sst, rho_sat_sst = sandstone_models.constant_cement_model(
247
+ k_sst,
248
+ mu_sst,
249
+ rho_sst,
250
+ k_cem,
251
+ mu_cem,
252
+ rho_cem,
253
+ k_fl_sst,
254
+ rho_fl_sst,
255
+ phi,
256
+ frac_cem,
257
+ phi_c_sst,
258
+ n_sst,
259
+ shear_red_sst,
260
+ )[0:3]
261
+ k_sat_sst, mu_sat_sst = std_functions.moduli(vp_sat_sst, vs_sat_sst, rho_sat_sst)
262
+
263
+ k = np.ones(shale_frac.shape) * np.nan
264
+ mu = np.ones(shale_frac.shape) * np.nan
265
+ rhob = np.ones(shale_frac.shape) * np.nan
266
+
267
+ # Points on sandy shale trend
268
+ k[sandy_shale_idx], mu[sandy_shale_idx] = std_functions.hashin_shtrikman_walpole(
269
+ k_silt[sandy_shale_idx],
270
+ mu_silt[sandy_shale_idx],
271
+ k_sat_mud[sandy_shale_idx],
272
+ mu_sat_mud[sandy_shale_idx],
273
+ frac_silt[sandy_shale_idx],
274
+ )
275
+
276
+ rhob[sandy_shale_idx] = (
277
+ rho_b_mud[sandy_shale_idx] * (1 - frac_silt[sandy_shale_idx])
278
+ + rho_silt[sandy_shale_idx] * frac_silt[sandy_shale_idx]
279
+ )
280
+
281
+ # Points on shaly sand trend
282
+ k[shaly_sand_idx], mu[shaly_sand_idx] = std_functions.hashin_shtrikman_walpole(
283
+ k_sat_sst[shaly_sand_idx],
284
+ mu_sat_sst[shaly_sand_idx],
285
+ k_silt[shaly_sand_idx],
286
+ mu_silt[shaly_sand_idx],
287
+ frac_sand[shaly_sand_idx],
288
+ )
289
+
290
+ rhob[shaly_sand_idx] = (
291
+ (1 - phi[shaly_sand_idx]) * rho_zero[shaly_sand_idx]
292
+ + phi[shaly_sand_idx] * rho_fl_sst[shaly_sand_idx]
293
+ ) * frac_sand[shaly_sand_idx] + (1 - frac_sand[shaly_sand_idx]) * rho_silt[
294
+ shaly_sand_idx
295
+ ]
296
+
297
+ vp, vs, ai, vpvs = std_functions.velocity(k, mu, rhob)
298
+
299
+ # Restore original length
300
+ vp, vs, rhob, ai, vpvs = gen_utilities.filter_output(
301
+ idx_phi, (vp, vs, rhob, ai, vpvs)
302
+ )
303
+
304
+ return vp, vs, rhob, ai, vpvs
@@ -0,0 +1,204 @@
1
+ import numpy as np
2
+ from scipy.interpolate import interp1d
3
+
4
+ from rock_physics_open.equinor_utilities import gen_utilities, std_functions
5
+
6
+
7
+ def constant_cement_model(
8
+ k_min,
9
+ mu_min,
10
+ rho_min,
11
+ k_cem,
12
+ mu_cem,
13
+ rho_cem,
14
+ k_fl,
15
+ rho_fl,
16
+ phi,
17
+ frac_cem,
18
+ phi_c,
19
+ n,
20
+ shear_red,
21
+ extrapolate_to_max_phi=False,
22
+ ):
23
+ """
24
+ Constant cement model is a sandstone model that combined a cemented and a friable sand, so that a constant
25
+ proportion of the rock volume is made up of grain-bonding cement. Variation in porosity is due to grain sorting,
26
+ i.e. a well-sorted sand will have high porosity, and a poorly sorted one will have low porosity. In the extreme
27
+ end all porosity is removed and the effective mineral properties is returned.
28
+
29
+ Mineral properties k_min, mu_min, rho_min are effective properties. For mixtures of minerals, effective
30
+ properties are calculated by Hashin-Shtrikman or similar.
31
+
32
+ Cement properties k_cem, mu_cem, rho_cem and cement fraction, the latter as a part of the whole volume.
33
+
34
+ Fluid properties k_fl, rho_fl are in situ properties calculated by fluid models using reservoir properties.
35
+
36
+ Critical porosity phi_c is input to Dvorkin-Nur function. Coordination number n is normally set to a fixed
37
+ value (default 9) but it is possible to override this. Porosity phi is used in Hashin-Shtrikman mixing
38
+ (together with phi_c) and Gassmann saturation.
39
+
40
+ Shear reduction parameter shear_red is used to account for tangential frictionless grain contacts
41
+
42
+ All inputs are assumed to be vectors of the same length
43
+
44
+ Parameters
45
+ ----------
46
+ k_min : np.ndarray
47
+ Mineral bulk modulus [Pa].
48
+ mu_min : np.ndarray
49
+ Mineral shear modulus [Pa].
50
+ rho_min : np.ndarray
51
+ Mineral bulk density [kg/m^3].
52
+ k_cem : np.ndarray
53
+ Cement bulk modulus [Pa].
54
+ mu_cem : np.ndarray
55
+ Cement shear modulus [Pa].
56
+ rho_cem : np.ndarray
57
+ Cement bulk density [kg/m^3].
58
+ k_fl : np.ndarray
59
+ Fluid bulk modulus [Pa].
60
+ rho_fl : np.ndarray
61
+ Fluid bulk density [kg/m^3].
62
+ phi : np.ndarray
63
+ Porosity [fraction].
64
+ frac_cem : np.ndarray or float
65
+ Cement fraction [fraction].
66
+ phi_c : float
67
+ Critical porosity [fraction].
68
+ n : float
69
+ Coordination number [unitless].
70
+ shear_red : float
71
+ Shear reduction factor [fraction].
72
+ extrapolate_to_max_phi : bool
73
+ If True, the model will extrapolate to the maximum porosity value (phi_c - frac_cem) if the input porosity
74
+ exceeds this value. If False, the model will return NaN for porosity values exceeding this limit.
75
+
76
+ Returns
77
+ -------
78
+ tuple
79
+ vp, vs, rho, ai, vpvs : (np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray)
80
+ vp [m/s] and vs [m/s], bulk density [kg/m^3], ai [m/s x kg/m^3], vpvs [ratio] of saturated rock.
81
+ """
82
+ k_zero, k_dry, mu = constant_cement_model_dry(
83
+ k_min,
84
+ mu_min,
85
+ k_cem,
86
+ mu_cem,
87
+ phi,
88
+ frac_cem,
89
+ phi_c,
90
+ n,
91
+ shear_red,
92
+ extrapolate_to_max_phi=extrapolate_to_max_phi,
93
+ return_k_zero=True,
94
+ )
95
+ # Saturated rock incompressibility is calculated with Gassmann
96
+ k = std_functions.gassmann(k_dry, phi, k_fl, k_zero)
97
+
98
+ # Bulk density
99
+ rho = phi * rho_fl + (1 - phi - frac_cem) * rho_min + frac_cem * rho_cem
100
+ # Velocity
101
+ vp, vs, ai, vpvs = std_functions.velocity(k, mu, rho)
102
+
103
+ return vp, vs, rho, ai, vpvs
104
+
105
+
106
+ def constant_cement_model_dry(
107
+ k_min,
108
+ mu_min,
109
+ k_cem,
110
+ mu_cem,
111
+ phi,
112
+ frac_cem,
113
+ phi_c,
114
+ n,
115
+ shear_red,
116
+ extrapolate_to_max_phi=False,
117
+ return_k_zero=False,
118
+ ):
119
+ """
120
+ Dry rock version of the constant cement model. The method is identical to the constant cement model function,
121
+ except that a saturation step is not performed at the end.
122
+
123
+ Parameters
124
+ ----------
125
+ k_min : np.ndarray
126
+ Mineral bulk modulus [Pa].
127
+ mu_min : np.ndarray
128
+ Mineral shear modulus [Pa].
129
+ k_cem : np.ndarray
130
+ Cement bulk modulus [Pa].
131
+ mu_cem : np.ndarray
132
+ Cement shear modulus [Pa].
133
+ phi : np.ndarray
134
+ Porosity [fraction].
135
+ frac_cem : float or np.ndarray
136
+ Cement fraction [fraction].
137
+ phi_c : float
138
+ Critical porosity [fraction].
139
+ n : float
140
+ Coordination number [unitless].
141
+ shear_red : float
142
+ Shear reduction factor [fraction].
143
+ extrapolate_to_max_phi : bool
144
+ If True, the model will extrapolate to the maximum porosity value (phi_c - frac_cem) if the input porosity
145
+ exceeds this value. If False, the model will return NaN for porosity values exceeding this limit.
146
+ return_k_zero : bool
147
+ If True, the model will return the zero-porosity end member bulk modulus k_zero in addition to the dry rock
148
+ bulk modulus k_dry and shear modulus mu.
149
+
150
+ Returns
151
+ -------
152
+ tuple
153
+ k_dry, mu : (np.ndarray, np.ndarray).
154
+ Bulk modulus k [Pa] and shear modulus mu [Pa] of dry rock.
155
+ """
156
+ # First check if there are input values that are unphysical, i.e. negative values, separate between dry and
157
+ # saturated rock properties. Use the filter_input_log function to identify these values
158
+ idx, (k_min, mu_min, k_cem, mu_cem, phi) = gen_utilities.filter_input_log(
159
+ (k_min, mu_min, k_cem, mu_cem, phi)
160
+ )
161
+
162
+ # Identify porosity values that exceed (phi_c - frac_cem). This is regardless of setting for extrapolate_to_max_phi
163
+ idx_phi = np.where(phi > phi_c - frac_cem)[0]
164
+
165
+ # At the zero-porosity point, all original porosity (critical porosity -
166
+ # cement fraction) is filled with grains. The cement fraction surrounds the
167
+ # original grains, so they will be fraction 1 according to the geometrical
168
+ # interpretation of Hashin-Shtrikman
169
+ k_zero, mu_zero = std_functions.hashin_shtrikman_walpole(
170
+ k_cem, mu_cem, k_min, mu_min, frac_cem, bound="lower"
171
+ )
172
+
173
+ # Dry rock properties of high-porosity end member calculated with
174
+ # Dvorkin-Nur equation. Cement is assumed to be evenly distributed on the
175
+ # grains (scheme 2 in Dvorkin and Nur's original paper)
176
+
177
+ k_cc, mu_cc = std_functions.dvorkin_contact_cement(
178
+ frac_cem, phi_c, mu_min, k_min, mu_cem, k_cem, shear_red, n
179
+ )
180
+
181
+ # Hashin-Shtrikman lower bound describes the dry rock property mixing from
182
+ # mineral properties to high-end porosity.
183
+
184
+ # Fraction of zero-porosity end member
185
+ f1 = 1 - phi / (phi_c - frac_cem)
186
+
187
+ k_dry, mu = std_functions.hashin_shtrikman_walpole(
188
+ k_zero, mu_zero, k_cc, mu_cc, f1, bound="lower"
189
+ )
190
+
191
+ # If extrapolate_to_max_phi is True, create extrapolation functions for k_dry and mu using scipy's interp1d
192
+ if extrapolate_to_max_phi:
193
+ k_dry_func = interp1d(phi, k_dry, fill_value="extrapolate")
194
+ mu_func = interp1d(phi, mu, fill_value="extrapolate")
195
+ k_dry[idx_phi] = k_dry_func(phi[idx_phi])
196
+ mu[idx_phi] = mu_func(phi[idx_phi])
197
+ else:
198
+ k_dry[idx_phi] = np.nan
199
+ mu[idx_phi] = np.nan
200
+
201
+ k_dry, mu = gen_utilities.filter_output(idx, (k_dry, mu))
202
+ if return_k_zero:
203
+ return k_zero, k_dry, mu
204
+ return k_dry, mu