rock-physics-open 0.0__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.

Potentially problematic release.


This version of rock-physics-open might be problematic. Click here for more details.

Files changed (142) 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 +162 -0
  4. rock_physics_open/equinor_utilities/classification_functions/__init__.py +17 -0
  5. rock_physics_open/equinor_utilities/classification_functions/class_stats.py +58 -0
  6. rock_physics_open/equinor_utilities/classification_functions/lin_class.py +47 -0
  7. rock_physics_open/equinor_utilities/classification_functions/mahal_class.py +56 -0
  8. rock_physics_open/equinor_utilities/classification_functions/norm_class.py +65 -0
  9. rock_physics_open/equinor_utilities/classification_functions/poly_class.py +40 -0
  10. rock_physics_open/equinor_utilities/classification_functions/post_prob.py +26 -0
  11. rock_physics_open/equinor_utilities/classification_functions/two_step_classification.py +46 -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 +33 -0
  15. rock_physics_open/equinor_utilities/gen_utilities/dim_check_vector.py +83 -0
  16. rock_physics_open/equinor_utilities/gen_utilities/filter_input.py +126 -0
  17. rock_physics_open/equinor_utilities/gen_utilities/filter_output.py +78 -0
  18. rock_physics_open/equinor_utilities/machine_learning_utilities/__init__.py +14 -0
  19. rock_physics_open/equinor_utilities/machine_learning_utilities/dummy_vars.py +42 -0
  20. rock_physics_open/equinor_utilities/machine_learning_utilities/exponential_model.py +119 -0
  21. rock_physics_open/equinor_utilities/machine_learning_utilities/import_ml_models.py +61 -0
  22. rock_physics_open/equinor_utilities/machine_learning_utilities/run_regression.py +151 -0
  23. rock_physics_open/equinor_utilities/machine_learning_utilities/sigmoidal_model.py +188 -0
  24. rock_physics_open/equinor_utilities/snapshot_test_utilities/__init__.py +10 -0
  25. rock_physics_open/equinor_utilities/snapshot_test_utilities/compare_snapshots.py +145 -0
  26. rock_physics_open/equinor_utilities/snapshot_test_utilities/snapshots.py +54 -0
  27. rock_physics_open/equinor_utilities/std_functions/__init__.py +43 -0
  28. rock_physics_open/equinor_utilities/std_functions/backus_ave.py +53 -0
  29. rock_physics_open/equinor_utilities/std_functions/dvorkin_nur.py +69 -0
  30. rock_physics_open/equinor_utilities/std_functions/gassmann.py +140 -0
  31. rock_physics_open/equinor_utilities/std_functions/hashin_shtrikman.py +195 -0
  32. rock_physics_open/equinor_utilities/std_functions/hertz_mindlin.py +43 -0
  33. rock_physics_open/equinor_utilities/std_functions/moduli_velocity.py +51 -0
  34. rock_physics_open/equinor_utilities/std_functions/reflection_eq.py +98 -0
  35. rock_physics_open/equinor_utilities/std_functions/rho.py +59 -0
  36. rock_physics_open/equinor_utilities/std_functions/voigt_reuss_hill.py +128 -0
  37. rock_physics_open/equinor_utilities/std_functions/walton.py +38 -0
  38. rock_physics_open/equinor_utilities/std_functions/wood_brie.py +77 -0
  39. rock_physics_open/equinor_utilities/various_utilities/Equinor_logo.gif +0 -0
  40. rock_physics_open/equinor_utilities/various_utilities/Equinor_logo.ico +0 -0
  41. rock_physics_open/equinor_utilities/various_utilities/__init__.py +24 -0
  42. rock_physics_open/equinor_utilities/various_utilities/display_result_statistics.py +83 -0
  43. rock_physics_open/equinor_utilities/various_utilities/gassmann_dry_mod.py +37 -0
  44. rock_physics_open/equinor_utilities/various_utilities/gassmann_mod.py +37 -0
  45. rock_physics_open/equinor_utilities/various_utilities/gassmann_sub_mod.py +53 -0
  46. rock_physics_open/equinor_utilities/various_utilities/hs_average.py +40 -0
  47. rock_physics_open/equinor_utilities/various_utilities/pressure.py +88 -0
  48. rock_physics_open/equinor_utilities/various_utilities/reflectivity.py +85 -0
  49. rock_physics_open/equinor_utilities/various_utilities/timeshift.py +91 -0
  50. rock_physics_open/equinor_utilities/various_utilities/vp_vs_rho_set_statistics.py +154 -0
  51. rock_physics_open/equinor_utilities/various_utilities/vrh_3_min.py +61 -0
  52. rock_physics_open/fluid_models/__init__.py +9 -0
  53. rock_physics_open/fluid_models/brine_model/__init__.py +5 -0
  54. rock_physics_open/fluid_models/brine_model/brine_properties.py +143 -0
  55. rock_physics_open/fluid_models/gas_model/__init__.py +5 -0
  56. rock_physics_open/fluid_models/gas_model/gas_properties.py +277 -0
  57. rock_physics_open/fluid_models/oil_model/__init__.py +5 -0
  58. rock_physics_open/fluid_models/oil_model/dead_oil_density.py +60 -0
  59. rock_physics_open/fluid_models/oil_model/dead_oil_velocity.py +28 -0
  60. rock_physics_open/fluid_models/oil_model/live_oil_density.py +79 -0
  61. rock_physics_open/fluid_models/oil_model/live_oil_velocity.py +24 -0
  62. rock_physics_open/fluid_models/oil_model/oil_bubble_point.py +69 -0
  63. rock_physics_open/fluid_models/oil_model/oil_properties.py +114 -0
  64. rock_physics_open/sandstone_models/__init__.py +57 -0
  65. rock_physics_open/sandstone_models/cemented_shalysand_sandyshale_models.py +304 -0
  66. rock_physics_open/sandstone_models/constant_cement_models.py +204 -0
  67. rock_physics_open/sandstone_models/constant_cement_optimisation.py +122 -0
  68. rock_physics_open/sandstone_models/contact_cement_model.py +138 -0
  69. rock_physics_open/sandstone_models/curvefit_sandstone_models.py +143 -0
  70. rock_physics_open/sandstone_models/friable_models.py +178 -0
  71. rock_physics_open/sandstone_models/friable_optimisation.py +112 -0
  72. rock_physics_open/sandstone_models/friable_shalysand_sandyshale_models.py +235 -0
  73. rock_physics_open/sandstone_models/patchy_cement_fluid_substitution_model.py +477 -0
  74. rock_physics_open/sandstone_models/patchy_cement_model.py +286 -0
  75. rock_physics_open/sandstone_models/patchy_cement_optimisation.py +251 -0
  76. rock_physics_open/sandstone_models/unresolved_cemented_sandshale_models.py +134 -0
  77. rock_physics_open/sandstone_models/unresolved_friable_sandshale_models.py +126 -0
  78. rock_physics_open/shale_models/__init__.py +19 -0
  79. rock_physics_open/shale_models/dem.py +174 -0
  80. rock_physics_open/shale_models/dem_dual_por.py +61 -0
  81. rock_physics_open/shale_models/kus_tok.py +59 -0
  82. rock_physics_open/shale_models/multi_sca.py +133 -0
  83. rock_physics_open/shale_models/pq.py +102 -0
  84. rock_physics_open/shale_models/sca.py +90 -0
  85. rock_physics_open/shale_models/shale4_mineral.py +147 -0
  86. rock_physics_open/shale_models/shale4_mineral_dem_overlay.py +92 -0
  87. rock_physics_open/span_wagner/__init__.py +5 -0
  88. rock_physics_open/span_wagner/co2_properties.py +438 -0
  89. rock_physics_open/span_wagner/coefficients.py +165 -0
  90. rock_physics_open/span_wagner/equations.py +104 -0
  91. rock_physics_open/span_wagner/tables/__init__.py +0 -0
  92. rock_physics_open/span_wagner/tables/carbon_dioxide_density.npz +0 -0
  93. rock_physics_open/span_wagner/tables/lookup_table.py +33 -0
  94. rock_physics_open/t_matrix_models/Equinor_logo.ico +0 -0
  95. rock_physics_open/t_matrix_models/__init__.py +45 -0
  96. rock_physics_open/t_matrix_models/carbonate_pressure_substitution.py +124 -0
  97. rock_physics_open/t_matrix_models/curvefit_t_matrix_exp.py +124 -0
  98. rock_physics_open/t_matrix_models/curvefit_t_matrix_min.py +86 -0
  99. rock_physics_open/t_matrix_models/opt_subst_utilities.py +415 -0
  100. rock_physics_open/t_matrix_models/parse_t_matrix_inputs.py +297 -0
  101. rock_physics_open/t_matrix_models/run_t_matrix.py +243 -0
  102. rock_physics_open/t_matrix_models/t_matrix_C.py +210 -0
  103. rock_physics_open/t_matrix_models/t_matrix_opt_fluid_sub_exp.py +137 -0
  104. rock_physics_open/t_matrix_models/t_matrix_opt_fluid_sub_petec.py +163 -0
  105. rock_physics_open/t_matrix_models/t_matrix_opt_forward_model_exp.py +72 -0
  106. rock_physics_open/t_matrix_models/t_matrix_opt_forward_model_min.py +86 -0
  107. rock_physics_open/t_matrix_models/t_matrix_parameter_optimisation_exp.py +172 -0
  108. rock_physics_open/t_matrix_models/t_matrix_parameter_optimisation_min.py +159 -0
  109. rock_physics_open/t_matrix_models/t_matrix_vector/__init__.py +12 -0
  110. rock_physics_open/t_matrix_models/t_matrix_vector/array_functions.py +75 -0
  111. rock_physics_open/t_matrix_models/t_matrix_vector/calc_c_eff.py +163 -0
  112. rock_physics_open/t_matrix_models/t_matrix_vector/calc_isolated.py +95 -0
  113. rock_physics_open/t_matrix_models/t_matrix_vector/calc_kd.py +40 -0
  114. rock_physics_open/t_matrix_models/t_matrix_vector/calc_kd_eff.py +116 -0
  115. rock_physics_open/t_matrix_models/t_matrix_vector/calc_kd_uuv.py +18 -0
  116. rock_physics_open/t_matrix_models/t_matrix_vector/calc_pressure.py +140 -0
  117. rock_physics_open/t_matrix_models/t_matrix_vector/calc_t.py +71 -0
  118. rock_physics_open/t_matrix_models/t_matrix_vector/calc_td.py +42 -0
  119. rock_physics_open/t_matrix_models/t_matrix_vector/calc_theta.py +43 -0
  120. rock_physics_open/t_matrix_models/t_matrix_vector/calc_x.py +33 -0
  121. rock_physics_open/t_matrix_models/t_matrix_vector/calc_z.py +50 -0
  122. rock_physics_open/t_matrix_models/t_matrix_vector/check_and_tile.py +43 -0
  123. rock_physics_open/t_matrix_models/t_matrix_vector/g_tensor.py +140 -0
  124. rock_physics_open/t_matrix_models/t_matrix_vector/iso_av.py +60 -0
  125. rock_physics_open/t_matrix_models/t_matrix_vector/iso_ave_all.py +55 -0
  126. rock_physics_open/t_matrix_models/t_matrix_vector/pressure_input.py +44 -0
  127. rock_physics_open/t_matrix_models/t_matrix_vector/t_matrix_vec.py +278 -0
  128. rock_physics_open/t_matrix_models/t_matrix_vector/velocity_vti_angles.py +81 -0
  129. rock_physics_open/t_matrix_models/tmatrix_python.dll +0 -0
  130. rock_physics_open/t_matrix_models/tmatrix_python.so +0 -0
  131. rock_physics_open/ternary_plots/__init__.py +3 -0
  132. rock_physics_open/ternary_plots/gen_ternary_plot.py +73 -0
  133. rock_physics_open/ternary_plots/shale_prop_ternary.py +337 -0
  134. rock_physics_open/ternary_plots/ternary_patches.py +277 -0
  135. rock_physics_open/ternary_plots/ternary_plot_utilities.py +197 -0
  136. rock_physics_open/ternary_plots/unconventionals_ternary.py +75 -0
  137. rock_physics_open/version.py +21 -0
  138. rock_physics_open-0.0.dist-info/METADATA +92 -0
  139. rock_physics_open-0.0.dist-info/RECORD +142 -0
  140. rock_physics_open-0.0.dist-info/WHEEL +5 -0
  141. rock_physics_open-0.0.dist-info/licenses/LICENSE +165 -0
  142. rock_physics_open-0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,415 @@
1
+ import os
2
+ import pickle
3
+
4
+ # from scipy.optimize import minimize, Bounds
5
+ import sys
6
+
7
+ import numpy as np
8
+ from scipy.optimize import curve_fit
9
+
10
+
11
+ def curve_fit_wrapper(x_init, opt_func, x_data, y_data, *args, **opt_kwargs):
12
+ """Use in tests with scipy.optimize.minimize instead of curve_fit.
13
+
14
+ Parameters
15
+ ----------
16
+ x_init : np.ndarray
17
+ Initial guess for parameters.
18
+ opt_func : callable
19
+ Function to optimize.
20
+ x_data : np.ndarray
21
+ Input data to opt_func.
22
+ y_data : np.ndarray
23
+ Results that the optimisation should match.
24
+ args :
25
+ args opt_func.
26
+ opt_kwargs :
27
+ kwargs opt_func.
28
+
29
+ Returns
30
+ -------
31
+ np.ndarray
32
+ res values.
33
+ """
34
+ y_pred = opt_func(x_data, *x_init, *args, **opt_kwargs)
35
+ return np.sum(np.sqrt((y_data - y_pred) ** 2))
36
+
37
+
38
+ def gen_opt_routine(
39
+ opt_function, x_data_orig, y_data, x_init, low_bound, high_bound, **opt_kwargs
40
+ ):
41
+ """
42
+ This function is a lean method for running optimisation with the given opt_function in curve_fit. Predicted values,
43
+ residuals to the observed values and optimal parameters are returned.
44
+
45
+ Parameters
46
+ ----------
47
+ opt_function : callable
48
+ function to optimise
49
+ x_data_orig : np.ndarray
50
+ input data to the function - independent variables
51
+ y_data : np.ndarray
52
+ results that the optimisation should match - dependent variables
53
+ x_init : np.ndarray
54
+ initial guess for parameters
55
+ low_bound : np.ndarray
56
+ parameter low bound
57
+ high_bound : np.ndarray
58
+ parameter high bound
59
+ opt_kwargs : dict
60
+ optional meta-parameters to the optimisation function
61
+
62
+ Returns
63
+ -------
64
+ tuple
65
+ y_pred, y_res, opt_params : (np.ndarray, np.ndarray, np.ndarray).
66
+ y_pred : predicted values,
67
+ y_res : residual values,
68
+ opt_params : optimal model parameters.
69
+ """
70
+ try:
71
+ opt_params, param_cov = curve_fit(
72
+ opt_function,
73
+ x_data_orig,
74
+ y_data.flatten("F"),
75
+ x_init,
76
+ bounds=(low_bound, high_bound),
77
+ method="trf",
78
+ loss="soft_l1",
79
+ **opt_kwargs,
80
+ )
81
+
82
+ except ValueError:
83
+ raise ValueError(
84
+ "gen_opt_routine: failed in optimisation step: {}".format(
85
+ str(sys.exc_info())
86
+ )
87
+ )
88
+ else:
89
+ y_pred = np.reshape(
90
+ opt_function(x_data_orig, *opt_params), y_data.shape, order="F"
91
+ )
92
+ y_res = y_pred - y_data
93
+
94
+ # Alternative implementation, not shown to improve results
95
+ # alt_opt_params = minimize(curve_fit_wrapper, x_init, args=(opt_function, x_data_orig, y_data.flatten('F')),
96
+ # bounds=Bounds(low_bound, high_bound), method='SLSQP', options={'maxiter': 10000})
97
+ # y_pred_1 = np.reshape(opt_function(x_data_orig, *alt_opt_params['x'], **opt_kwargs), y_data.shape, order='F')
98
+ # y_res_1 = y_pred_1 - y_data
99
+ # return y_pred_1, y_res_1, alt_opt_params['x']
100
+
101
+ return y_pred, y_res, opt_params
102
+
103
+
104
+ def gen_mod_routine(opt_function, xdata_orig, ydata_shape, opt_params):
105
+ """Predict modelled values based on an earlier optimisation run for optimal model parameters.
106
+
107
+ Parameters
108
+ ----------
109
+ opt_function : callable
110
+ Function to optimise.
111
+ xdata_orig : np.ndarray
112
+ Input data to the function - independent variables.
113
+ ydata_shape : (int, int)
114
+ Shape of y_data.
115
+ opt_params : np.ndarray
116
+ Optimal model parameters.
117
+
118
+ Returns
119
+ -------
120
+ np.ndarray
121
+ Predicted values.
122
+ """
123
+ # Estimation of values
124
+ return np.reshape(opt_function(xdata_orig, *opt_params), ydata_shape, order="F")
125
+
126
+
127
+ def gen_sub_routine(opt_function, xdata_orig, xdata_new, ydata, opt_params):
128
+ """General substitution function based on a calibrated/optimised model and with two sets of input parameters.
129
+ The substituted values are calculated as the original observations plus the difference of the two modelling
130
+ steps.
131
+
132
+ Parameters
133
+ ----------
134
+ opt_function : callable
135
+ Function to optimise.
136
+ xdata_orig : np.ndarray
137
+ Input data to the function step 1 - independent variables.
138
+ xdata_new : np.ndarray
139
+ Input data to the function step 2 - independent variables.
140
+ ydata : np.ndarray
141
+ Original observed values step 1.
142
+ opt_params : np.ndarray
143
+ Set of optimal parameters to model.
144
+
145
+ Returns
146
+ -------
147
+ tuple
148
+ y_final, y_pred, y_res : (np.ndarray, np.ndarray, np.ndarray).
149
+ Original observed data + difference in estimation between steps 0 and 1, y_pred - modelled data,
150
+ y_res - residuals, opt_params - best parameter setting.
151
+ """
152
+ # Estimation of initial values
153
+ y_pred = np.reshape(opt_function(xdata_orig, *opt_params), ydata.shape, order="F")
154
+ # Estimation step for substituted fluid properties
155
+ y_subst = np.reshape(opt_function(xdata_new, *opt_params), ydata.shape, "F")
156
+
157
+ y_res = y_pred - ydata
158
+ y_diff = y_subst - y_pred
159
+ y_final = ydata + y_diff
160
+
161
+ return y_final, y_pred, y_res
162
+
163
+
164
+ def save_opt_params(
165
+ opt_type: str,
166
+ opt_params: np.ndarray,
167
+ file_name: str = "opt_params.pkl",
168
+ well_name: str = "Unknown well",
169
+ ):
170
+ """
171
+ Utility to save optimal parameters as a pickle file in a more readable format so that the optimisation method can be
172
+ recognised.
173
+
174
+ Parameters
175
+ ----------
176
+ opt_type : str
177
+ String defining optimisation type.
178
+ opt_params : np.ndarray
179
+ Numpy array with parameters from optimisation.
180
+ file_name : str, optional
181
+ File to save results to, by default 'opt_params.pkl'.
182
+ well_name : str, optional
183
+ Name of the well which is used in optimisation, by default 'Unknown well'.
184
+
185
+ Raises
186
+ ------
187
+ ValueError
188
+ If unknown optimisation opt_type.
189
+ """
190
+ # Save the optimal parameters with info
191
+ if opt_type == "min": # optimisation with mineral input from well
192
+ opt_param_dict = {
193
+ "well_name": well_name,
194
+ "opt_ver": opt_type,
195
+ "f_ani": opt_params[0],
196
+ "f_con": opt_params[1],
197
+ "alpha_opt": opt_params[2:4],
198
+ "v_opt": opt_params[4],
199
+ "opt_vec": opt_params,
200
+ }
201
+ elif opt_type == "exp":
202
+ opt_param_dict = {
203
+ "well_name": well_name,
204
+ "opt_ver": opt_type,
205
+ "f_ani": opt_params[0],
206
+ "f_con": opt_params[1],
207
+ "alpha_opt": opt_params[2:4],
208
+ "v_opt": opt_params[4],
209
+ "k_carb": opt_params[5],
210
+ "mu_carb": opt_params[6],
211
+ "rho_carb": opt_params[7],
212
+ "k_sh": opt_params[8],
213
+ "mu_sh": opt_params[9],
214
+ "rho_sh": opt_params[10],
215
+ "opt_vec": opt_params,
216
+ }
217
+ elif opt_type == "pat_cem":
218
+ opt_param_dict = {
219
+ "well_name": well_name,
220
+ "opt_ver": opt_type,
221
+ "weight_k": opt_params[0],
222
+ "weight_mu": opt_params[1],
223
+ "shear_red": opt_params[2],
224
+ "frac_cem": opt_params[3],
225
+ "opt_vec": opt_params,
226
+ }
227
+ elif opt_type == "const_cem":
228
+ opt_param_dict = {
229
+ "well_name": well_name,
230
+ "opt_ver": opt_type,
231
+ "phi_c": opt_params[0],
232
+ "shear_red": opt_params[1],
233
+ "frac_cem": opt_params[2],
234
+ "opt_vec": opt_params,
235
+ }
236
+ elif opt_type == "friable":
237
+ opt_param_dict = {
238
+ "well_name": well_name,
239
+ "opt_ver": opt_type,
240
+ "phi_c": opt_params[0],
241
+ "shear_red": opt_params[1],
242
+ "opt_vec": opt_params,
243
+ }
244
+ else:
245
+ raise ValueError(
246
+ "save_opt_params: unknown optimisation opt_type: {}".format(opt_type)
247
+ )
248
+
249
+ with open(file_name, "wb") as file_out:
250
+ pickle.dump(opt_param_dict, file_out)
251
+
252
+
253
+ def opt_param_info():
254
+ """Hard coded dictionaries returned.
255
+ Returns
256
+ -------
257
+ tuple
258
+ parameter_translation_dict, value_translation_dict, type_translation_dict.
259
+ """
260
+ parameter_translation_dict = {
261
+ "opt_ver": "Optimisation version",
262
+ "no_incl_sets": "Number of inclusion sets",
263
+ "ang_sym": "Angle of symmetry plane [°]",
264
+ "f_ani": "Fraction of anisotropic inclusions",
265
+ "f_con": "Fraction of connected inclusions",
266
+ "alpha_opt": "Optimal aspect ratios for inclusion sets",
267
+ "v_opt": "Ratio of volume for inclusion sets",
268
+ "k_carb": "Matrix (carbonate) bulk modulus [Pa]",
269
+ "mu_carb": "Matrix (carbonate) shear modulus [Pa]",
270
+ "rho_carb": "Matrix (carbonate) density [kg/m^3]",
271
+ "k_sh": "Mud/shale bulk modulus [Pa]",
272
+ "mu_sh": "Mud/shale shear modulus [Pa]",
273
+ "rho_sh": "Mud/shale density [kg/m^3]",
274
+ "k_sst": "Sst bulk modulus [Pa]",
275
+ "mu_sst": "Sst shear modulus [Pa]",
276
+ "rho_sst": "Sst density [kg/m^3]",
277
+ "frac_cem": "Cement fraction [fraction]",
278
+ "phi_c": "Critical porosity [fraction]",
279
+ "shear_red": "Reduction in tangential friction [fraction]",
280
+ "weight_k": "Bulk modulus weight for constant cement model",
281
+ "weight_mu": "Shear modulus weight for constant cement model",
282
+ }
283
+ value_translation_dict = {
284
+ "ang_sym": 90.0,
285
+ "k_carb": 95.0e9,
286
+ "mu_carb": 45.0e9,
287
+ "rho_carb": 2950.0,
288
+ "k_sh": 35.0e9,
289
+ "mu_sh": 20.0e9,
290
+ "rho_sh": 2750.0,
291
+ "k_sst": 45.0e9,
292
+ "mu_sst": 50.0e9,
293
+ "rho_sst": 2750.0,
294
+ }
295
+ type_translation_dict = {
296
+ "min": "PETEC (Mineral input) optimisation",
297
+ "exp": "Exploration type optimisation",
298
+ "pat_cem": "Patchy cement model",
299
+ "const_cem": "Constant cement model",
300
+ "friable": "Friable sand model",
301
+ }
302
+ return parameter_translation_dict, value_translation_dict, type_translation_dict
303
+
304
+
305
+ def load_opt_params(file_name: str):
306
+ """Utility to load parameter file from optimisation run.
307
+
308
+ Parameters
309
+ ----------
310
+ file_name : str
311
+ Input file name including path.
312
+
313
+ Returns
314
+ -------
315
+ tuple
316
+ opt_type: model type, no_sets: number of inclusion sets, opt_param: with all parameters for model.
317
+ """
318
+ with open(file_name, "rb") as fin:
319
+ param_dict = pickle.load(fin)
320
+ opt_type = param_dict["opt_ver"]
321
+ opt_param = param_dict["opt_vec"]
322
+ opt_dict = param_dict
323
+
324
+ return opt_type, opt_param, opt_dict
325
+
326
+
327
+ def opt_param_to_ascii(
328
+ in_file, display_results=True, out_file=None, well_name="Unknown well", **kwargs
329
+ ):
330
+ """Utility to convert stored optimised parameters to ascii and display results or save to file.
331
+
332
+ Parameters
333
+ ----------
334
+ in_file : str
335
+ File name for stored optimised parameters.
336
+ display_results : bool
337
+ Display results on screen, default True.
338
+ out_file : str or None
339
+ Optional store optimised parameters in ascii file.
340
+ well_name : str
341
+ Optional name of the well that is used in optimisation.
342
+ """
343
+ with open(in_file, "rb") as f_in:
344
+ param_dict = pickle.load(f_in)
345
+ if well_name.lower() == "unknown well":
346
+ well_name = param_dict.pop("well_name", "Unknown Well")
347
+
348
+ (
349
+ parameter_translation_dict,
350
+ value_translation_dict,
351
+ type_translation_dict,
352
+ ) = opt_param_info()
353
+
354
+ item = []
355
+ value = []
356
+ disp_string = ""
357
+ for opt_key, opt_value in param_dict.items():
358
+ if opt_key in parameter_translation_dict:
359
+ if opt_key in value_translation_dict:
360
+ opt_value = opt_value * value_translation_dict[opt_key]
361
+ opt_str = f" {opt_value:.4f}"
362
+ elif opt_key == "opt_ver":
363
+ opt_str = type_translation_dict[opt_value]
364
+ elif opt_key == "v_opt":
365
+ opt_value = np.append(opt_value, 1.0 - np.sum(opt_value))
366
+ opt_str = f" {opt_value:}"
367
+ else:
368
+ if isinstance(opt_value, float):
369
+ opt_str = f" {opt_value:.4f}"
370
+ else:
371
+ opt_str = f" {opt_value:}"
372
+ item.append(f"{parameter_translation_dict[opt_key]}: ")
373
+ value.append(opt_str)
374
+ disp_string += f"{parameter_translation_dict[opt_key]}: {opt_str}\n"
375
+ info_array = np.stack((item, value), axis=1)
376
+
377
+ if display_results:
378
+ from tkinter import END, Entry, Tk
379
+
380
+ class Table:
381
+ def __init__(self, tk_root, no_rows, no_cols, info):
382
+ # code for creating table
383
+ str_len = np.vectorize(len)
384
+ text_justify = ["right", "left"]
385
+ for i in range(no_rows):
386
+ for j in range(no_cols):
387
+ just = text_justify[0] if j == 0 else text_justify[1]
388
+ max_len = np.max(str_len(info[:, j]))
389
+ self.e = Entry(
390
+ root,
391
+ width=max_len + 2,
392
+ fg="black",
393
+ font=("Consolas", 11, "normal"),
394
+ justify=just,
395
+ )
396
+ self.e.grid(row=i, column=j)
397
+ self.e.insert(END, info[i][j])
398
+
399
+ root = Tk(**kwargs)
400
+ if well_name.lower() == "unknown well":
401
+ root.title("T Matrix Optimised Parameters")
402
+ else:
403
+ root.title(well_name)
404
+ if sys.platform.startswith("win"):
405
+ ico_file = os.path.join(os.path.dirname(__file__), "Equinor_logo.ico")
406
+ root.iconbitmap(ico_file)
407
+ Table(root, info_array.shape[0], info_array.shape[1], info_array)
408
+ root.attributes("-topmost", True)
409
+ root.mainloop()
410
+
411
+ if out_file is not None:
412
+ with open(out_file, "w") as f_out:
413
+ f_out.write(disp_string)
414
+
415
+ return
@@ -0,0 +1,297 @@
1
+ import sys
2
+
3
+ import numpy as np
4
+
5
+ from rock_physics_open import t_matrix_models
6
+ from rock_physics_open.equinor_utilities import gen_utilities
7
+
8
+
9
+ def parse_t_matrix_inputs(
10
+ k_min,
11
+ mu_min,
12
+ rho_min,
13
+ k_fl,
14
+ rho_fl,
15
+ phi,
16
+ perm,
17
+ visco,
18
+ alpha,
19
+ v,
20
+ tau,
21
+ frequency,
22
+ angle,
23
+ frac_inc_con,
24
+ frac_inc_ani,
25
+ pressure,
26
+ scenario,
27
+ fcn,
28
+ ):
29
+ """Function to do all necessary checking of input type, dimension, reshaping etc. that clutter up the start of T-Matrix
30
+ NB: Setting scenario will override the settings for alpha, v and tau.
31
+
32
+ Parameters
33
+ ----------
34
+ k_min : np.ndarray
35
+ N length numpy array, mineral bulk modulus [Pa].
36
+ mu_min : np.ndarray
37
+ N length numpy array, mineral shear modulus [Pa].
38
+ rho_min : np.ndarray
39
+ N length numpy array, mineral density [kg/m^3].
40
+ k_fl : np.ndarray
41
+ N length numpy array, fluid bulk modulus [Pa].
42
+ rho_fl : np.ndarray
43
+ N length numpy array, mineral density [kg/m^3].
44
+ phi : np.ndarray or float
45
+ N length numpy array, total porosity [ratio].
46
+ perm : np.ndarray or float
47
+ float or N length numpy array, permeability [mD].
48
+ visco : np.ndarray or float
49
+ float or N length numpy array, fluid viscosity [cP].
50
+ alpha : np.ndarray
51
+ M or NxM length numpy array, inclusion aspect ratio [ratio].
52
+ v : np.ndarray
53
+ M or NxM length numpy array, inclusion concentration [ratio].
54
+ tau : np.ndarray
55
+ M length numpy array, relaxation time [s].
56
+ frequency : float
57
+ single float, signal frequency [Hz].
58
+ angle : float
59
+ single float, angle of symmetry plane [degree].
60
+ frac_inc_con : np.ndarray or float
61
+ single float or N length numpy array, fraction of connected inclusions [ratio].
62
+ frac_inc_ani : np.ndarray or float
63
+ single float or N length numpy array, fraction of anisotropic inclusions [ratio].
64
+ pressure : list or np.ndarray
65
+ > 1 value list or numpy array in ascending order, effective pressure [Pa].
66
+ scenario : int
67
+ pre-set scenarios for alpha, v and tau
68
+ fcn : callable
69
+ function with which to run the T-Matrix model.
70
+
71
+ Returns
72
+ -------
73
+ tuple
74
+ All inputs in correct dimension and data type plus ctrl_connected, ctrl_anisotropy - control parameters.
75
+ """
76
+
77
+ def _assert_type(arg, exp_dtype, err_str="check inputs, wrong type encountered"):
78
+ """Assert type.
79
+
80
+ Parameters
81
+ ----------
82
+ arg : any
83
+ To be asserted.
84
+ exp_dtype : type
85
+ Expected data type.
86
+ err_str : str, optional
87
+ Error string, by default 'check inputs, wrong type encountered'.
88
+
89
+ Raises
90
+ ------
91
+ ValueError
92
+ Content of err_str.
93
+ """
94
+ if not isinstance(arg, exp_dtype):
95
+ raise ValueError("t-matrix inputs: " + err_str)
96
+
97
+ # 1: Check all single float values, silently cast int to float
98
+ # Permeability and viscosity: Check that they are floats and convert them to to SI units
99
+ _assert_type(
100
+ perm, (float, int), "expect permeability given as single float in units mD"
101
+ )
102
+ perm = perm * 0.986923e-15
103
+
104
+ _assert_type(
105
+ visco, (float, int), "expect viscosity given as single float in units cP"
106
+ )
107
+ visco = visco * 1.0e-2
108
+
109
+ _assert_type(
110
+ frequency, (float, int), "expect frequency given as single float value in Hz"
111
+ )
112
+ frequency = float(frequency)
113
+
114
+ _assert_type(
115
+ angle, (float, int), "expect angle given as single float value in degrees"
116
+ )
117
+ angle = float(angle)
118
+
119
+ # 2: Determine the T-Matrix function, use the C++ implementation as default in case of None
120
+ # If it given as a string, it must belong to the t_matrix_models module
121
+ if not fcn: # None
122
+ t_matrix_fcn = t_matrix_models.t_matrix_porosity_c_alpha_v
123
+ elif not callable(fcn):
124
+ fcn_err_str = (
125
+ "T-Matrix function should be given as the callable function or a string "
126
+ "to the function name within t_matrix_models "
127
+ )
128
+ _assert_type(fcn, str, fcn_err_str)
129
+ if not hasattr(t_matrix_models, fcn):
130
+ raise ValueError(fcn_err_str)
131
+ t_matrix_fcn = getattr(t_matrix_models, fcn)
132
+
133
+ else: # Function must be recognised
134
+ if not fcn: # check that the function exists
135
+ raise ValueError(
136
+ "t-matrix inputs: function for T-Matrix model is not known"
137
+ )
138
+ t_matrix_fcn = fcn
139
+
140
+ # 3: Check all inputs that should be one value per sample, expand perm and visco to match this.
141
+ # frac_inc_ani and frac_inc_con can be single floats or vectors of the same length as the other vector inputs
142
+
143
+ log_length = len(phi)
144
+
145
+ # Check that the inputs that should have the same length actually do
146
+ # dim_check_vector may throw an error message, modify it to show origin
147
+ try:
148
+ (
149
+ k_min,
150
+ mu_min,
151
+ rho_min,
152
+ k_fl,
153
+ rho_fl,
154
+ phi,
155
+ perm,
156
+ visco,
157
+ frac_inc_con,
158
+ frac_inc_ani,
159
+ ) = gen_utilities.dim_check_vector(
160
+ (
161
+ k_min,
162
+ mu_min,
163
+ rho_min,
164
+ k_fl,
165
+ rho_fl,
166
+ phi,
167
+ perm,
168
+ visco,
169
+ frac_inc_con,
170
+ frac_inc_ani,
171
+ ),
172
+ force_type=np.dtype(float),
173
+ )
174
+ except ValueError:
175
+ raise ValueError("t-matrix inputs: {}".format(str(sys.exc_info())))
176
+
177
+ # 4: Scenario will override settings for alpha, v and tau
178
+ if scenario:
179
+ scenario = int(scenario)
180
+ if scenario == 1: # Mostly rounded pores
181
+ alpha = np.array([0.9, 0.1])
182
+ v = np.array([0.9, 0.1])
183
+ elif scenario == 2: # Dual porosity with little rounded pores
184
+ alpha = np.array([0.58, 0.027])
185
+ v = np.array([0.85, 0.15])
186
+ elif scenario == 3: # Mixed pores
187
+ alpha = np.array([0.9, 0.1, 0.01])
188
+ v = np.array([0.8, 0.19, 0.01])
189
+ elif scenario == 4: # Flat pores and cracks
190
+ alpha = np.array([0.9, 0.1, 0.01, 0.001])
191
+ v = np.array([0.689, 0.3, 0.01, 0.001])
192
+ tau = np.ones_like(alpha) * 1.0e-7
193
+
194
+ # 4a: Check alpha, v, tau
195
+ # alpha and v is either 1D vector with inclusion aspect ratios and proportions applying to all samples or 2D arrays
196
+ # where the first dimension must coincide with the log_length
197
+ # tau should be a 1D vector with length equal to the number of inclusions per sample
198
+ _assert_type(
199
+ alpha,
200
+ np.ndarray,
201
+ "alpha should be a 1D or 2D numpy array of matching size with v",
202
+ )
203
+ _assert_type(
204
+ v, np.ndarray, "v should be a 1D or 2D numpy array og matching size with alpha"
205
+ )
206
+ _assert_type(
207
+ tau,
208
+ (float, np.ndarray),
209
+ "tau should be a single float or 1D numpy array with length matching "
210
+ "the number of inclusions",
211
+ )
212
+
213
+ alpha_shape = alpha.shape
214
+ # First make sure that alpha and v have the same number of elements
215
+ try:
216
+ alpha, v = gen_utilities.dim_check_vector(
217
+ (alpha, v), force_type=np.dtype(float)
218
+ )
219
+ except ValueError:
220
+ raise ValueError("t-matrix inputs: {}".format(str(sys.exc_info())))
221
+ alpha = alpha.reshape(alpha_shape)
222
+ v = v.reshape(alpha_shape)
223
+ # If they are 2D arrays, the first dimension should match log_length
224
+ if alpha.ndim == 2:
225
+ if not (alpha_shape[0] == log_length or alpha_shape[0] == 1):
226
+ raise ValueError(
227
+ "t-matrix inputs: number of samples in alpha is not matching length of inputs"
228
+ )
229
+ if alpha_shape[0] == 1:
230
+ alpha = np.tile(alpha, (log_length, 1))
231
+ v = np.tile(v, (log_length, 1))
232
+
233
+ elif alpha.ndim == 1:
234
+ alpha = np.tile(alpha.reshape(1, alpha_shape[0]), (log_length, 1))
235
+ v = np.tile(v.reshape(1, alpha_shape[0]), (log_length, 1))
236
+ # Check that the number of elements in tau matches dim 1 of alpha
237
+ if isinstance(tau, float):
238
+ tau = np.ones(alpha_shape) * tau
239
+ else:
240
+ if not tau.ndim == 1 and tau.shape[0] == alpha.shape[1]:
241
+ raise ValueError(
242
+ "t-matrix inputs: number of elements in tau is not matching number of inclusions"
243
+ )
244
+
245
+ # 5: Check pressure
246
+ # Check that pressure either consists of at least two elements in ascending order or is None
247
+ # in the case there is no pressure modelling
248
+ if pressure is not None:
249
+ _assert_type(
250
+ pressure,
251
+ (list, np.ndarray),
252
+ "pressure should be a list or numpy array of at least two "
253
+ "elements in ascending order",
254
+ )
255
+ pressure = np.sort(np.array(pressure).flatten())
256
+ if not pressure.shape[0] > 1:
257
+ raise ValueError(
258
+ "t-matrix inputs: if pressure is given, it should contain two or more values"
259
+ )
260
+
261
+ # 6: Determine case for connected/isolated and isotropic/anisotropic inclusions
262
+ # Assume the most general case: mix of isotropic and anisotropic inclusions and connected and isolated inclusions
263
+ ctrl_anisotropy = 1
264
+ if np.all(frac_inc_ani == 0):
265
+ ctrl_anisotropy = 0 # All isotropic
266
+ angle = 0
267
+ elif np.all(frac_inc_ani == 1):
268
+ ctrl_anisotropy = 2 # All anisotropic
269
+
270
+ ctrl_connected = 1
271
+ # Create case based on amount of connected inclusions
272
+ if np.all(frac_inc_con == 0):
273
+ ctrl_connected = 0 # All isolated
274
+ elif np.all(frac_inc_con == 1):
275
+ ctrl_connected = 2 # All connected
276
+
277
+ return (
278
+ k_min,
279
+ mu_min,
280
+ rho_min,
281
+ k_fl,
282
+ rho_fl,
283
+ phi,
284
+ perm,
285
+ visco,
286
+ alpha,
287
+ v,
288
+ tau,
289
+ frequency,
290
+ angle,
291
+ frac_inc_con,
292
+ frac_inc_ani,
293
+ pressure,
294
+ t_matrix_fcn,
295
+ ctrl_connected,
296
+ ctrl_anisotropy,
297
+ )