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,125 @@
1
+ import numpy as np
2
+
3
+ from rock_physics_open.equinor_utilities import gen_utilities
4
+ from rock_physics_open.equinor_utilities.optimisation_utilities import (
5
+ gen_opt_routine,
6
+ save_opt_params,
7
+ )
8
+
9
+ from .curvefit_sandstone_models import curvefit_constant_cement
10
+
11
+
12
+ def constant_cement_model_optimisation(
13
+ k_min: np.ndarray,
14
+ mu_min: np.ndarray,
15
+ rho_min: np.ndarray,
16
+ k_cem: np.ndarray,
17
+ mu_cem: np.ndarray,
18
+ rho_cem: np.ndarray,
19
+ k_fl: np.ndarray,
20
+ rho_fl: np.ndarray,
21
+ por: np.ndarray,
22
+ vp: np.ndarray,
23
+ vs: np.ndarray,
24
+ rhob: np.ndarray,
25
+ file_out_str: str = "constant_cement_optimal_params.pkl",
26
+ display_results: bool = False,
27
+ well_name: str = "Unknown well",
28
+ ):
29
+ """Patchy cement model with optimisation for a selection of parameters.
30
+
31
+ Parameters
32
+ ----------
33
+ k_min :
34
+ Cement bulk modulus [Pa].
35
+ mu_min :
36
+ Cement shear modulus [Pa].
37
+ rho_min :
38
+ Cement density [kg/m^3].
39
+ k_cem :
40
+ Cement bulk modulus [Pa].
41
+ mu_cem :
42
+ Cement shear modulus [Pa].
43
+ rho_cem :
44
+ Cement density [kg/m^3].
45
+ k_fl :
46
+ Fluid bulk modulus [Pa].
47
+ rho_fl :
48
+ Fluid density [kg/m^3].
49
+ por :
50
+ Inclusion porosity [ratio].
51
+ vp :
52
+ Compressional velocity log [m/s].
53
+ vs :
54
+ Shear velocity log [m/s].
55
+ rhob :
56
+ Bulk density log [kg/m^3].
57
+ file_out_str :
58
+ Output file name (string) to store optimal parameters (pickle format).
59
+ display_results :
60
+ Display optimal parameters in a window after run.
61
+ well_name :
62
+ Name of well to be displayed in info box title.
63
+
64
+ Returns
65
+ -------
66
+ tuple
67
+ vp_mod, vs_mod - modelled logs, vp_res, vs_res - residual logs.
68
+ """
69
+
70
+ # Skip hardcoded Vp/Vs ratio
71
+ def_vpvs = np.mean(vp / vs)
72
+ # Set weight to vs to give vp and vs similar influence on optimisation
73
+ y_data = np.stack([vp, vs * def_vpvs], axis=1)
74
+ # Optimisation function for selected parameters
75
+ opt_fun = curvefit_constant_cement
76
+ # expand single value parameters to match logs length
77
+ por, def_vpvs = gen_utilities.dim_check_vector((por, def_vpvs))
78
+ x_data = np.stack(
79
+ (k_min, mu_min, rho_min, k_cem, mu_cem, rho_cem, k_fl, rho_fl, por, def_vpvs),
80
+ axis=1,
81
+ )
82
+
83
+ # Params: weight_k, weight_mu, shear_red, frac_cem
84
+ lower_bound = np.array(
85
+ [
86
+ 0.35, # phi_c
87
+ 0.0, # shear_red
88
+ 0.01, # frac_cem
89
+ ],
90
+ dtype=float,
91
+ )
92
+ upper_bound = np.array(
93
+ [
94
+ 0.45, # phi_c
95
+ 1.0, # shear_red
96
+ 0.1, # frac_cem
97
+ ],
98
+ dtype=float,
99
+ )
100
+
101
+ x0 = (upper_bound + lower_bound) / 2.0
102
+ # Optimisation step without fluid substitution
103
+ vel_mod, vel_res, opt_params = gen_opt_routine(
104
+ opt_fun, x_data, y_data, x0, lower_bound, upper_bound
105
+ )
106
+ frac_cem = opt_params[2]
107
+
108
+ # Reshape outputs and remove weight from vs
109
+ vp_mod, vs_mod = [arr.flatten() for arr in np.split(vel_mod, 2, axis=1)]
110
+ vp_res, vs_res = [arr.flatten() for arr in np.split(vel_res, 2, axis=1)]
111
+ vs_mod = vs_mod / def_vpvs
112
+ vs_res = vs_res / def_vpvs
113
+ vpvs_mod = vp_mod / vs_mod
114
+ # Calculate the modelled density
115
+ rhob_mod = rho_min * (1.0 - por - frac_cem) + frac_cem * rho_cem + por * rho_fl
116
+ ai_mod = vp_mod * rhob_mod
117
+ rhob_res = rhob_mod - rhob
118
+ # Save the optimal parameters
119
+ save_opt_params("const_cem", opt_params, file_out_str, well_name=well_name)
120
+ if display_results:
121
+ from rock_physics_open.t_matrix_models import opt_param_to_ascii
122
+
123
+ opt_param_to_ascii(file_out_str, well_name=well_name)
124
+
125
+ return vp_mod, vs_mod, rhob_mod, ai_mod, vpvs_mod, vp_res, vs_res, rhob_res
@@ -0,0 +1,138 @@
1
+ from rock_physics_open.equinor_utilities import gen_utilities, std_functions
2
+
3
+
4
+ def contact_cement_model(
5
+ k_min,
6
+ mu_min,
7
+ rho_min,
8
+ k_cem,
9
+ mu_cem,
10
+ rho_cem,
11
+ k_fl,
12
+ rho_fl,
13
+ phi,
14
+ frac_cem,
15
+ phi_c,
16
+ n,
17
+ shear_red,
18
+ ):
19
+ """
20
+ Contact cement model is a sandstone model where all variation in porosity is explained by variation in grain contact
21
+ cement. This is leads to the stiffest transition from critical porosity to the mineral point.
22
+
23
+ Mineral properties k_min, muMin, rho_min are effective properties. For mixtures of minerals, effective properties
24
+ are calculated by Hashin-Shtrikman or similar.
25
+
26
+ Cement properties kCem, muCem, rhoCem and cement fraction, the latter as a part of the whole volume.
27
+
28
+ Fluid properties k_fl, rho_fl are in situ properties calculated by fluid models using reservoir properties.
29
+
30
+ Critical porosity phiC is input to Dvorkin-Nur function. Coordination number n is normally set to a fixed value
31
+ (default 9) but it is possible to override this. Porosity phi is used in Hashin-Shtrikman mixing (together with
32
+ phiC) and Gassmann saturation.
33
+
34
+ Shear reduction parameter shearRed is used to account for tangential frictionless grain contacts.
35
+
36
+ All inputs are assumed to be vectors of the same length.
37
+
38
+
39
+ Parameters
40
+ ----------
41
+ k_min : np.ndarray
42
+ Mineral bulk modulus [Pa].
43
+ mu_min : np.ndarray
44
+ Mineral shear modulus [Pa].
45
+ rho_min : np.ndarray
46
+ Mineral bulk density [kg/m^3].
47
+ k_cem : np.ndarray
48
+ Cement bulk modulus [Pa].
49
+ mu_cem : np.ndarray
50
+ Cement shear modulus [Pa].
51
+ rho_cem : np.ndarray
52
+ Cement bulk density [kg/m^3].
53
+ k_fl : np.ndarray
54
+ Fluid bulk modulus [Pa].
55
+ rho_fl : np.ndarray
56
+ Fluid bulk density [kg/m^3].
57
+ phi : np.ndarray
58
+ Porosity [fraction].
59
+ frac_cem : float
60
+ Cement fraction [fraction].
61
+ phi_c : float
62
+ Critical porosity [fraction].
63
+ n : float
64
+ Coordination number [unitless].
65
+ shear_red : float
66
+ Shear reduction factor [fraction].
67
+
68
+ Returns
69
+ -------
70
+ tuple
71
+ vp, vs, rho, ai, vpvs : (np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray)
72
+ vp [m/s] and vs [m/s], bulk density [kg/m^3], ai [m/s x kg/m^3], vpvs [ratio] of saturated rock.
73
+ """
74
+
75
+ # Identify porosity values that are above (phi_c - frac_cem), for which the model is not defined
76
+ (
77
+ idx_phi,
78
+ (k_min, mu_min, rho_min, k_cem, mu_cem, rho_cem, k_fl, rho_fl, phi, _),
79
+ ) = gen_utilities.filter_input_log(
80
+ (
81
+ k_min,
82
+ mu_min,
83
+ rho_min,
84
+ k_cem,
85
+ mu_cem,
86
+ rho_cem,
87
+ k_fl,
88
+ rho_fl,
89
+ phi,
90
+ phi_c - frac_cem - phi,
91
+ )
92
+ )
93
+
94
+ # Expand input parameters to arrays
95
+ phi, frac_cem, phi_c, n, shear_red = gen_utilities.dim_check_vector(
96
+ (phi, frac_cem, phi_c, n, shear_red)
97
+ )
98
+
99
+ # At the zero-porosity point, all original porosity (critical porosity) is
100
+ # filled with cement. The cement surrounds the original grains, so they
101
+ # will be fraction 1 according to the geometrical interpretation of
102
+ # Hashin-Shtrikman
103
+ k_zero, mu_zero = std_functions.hashin_shtrikman_walpole(
104
+ k_cem, mu_cem, k_min, mu_min, phi_c, bound="lower"
105
+ )
106
+
107
+ # Dry rock properties of high-porosity end member calculated with
108
+ # Dvorkin-Nur equation. Cement is assumed to be evenly distributed on the
109
+ # grains (scheme 2 in Dvorkin and Nur's original paper)
110
+
111
+ k_cc, mu_cc = std_functions.dvorkin_contact_cement(
112
+ frac_cem, phi_c, mu_zero, k_zero, mu_cem, k_cem, shear_red, n
113
+ )
114
+
115
+ # Hashin-Shtrikman upper bound describes the dry rock property mixing from
116
+ # mineral properties to high-end porosity.
117
+
118
+ # Fraction of zero-porosity end member
119
+ f1 = 1 - phi / (phi_c - frac_cem)
120
+
121
+ k_dry, mu = std_functions.hashin_shtrikman_walpole(
122
+ k_zero, mu_zero, k_cc, mu_cc, f1, bound="upper"
123
+ )
124
+
125
+ # Saturated rock incompressibility is calculated with Gassmann
126
+ k = std_functions.gassmann(k_dry, phi, k_fl, k_zero)
127
+
128
+ # Bulk density
129
+ rho = phi * rho_fl + (1 - phi_c) * rho_min + (phi_c - phi) * rho_cem
130
+
131
+ vp, vs, ai, vpvs = std_functions.velocity(k, mu, rho)
132
+
133
+ # Restore original array length
134
+ vp, vs, rho, ai, vpvs = gen_utilities.filter_output(
135
+ idx_phi, (vp, vs, rho, ai, vpvs)
136
+ )
137
+
138
+ return vp, vs, rho, ai, vpvs
@@ -0,0 +1,143 @@
1
+ import numpy as np
2
+
3
+ from .constant_cement_models import constant_cement_model
4
+ from .friable_models import friable_model
5
+ from .patchy_cement_model import patchy_cement_model_weight
6
+
7
+
8
+ def curvefit_patchy_cement(x_data, weight_k, weight_mu, shear_red, frac_cem):
9
+ """Run patchy_cement_model_weight with parameter optimisation for closest possible fit to observations
10
+
11
+ Inputs: vp, vs, rho, por, k_fl, rho_fl, p_eff, k_min, mu_min, rho_min, k_cem, mu_cem, rho_cem, phi_c
12
+ Parameters to optimise for: frac_cem, shear_red, weight_k, weight_mu
13
+ Optimise for vp, vs
14
+ """
15
+ # Unpack x inputs
16
+ # In calling function:
17
+ k_min = x_data[:, 0]
18
+ mu_min = x_data[:, 1]
19
+ rho_min = x_data[:, 2]
20
+ k_cem = x_data[:, 3]
21
+ mu_cem = x_data[:, 4]
22
+ rho_cem = x_data[:, 5]
23
+ k_fl = x_data[:, 6]
24
+ rho_fl = x_data[:, 7]
25
+ phi = x_data[:, 8]
26
+ p_eff = x_data[:, 9]
27
+ def_vp_vs_ratio = x_data[0, 10]
28
+ phi_c = x_data[0, 11]
29
+
30
+ # Catch phi values that are above phi_c - frac_cem, reduce silently to phi_c - frac_cem
31
+ phi = np.minimum(phi, phi_c - frac_cem)
32
+
33
+ try:
34
+ vp, vs = patchy_cement_model_weight(
35
+ k_min,
36
+ mu_min,
37
+ rho_min,
38
+ k_cem,
39
+ mu_cem,
40
+ rho_cem,
41
+ k_fl,
42
+ rho_fl,
43
+ phi,
44
+ p_eff,
45
+ frac_cem,
46
+ phi_c,
47
+ "por_based",
48
+ 9.0,
49
+ shear_red,
50
+ weight_k,
51
+ weight_mu,
52
+ )[0:2]
53
+ except ValueError:
54
+ vp = np.zeros(k_min.shape)
55
+ vs = np.zeros(k_min.shape)
56
+
57
+ return np.stack((vp, def_vp_vs_ratio * vs), axis=1).flatten("F")
58
+
59
+
60
+ def curvefit_friable(x_data, phi_c, shear_red):
61
+ """Run friable sand model with parameter optimisation for closest possible fit to observations
62
+
63
+ Inputs: vp, vs, por, k_fl, rho_fl, p_eff, k_min, mu_min, rho_min
64
+ Parameters to optimise for: phi_c, shear_red
65
+ Optimise for vp, vs
66
+ """
67
+ # Unpack x inputs
68
+ k_min = x_data[:, 0]
69
+ mu_min = x_data[:, 1]
70
+ rho_min = x_data[:, 2]
71
+ k_fl = x_data[:, 3]
72
+ rho_fl = x_data[:, 4]
73
+ phi = x_data[:, 5]
74
+ p_eff = x_data[:, 6]
75
+ def_vp_vs_ratio = x_data[0, 7]
76
+
77
+ # Catch phi values that are above phi_c, reduce silently to phi_c
78
+ phi = np.minimum(phi, phi_c)
79
+
80
+ try:
81
+ vp, vs = friable_model(
82
+ k_min,
83
+ mu_min,
84
+ rho_min,
85
+ k_fl,
86
+ rho_fl,
87
+ phi,
88
+ p_eff,
89
+ phi_c,
90
+ "por_based",
91
+ 1.0,
92
+ shear_red,
93
+ )[0:2]
94
+ except ValueError:
95
+ vp = np.zeros(k_min.shape)
96
+ vs = np.zeros(k_min.shape)
97
+
98
+ return np.stack((vp, def_vp_vs_ratio * vs), axis=1).flatten("F")
99
+
100
+
101
+ def curvefit_constant_cement(x_data, phi_c, shear_red, frac_cem):
102
+ """Run constant_cement_model with parameter optimisation for closest possible fit to observations
103
+
104
+ Inputs: vp, vs, por, k_min, mu_min, rho_min, k_cem, mu_cem, rho_cem, k_fl, rho_fl
105
+ Parameters to optimise for: phi_c, shear_red, frac_cem
106
+ Optimise for vp, vs
107
+ """
108
+ # Unpack x inputs
109
+ k_min = x_data[:, 0]
110
+ mu_min = x_data[:, 1]
111
+ rho_min = x_data[:, 2]
112
+ k_cem = x_data[:, 3]
113
+ mu_cem = x_data[:, 4]
114
+ rho_cem = x_data[:, 5]
115
+ k_fl = x_data[:, 6]
116
+ rho_fl = x_data[:, 7]
117
+ phi = x_data[:, 8]
118
+ def_vp_vs_ratio = x_data[0, 9]
119
+
120
+ # Catch phi values that are above phi_c - frac_cem, reduce silently to phi_c - frac_cem
121
+ phi = np.minimum(phi, phi_c - frac_cem)
122
+
123
+ try:
124
+ vp, vs = constant_cement_model(
125
+ k_min,
126
+ mu_min,
127
+ rho_min,
128
+ k_cem,
129
+ mu_cem,
130
+ rho_cem,
131
+ k_fl,
132
+ rho_fl,
133
+ phi,
134
+ frac_cem,
135
+ phi_c,
136
+ 9.0,
137
+ shear_red,
138
+ )[0:2]
139
+ except ValueError:
140
+ vp = np.zeros(k_min.shape)
141
+ vs = np.zeros(k_min.shape)
142
+
143
+ return np.stack((vp, def_vp_vs_ratio * vs), axis=1).flatten("F")
@@ -0,0 +1,177 @@
1
+ from rock_physics_open.equinor_utilities import gen_utilities, std_functions
2
+
3
+
4
+ def friable_model(
5
+ k_min,
6
+ mu_min,
7
+ rho_min,
8
+ k_fl,
9
+ rho_fl,
10
+ phi,
11
+ p_eff,
12
+ phi_c,
13
+ coord_num_func,
14
+ n,
15
+ shear_red,
16
+ ):
17
+ """
18
+ Friable (non-cemented) sandstone model. All porosity variation is due to sorting, i.e. porosity filled with
19
+ smaller grains. This model is pressure sensitive, but without asymptotic behaviour, which could be expected.
20
+
21
+ The same model is also used for shale, with different set of parameters.
22
+
23
+ Mineral properties k_min, mu_min, rho_min are effective properties. For
24
+ mixtures of minerals, effective properties are calculated by
25
+ Hashin-Shtrikman or similar.
26
+
27
+ Fluid properties k_fl, rho_fl are in situ properties calculated by a fluid model using reservoir properties.
28
+
29
+ Effective pressure p_eff is normally calculated as differential
30
+ pressure, i.e. overburden pressure minus pore pressure.
31
+
32
+ Critical porosity phi_c is input to Hertz-Mindlin function. Coordination
33
+ number n is normally calculated from critical porosity, but it is
34
+ possible to override this through coord_num_func and parameter n.
35
+ Porosity phi is used in Hashin-Shtrikman mixing (together with phi_c)
36
+ and Gassmann saturation. Porosity values above the critical porosity are undefined and NaN is returned.
37
+
38
+ Shear reduction parameter shearRed is used to account for tangential
39
+ frictionless grain contacts.
40
+
41
+ All inputs are assumed to be vectors of the same length. Single parameters
42
+ are expanded to column vectors matching other inputs.
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_fl : np.ndarray
53
+ Fluid bulk modulus [Pa].
54
+ rho_fl : np.ndarray
55
+ Fluid bulk density [kg/m^3].
56
+ phi : np.ndarray
57
+ Porosity [fraction].
58
+ p_eff : np.ndarray
59
+ Effective pressure [Pa].
60
+ phi_c : float
61
+ Critical porosity [fraction].
62
+ coord_num_func : str
63
+ Indication if coordination number should be calculated from porosity or kept constant.
64
+ n : float
65
+ Coordination number [unitless].
66
+ shear_red : float
67
+ Shear reduction factor [fraction].
68
+
69
+ Returns
70
+ -------
71
+ tuple
72
+ vp, vs, rho, ai, vpvs : (np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray)
73
+ vp [m/s] and vs [m/s], bulk density [kg/m^3], ai [m/s x kg/m^3], vpvs [ratio] of saturated rock.
74
+ """
75
+ k_dry, mu = friable_model_dry(
76
+ k_min, mu_min, phi, p_eff, phi_c, coord_num_func, n, shear_red
77
+ )
78
+
79
+ # Saturated rock incompressibility is calculated with Gassmann
80
+ k = std_functions.gassmann(k_dry, phi, k_fl, k_min)
81
+
82
+ # Bulk density
83
+ rhob = std_functions.rho_b(phi, rho_fl, rho_min)
84
+
85
+ vp, vs, ai, vpvs = std_functions.velocity(k, mu, rhob)
86
+
87
+ return vp, vs, rhob, ai, vpvs
88
+
89
+
90
+ def friable_model_dry(k_min, mu_min, phi, p_eff, phi_c, coord_num_func, n, shear_red):
91
+ """
92
+ Dry rock version of friable sandstone model.
93
+
94
+ Mineral properties k_min, mu_min, are effective properties. For
95
+ mixtures of minerals, effective properties are calculated by
96
+ Hashin-Shtrikman or similar.
97
+
98
+ Effective pressure p_eff is normally calculated as differential
99
+ pressure, i.e. overburden pressure minus pore pressure.
100
+
101
+ Critical porosity phi_c is input to Hertz-Mindlin function. Coordination
102
+ number n is normally calculated from critical porosity, but it is
103
+ possible to override this through coordNumFunc and parameter n.
104
+ Porosity phi is used in Hashin-Shtrikman mixing (together with phi_c).
105
+ Porosity values above the critical porosity are undefined and NaN is returned.
106
+
107
+ Shear reduction parameter shearRed is used to account for tangential
108
+ frictionless grain contacts.
109
+
110
+ All inputs are assumed to be vectors of the same length. Single parameters
111
+ are expanded to column vectors matching other inputs.
112
+
113
+ Parameters
114
+ ----------
115
+ k_min : np.ndarray
116
+ Mineral bulk modulus [Pa].
117
+ mu_min : np.ndarray
118
+ Mineral shear modulus [Pa].
119
+ phi : np.ndarray
120
+ Porosity [fraction].
121
+ p_eff : np.ndarray
122
+ Effective pressure [Pa].
123
+ phi_c : float
124
+ Critical porosity [fraction].
125
+ coord_num_func : str
126
+ Indication if coordination number should be calculated from porosity or kept constant.
127
+ n : float | None
128
+ Coordination number [unitless].
129
+ shear_red : float
130
+ Shear reduction factor [fraction].
131
+
132
+ Returns
133
+ -------
134
+ tuple
135
+ k, mu : (np.ndarray, np.ndarray).
136
+ Bulk modulus k [Pa], shear modulus mu [Pa] of dry rock.
137
+ """
138
+ # Expand floats to arrays, check for equal length
139
+ phi, phi_c, shear_red, k_min, mu_min, p_eff = gen_utilities.dim_check_vector(
140
+ (phi, phi_c, shear_red, k_min, mu_min, p_eff)
141
+ )
142
+ # Valid porosity values are less or equal to the critical porosity
143
+ # Use filter_input_log to remove values that do not comply with this
144
+ (
145
+ idx_phi,
146
+ (phi, phi_c, shear_red, k_min, mu_min, p_eff, _),
147
+ ) = gen_utilities.filter_input_log(
148
+ (phi, phi_c, shear_red, k_min, mu_min, p_eff, phi_c - phi)
149
+ )
150
+
151
+ # Dry rock properties of high-porosity end member calculated with
152
+ # Hertz-Mindlin equation
153
+
154
+ # Override coordination number calculation based on porosity
155
+ if coord_num_func == "ConstVal":
156
+ k_hm, mu_hm = std_functions.hertz_mindlin(
157
+ k_min, mu_min, phi_c, p_eff, shear_red, n
158
+ )
159
+ else:
160
+ # Porosity based coordination number
161
+ k_hm, mu_hm = std_functions.hertz_mindlin(
162
+ k_min, mu_min, phi_c, p_eff, shear_red
163
+ )
164
+
165
+ # Hashin-Shtrikman lower bound describes the dry rock property mixing from
166
+ # mineral properties to high-end porosity.
167
+
168
+ # Fraction of solid
169
+ f1 = 1 - phi / phi_c
170
+
171
+ k_dry, mu = std_functions.hashin_shtrikman_walpole(
172
+ k_min, mu_min, k_hm, mu_hm, f1, bound="lower"
173
+ )
174
+
175
+ k_dry, mu = gen_utilities.filter_output(idx_phi, (k_dry, mu))
176
+
177
+ return k_dry, mu
@@ -0,0 +1,115 @@
1
+ import numpy as np
2
+
3
+ from rock_physics_open.equinor_utilities import gen_utilities
4
+ from rock_physics_open.equinor_utilities.optimisation_utilities import (
5
+ gen_opt_routine,
6
+ save_opt_params,
7
+ )
8
+
9
+ from .curvefit_sandstone_models import curvefit_friable
10
+
11
+
12
+ def friable_model_optimisation(
13
+ k_min: np.ndarray,
14
+ mu_min: np.ndarray,
15
+ rho_min: np.ndarray,
16
+ k_fl: np.ndarray,
17
+ rho_fl: np.ndarray,
18
+ por: np.ndarray,
19
+ p_eff: np.ndarray,
20
+ vp: np.ndarray,
21
+ vs: np.ndarray,
22
+ rhob: np.ndarray,
23
+ file_out_str: str = "friable_model_optimal_params.pkl",
24
+ display_results: bool = False,
25
+ well_name: str = "Unknown well",
26
+ ):
27
+ """Patchy cement model with optimisation for a selection of parameters.
28
+
29
+ Parameters
30
+ ----------
31
+ k_min :
32
+ Cement bulk modulus [Pa].
33
+ mu_min :
34
+ Cement shear modulus [Pa].
35
+ rho_min :
36
+ Cement density [kg/m^3].
37
+ k_fl :
38
+ Fluid bulk modulus [Pa].
39
+ rho_fl :
40
+ Fluid density [kg/m^3].
41
+ por :
42
+ Inclusion porosity [ratio].
43
+ vp :
44
+ Compressional velocity log [m/s].
45
+ vs :
46
+ Shear velocity log [m/s].
47
+ rhob :
48
+ Bulk density log [kg/m^3].
49
+ p_eff :
50
+ Effective pressure log [Pa].
51
+ file_out_str :
52
+ Output file name (string) to store optimal parameters (pickle format).
53
+ display_results :
54
+ D isplay optimal parameters in a window after run.
55
+ well_name :
56
+ Name of well to be displayed in info box title.
57
+
58
+ Returns
59
+ -------
60
+ tuple
61
+ vp_mod, vs_mod, rho_mod, ai_mod, vpvs_mod - modelled logs, vp_res, vs_res, rho_res - residual logs.
62
+ """
63
+
64
+ # Skip hardcoded Vp/Vs ratio
65
+ def_vpvs = np.mean(vp / vs)
66
+ # Set weight to vs to give vp and vs similar influence on optimisation
67
+ y_data = np.stack([vp, vs * def_vpvs], axis=1)
68
+ # Optimisation function for selected parameters
69
+ opt_fun = curvefit_friable
70
+ # expand single value parameters to match logs length
71
+ por, def_vpvs = gen_utilities.dim_check_vector((por, def_vpvs))
72
+ x_data = np.stack(
73
+ (k_min, mu_min, rho_min, k_fl, rho_fl, por, p_eff, def_vpvs), axis=1
74
+ )
75
+
76
+ # Params: weight_k, weight_mu, shear_red, frac_cem
77
+ lower_bound = np.array(
78
+ [
79
+ 0.35, # phi_c
80
+ 0.0, # shear_red
81
+ ],
82
+ dtype=float,
83
+ )
84
+ upper_bound = np.array(
85
+ [
86
+ 0.45, # phi_c
87
+ 1.0, # shear_red
88
+ ],
89
+ dtype=float,
90
+ )
91
+
92
+ x0 = (upper_bound + lower_bound) / 2.0
93
+ # Optimisation step without fluid substitution
94
+ vel_mod, vel_res, opt_params = gen_opt_routine(
95
+ opt_fun, x_data, y_data, x0, lower_bound, upper_bound
96
+ )
97
+
98
+ # Reshape outputs and remove weight from vs
99
+ vp_mod, vs_mod = [arr.flatten() for arr in np.split(vel_mod, 2, axis=1)]
100
+ vp_res, vs_res = [arr.flatten() for arr in np.split(vel_res, 2, axis=1)]
101
+ vs_mod = vs_mod / def_vpvs
102
+ vs_res = vs_res / def_vpvs
103
+ vpvs_mod = vp_mod / vs_mod
104
+ # Calculate the modelled density
105
+ rhob_mod = rho_min * (1.0 - por) + por * rho_fl
106
+ ai_mod = vp_mod * rhob_mod
107
+ rhob_res = rhob_mod - rhob
108
+ # Save the optimal parameters
109
+ save_opt_params("friable", opt_params, file_out_str, well_name=well_name)
110
+ if display_results:
111
+ from rock_physics_open.t_matrix_models import opt_param_to_ascii
112
+
113
+ opt_param_to_ascii(file_out_str, well_name=well_name)
114
+
115
+ return vp_mod, vs_mod, rhob_mod, ai_mod, vpvs_mod, vp_res, vs_res, rhob_res