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,176 @@
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
+ opt_param_info,
7
+ save_opt_params,
8
+ )
9
+
10
+ from .curvefit_t_matrix_exp import curvefit_t_matrix_exp
11
+ from .t_matrix_parameter_optimisation_min import DEF_VP_VS_RATIO
12
+
13
+
14
+ def t_matrix_optimisation_exp(
15
+ k_fl: np.ndarray,
16
+ rho_fl: np.ndarray,
17
+ por: np.ndarray,
18
+ vsh: np.ndarray,
19
+ vp: np.ndarray,
20
+ vs: np.ndarray,
21
+ rhob: np.ndarray,
22
+ angle: float = 0.0,
23
+ k_r: float = 50.0,
24
+ eta_f: float = 1.0,
25
+ tau: float = 1.0e-7,
26
+ freq: float = 1.0e3,
27
+ file_out_str: str = "opt_params_exp.pkl",
28
+ display_results: bool = False,
29
+ well_name: str = "Unknown well",
30
+ **opt_kwargs,
31
+ ):
32
+ """T-Matrix optimisation adapted to an exploration setting, where detailed well information is generally not known.
33
+ Inclusion parameters are optimised for the whole well.
34
+
35
+ Parameters
36
+ ----------
37
+ por :
38
+ Inclusion porosity [ratio].
39
+ vsh :
40
+ Shale volume [ratio].
41
+ k_fl :
42
+ Fluid bulk modulus [Pa].
43
+ rho_fl :
44
+ Fluid density [kg/m^3].
45
+ vp :
46
+ Compressional velocity log [m/s].
47
+ vs :
48
+ Shear velocity log [m/s].
49
+ rhob :
50
+ Bulk density log [kg/m^3].
51
+ angle : float
52
+ Angle of symmetry plane [degrees]
53
+ k_r :
54
+ Permeability [mD].
55
+ eta_f :
56
+ Fluid viscosity [cP].
57
+ tau :
58
+ Relaxation time constant [s].
59
+ freq :
60
+ Signal frequency [Hz].
61
+ file_out_str :
62
+ Output file name (string) to store optimal parameters (pickle format).
63
+ display_results :
64
+ D isplay optimal parameters in a window after run.
65
+ well_name :
66
+ Name of well to be displayed in info box title.
67
+ opt_kwargs :
68
+ Additional keywords to be passed to optimisation function
69
+
70
+ Returns
71
+ -------
72
+ tuple
73
+ vp_mod, vs_mod - modelled logs, vp_res, vs_res - residual logs.
74
+ """
75
+ # 1. Preparation that is independent of search for minimum possible aspect ratio for second inclusion set
76
+
77
+ # Optimisation function for selected parameters
78
+ opt_fun = curvefit_t_matrix_exp
79
+ # rho_min = (rhob - por * rho_fl) / (1 - por)
80
+ # EXP adapted inputs: include fluid data and other params in x_data
81
+ # expand single value parameters to match logs length
82
+ por, angle, k_r, eta_f, tau, freq, def_vpvs = gen_utilities.dim_check_vector(
83
+ (por, angle, k_r, eta_f, tau, freq, DEF_VP_VS_RATIO)
84
+ )
85
+ x_data = np.stack(
86
+ (por, vsh, k_fl, rho_fl, angle, k_r, eta_f, tau, freq, def_vpvs), axis=1
87
+ )
88
+ # Set weight to vs to give vp and vs similar influence on optimisation
89
+ y_data = np.stack([vp, vs * DEF_VP_VS_RATIO], axis=1)
90
+
91
+ # 2. Search for minimum aspect ratio of inclusion set no. 2, given that inclusion set no. 1 will at least represent
92
+ # 50% of inclusions. Minimum aspect ratio is linked to the porosity, and the most conservative estimate is to use
93
+ # the maximum value. This is likely to deteriorate the optimisation results, so a search for a more appropriate
94
+ # value that still produces valid results is made
95
+ percentiles = [50, 75, 80, 85, 90, 95, 99, 100]
96
+ valid_result = False
97
+ vel_mod = None
98
+ vel_res = None
99
+ opt_params = None
100
+ scale_val = opt_param_info()[1]
101
+ while not valid_result and percentiles:
102
+ try:
103
+ # Make sure that parameters are not in conflict with T Matrix assumptions
104
+ min_v1 = 0.5
105
+ max_por = np.percentile(por, percentiles[0])
106
+ min_a2 = (1.0 - min_v1) * max_por
107
+ # Test with all parameters in the range 0.0 - 1.0
108
+ # Params: f_ani f_con a1 a2 v1 k_carb mu_carb rho_carb k_sh mu_sh rho_sh
109
+ lower_bound = np.array(
110
+ [
111
+ 0.0,
112
+ 0.0,
113
+ 0.5,
114
+ min_a2,
115
+ min_v1, # f_ani f_con a1 a2 v1
116
+ 35.0 / scale_val["k_carb"],
117
+ 30.0 / scale_val["mu_carb"],
118
+ 2650.0 / scale_val["rho_carb"], # k_carb, mu_carb, rho_carb
119
+ 15.0 / scale_val["k_sh"],
120
+ 7.0 / scale_val["mu_sh"],
121
+ 2500.0 / scale_val["rho_sh"],
122
+ ],
123
+ dtype=float,
124
+ ) # k_sh, mu_sh, rho_sh
125
+ upper_bound = np.array(
126
+ [
127
+ 1.0,
128
+ 1.0,
129
+ 1.0,
130
+ 0.30,
131
+ 1.0, # f_ani f_con a1 a2 v1
132
+ 1.0,
133
+ 1.0,
134
+ 1.0, # k_carb, mu_carb, rho_carb
135
+ 1.0,
136
+ 1.0,
137
+ 1.0,
138
+ ],
139
+ dtype=float,
140
+ ) # k_sh, mu_sh, rho_sh
141
+ x0 = (upper_bound + lower_bound) / 2.0
142
+ # Optimisation step without fluid substitution
143
+ vel_mod, vel_res, opt_params = gen_opt_routine(
144
+ opt_fun, x_data, y_data, x0, lower_bound, upper_bound, **opt_kwargs
145
+ )
146
+ valid_result = True
147
+ except ValueError:
148
+ percentiles.pop(0)
149
+ valid_result = False
150
+
151
+ if not valid_result:
152
+ raise ValueError(
153
+ f"{__file__}: unable to find stable value for T Matrix optimisation, second inclusion"
154
+ )
155
+
156
+ # Reshape outputs and remove weight from vs
157
+ vp_mod, vs_mod = [arr.flatten() for arr in np.split(vel_mod, 2, axis=1)]
158
+ vp_res, vs_res = [arr.flatten() for arr in np.split(vel_res, 2, axis=1)]
159
+ vs_mod = vs_mod / DEF_VP_VS_RATIO
160
+ vs_res = vs_res / DEF_VP_VS_RATIO
161
+ vpvs_mod = vp_mod / vs_mod
162
+ # Calculate the modelled density
163
+ rhob_mod = (
164
+ (1.0 - vsh) * opt_params[7] * scale_val["rho_carb"]
165
+ + vsh * opt_params[10] * scale_val["rho_sh"]
166
+ ) * (1.0 - por) + por * rho_fl
167
+ ai_mod = vp_mod * rhob_mod
168
+ rhob_res = rhob_mod - rhob
169
+ # Save the optimal parameters
170
+ save_opt_params("exp", opt_params, file_out_str, well_name=well_name)
171
+ if display_results:
172
+ from .opt_subst_utilities import opt_param_to_ascii
173
+
174
+ opt_param_to_ascii(file_out_str, well_name=well_name)
175
+
176
+ return vp_mod, vs_mod, rhob_mod, ai_mod, vpvs_mod, vp_res, vs_res, rhob_res
@@ -0,0 +1,162 @@
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_t_matrix_min import curve_fit_2_inclusion_sets
10
+
11
+ # Trade-off between calcite, dolomite and quartz, vs is weighted by this in order to make it count as much as vp
12
+ # in the optimisation
13
+ DEF_VP_VS_RATIO = 1.8
14
+
15
+
16
+ def t_matrix_optimisation_petec(
17
+ k_min: np.ndarray,
18
+ mu_min: np.ndarray,
19
+ rho_min: np.ndarray,
20
+ k_fl: np.ndarray,
21
+ rho_fl: np.ndarray,
22
+ por: np.ndarray,
23
+ vp: np.ndarray,
24
+ vs: np.ndarray,
25
+ rhob: np.ndarray,
26
+ angle: float = 0.0,
27
+ k_r: float = 50.0,
28
+ eta_f: float = 1.0,
29
+ tau: float = 1.0e-7,
30
+ freq: float = 1.0e3,
31
+ file_out_str: str = "opt_params_min.pkl",
32
+ display_results: bool = False,
33
+ well_name: str = "Unknown well",
34
+ **opt_kwargs,
35
+ ):
36
+ """T-Matrix optimisation adapted to a case with detailed information available, such as in a development or production
37
+ setting. Mineral and fluid composition should be known on a sample basis. Inclusion parameters are regarded as
38
+ unknown and they are optimised for.
39
+
40
+ Parameters
41
+ ----------
42
+ k_min :
43
+ Effective mineral bulk modulus [Pa].
44
+ mu_min :
45
+ Effective mineral shear modulus [Pa].
46
+ rho_min :
47
+ Effective mineral bulk density [kg/m^3].
48
+ k_fl :
49
+ Effective fluid bulk modulud [Pa].
50
+ rho_fl :
51
+ Effective fluid density [kg/m^3].
52
+ por :
53
+ Inclusion porosity [ratio].
54
+ vp :
55
+ Compressional velocity log [m/s].
56
+ vs :
57
+ Shear velocity log [m/s].
58
+ rhob :
59
+ Bulk density log [kg/m^3].
60
+ angle : float
61
+ Angle of symmetry plane [degrees]
62
+ k_r :
63
+ Permeability [mD].
64
+ eta_f :
65
+ Fluid viscosity [cP].
66
+ tau :
67
+ Relaxation time constant [s].
68
+ freq :
69
+ Signal frequency [Hz].
70
+ file_out_str :
71
+ Output file name (string) to store optimal parameters (pickle format).
72
+ display_results :
73
+ Display optimal parameters in a window after run.
74
+ well_name:
75
+ Name of well to be displayed in info box title.
76
+ opt_kwargs:
77
+ Additional keywords to be passed to optimisation function
78
+
79
+ Returns
80
+ -------
81
+ tuple
82
+ vp_mod, vs_mod, rho_mod, ai_mod, vpvs_mod - modelled logs, vp_res, vs_res, rho_res - residual logs.
83
+ """
84
+ # 1. Preparation that is independent of search for minimum possible aspect ratio for second inclusion set
85
+
86
+ # Optimisation function for selected parameters, with effective mineral properties known and 2 inclusion sets
87
+ opt_fun = curve_fit_2_inclusion_sets
88
+ rhob_mod = rho_min * (1 - por) + rho_fl * por
89
+ rhob_res = rhob - rhob_mod
90
+ # PETEC adapted inputs: include fluid data and other params in x_data
91
+ por, angle, k_r, eta_f, tau, freq, def_vp_vs_ratio = gen_utilities.dim_check_vector(
92
+ (por, angle, k_r, eta_f, tau, freq, DEF_VP_VS_RATIO)
93
+ )
94
+ x_data = np.stack(
95
+ (
96
+ por,
97
+ k_min,
98
+ mu_min,
99
+ rho_min,
100
+ k_fl,
101
+ rho_fl,
102
+ angle,
103
+ k_r,
104
+ eta_f,
105
+ tau,
106
+ freq,
107
+ def_vp_vs_ratio,
108
+ ),
109
+ axis=1,
110
+ )
111
+ # Set weight to vs to give vp and vs similar influence on optimisation
112
+ y_data = np.stack([vp, vs * DEF_VP_VS_RATIO], axis=1)
113
+
114
+ # 2. Search for minimum aspect ratio of inclusion set no. 2, given that inclusion set no. 1 will at least represent
115
+ # 50% of inclusions. Minimum aspect ratio is linked to the porosity, and the most conservative estimate is to use
116
+ # the maximum value. This is likely to deteriorate the optimisation results, so a search for a more appropriate
117
+ # value that still produces valid results is made
118
+ percentiles = [50, 75, 80, 85, 90, 95, 99, 100]
119
+ valid_result = False
120
+ vel_mod = None
121
+ vel_res = None
122
+ opt_params = None
123
+ while not valid_result and percentiles:
124
+ try:
125
+ # Make sure that parameters are not in conflict with T Matrix assumptions
126
+ min_v1 = 0.5
127
+ max_por = np.percentile(por, percentiles[0])
128
+ min_a2 = (1.0 - min_v1) * max_por
129
+ # Test with all parameters in the range 0.0 - 1.0 for best optimiser performance
130
+ # Params: f_ani f_con a1 a2 v1
131
+ lower_bound = np.array([0.0, 0.0, 0.5, min_a2, min_v1], dtype=float)
132
+ upper_bound = np.array([1.0, 1.0, 1.0, 0.30, 1.0], dtype=float)
133
+ x0 = (upper_bound + lower_bound) / 2.0
134
+ # Optimisation step without fluid substitution
135
+ vel_mod, vel_res, opt_params = gen_opt_routine(
136
+ opt_fun, x_data, y_data, x0, lower_bound, upper_bound, **opt_kwargs
137
+ )
138
+ valid_result = True
139
+ except ValueError:
140
+ percentiles.pop(0)
141
+ valid_result = False
142
+
143
+ if not valid_result:
144
+ raise ValueError(
145
+ f"{__file__}: unable to find stable value for T Matrix optimisation, second inclusion"
146
+ )
147
+
148
+ # Reshape outputs and remove weight from vs
149
+ vp_mod, vs_mod = [arr.flatten() for arr in np.split(vel_mod, 2, axis=1)]
150
+ ai_mod = vp_mod * rhob_mod
151
+ vp_res, vs_res = [arr.flatten() for arr in np.split(vel_res, 2, axis=1)]
152
+ vs_mod = vs_mod / DEF_VP_VS_RATIO
153
+ vs_res = vs_res / DEF_VP_VS_RATIO
154
+ vpvs_mod = vp_mod / vs_mod
155
+ # Save the optimal parameters
156
+ save_opt_params("min", opt_params, file_out_str, well_name=well_name)
157
+ if display_results:
158
+ from .opt_subst_utilities import opt_param_to_ascii
159
+
160
+ opt_param_to_ascii(file_out_str, well_name=well_name)
161
+
162
+ return vp_mod, vs_mod, rhob_mod, ai_mod, vpvs_mod, vp_res, vs_res, rhob_res
@@ -0,0 +1,12 @@
1
+ from .array_functions import array_inverse, array_matrix_mult
2
+ from .calc_pressure import calc_pressure_vec
3
+ from .pressure_input import pressure_input_utility
4
+ from .t_matrix_vec import t_matrix_porosity_vectorised
5
+
6
+ __all__ = [
7
+ "array_inverse",
8
+ "array_matrix_mult",
9
+ "calc_pressure_vec",
10
+ "pressure_input_utility",
11
+ "t_matrix_porosity_vectorised",
12
+ ]
@@ -0,0 +1,75 @@
1
+ import numpy as np
2
+
3
+
4
+ def array_inverse(a: np.ndarray) -> np.ndarray:
5
+ """Inverse of higher order array (3 dim) using linalg inv routine.
6
+
7
+ Parameters
8
+ ----------
9
+ a : np.ndarray
10
+ An nxmxm numpy array.
11
+
12
+ Returns
13
+ -------
14
+ np.ndarray
15
+ An nxmxm array where [i, :, :] contains the inverse of A[i, :, :].
16
+
17
+ Raises
18
+ ------
19
+ ValueError
20
+ If input of wrong shape.
21
+ """
22
+ if not (a.ndim == 3 and a.shape[1] == a.shape[2]):
23
+ raise ValueError(f"{__name__}: mismatch in inputs variables dimension/shape")
24
+
25
+ return np.array([np.linalg.inv(x) for x in a])
26
+
27
+
28
+ def array_matrix_mult(*args: np.ndarray) -> np.ndarray:
29
+ """3-dim arrays are matrix multiplied args[j][i, :, :] @ args[j+1][i, :, :].
30
+ Input args should all be numpy arrays of shape nxmxm.
31
+
32
+ Returns
33
+ -------
34
+ np.ndarray
35
+ An nxmxm array with n args[i] @ args[i+1] @ ....
36
+
37
+ Raises
38
+ ------
39
+ ValueError
40
+ If input is not a list or tuple.
41
+ ValueError
42
+ If mismatch in input shape/dimension.
43
+ ValueError
44
+ If mismatch in input shape/dimension.
45
+ """
46
+ if not isinstance(args, (list, tuple)):
47
+ raise ValueError(f"{__name__}: inputs must be list or tuple")
48
+ if not len(args) > 1:
49
+ return args[0]
50
+
51
+ arg_shape = []
52
+ arg_type = []
53
+ for i in range(len(args)):
54
+ if not (
55
+ isinstance(args[i], np.ndarray)
56
+ and args[i].ndim == 3
57
+ and args[i].shape[1] == args[i].shape[2]
58
+ ):
59
+ raise ValueError(
60
+ f"{__name__}: mismatch in inputs variables dimension/shape"
61
+ )
62
+ arg_shape.append(args[i].shape)
63
+ arg_type.append(args[i].dtype)
64
+ arg_shape = np.array(arg_shape)
65
+ arg_type = np.array(arg_type)
66
+ if not np.all(arg_shape[:, 0] == arg_shape[0, 0]):
67
+ raise ValueError(f"{__name__}: mismatch in inputs variables dimension/shape")
68
+ out_type = "complex128" if np.any(arg_type == np.dtype("complex128")) else "float64"
69
+
70
+ x = args[0]
71
+
72
+ for i in range(1, len(args)):
73
+ x = np.einsum("...ij,...jk->...ik", x, args[i], dtype=out_type)
74
+
75
+ return x
@@ -0,0 +1,163 @@
1
+ import numpy as np
2
+
3
+ from .array_functions import array_inverse, array_matrix_mult
4
+ from .calc_t import calc_t_vec
5
+ from .calc_theta import calc_theta_vec
6
+ from .calc_z import calc_z_vec
7
+
8
+
9
+ def calc_c_eff_vec(c0, c1, gd, t, t_bar, v, frac_aniso):
10
+ """
11
+ Equation 4 (page 222) Jakobsen et al. 2003 (The acoustic signature of fluid flow in complex
12
+ porous media).
13
+ Returns the effective stiffness tensor C* (nx6x6 matrix) calculated from the t-matrices t(r) (Eq. 1).
14
+
15
+ Parameters
16
+ ----------
17
+ c0 : np.ndarray
18
+ Stiffness tensor of the host of the inclusion (nx6x6 matrix).
19
+ c1 : np.ndarray
20
+ Sum of the concentration and t-matrices (nx6x6 matrix).
21
+ gd : np.ndarray
22
+ Correlation function (nx6x6 matrix).
23
+ t : np.ndarray
24
+ t-matrices of the different inclusions (nx6x6xr matrix) (anisotropic).
25
+ t_bar: np.ndarray
26
+ t-matrices of the different inclusions (nx6x6xr matrix) (isotropic).
27
+ v : np.ndarray
28
+ Concentration of the inclusions (nxr vector).
29
+ frac_aniso: np.ndarray
30
+ Fraction of anisotropic.
31
+
32
+ Returns
33
+ -------
34
+ tuple
35
+ c_eff: np.ndarray.
36
+ c_eff: effective stiffness tensor C.
37
+ """
38
+ if not (
39
+ c0.ndim == 3
40
+ and c1.ndim == 3
41
+ and gd.ndim == 3
42
+ and t.ndim == 4
43
+ and t_bar.ndim == 4
44
+ and v.ndim == 2
45
+ and np.all(
46
+ np.array(
47
+ [
48
+ c0.shape[1:2],
49
+ c1.shape[1:2],
50
+ gd.shape[1:2],
51
+ t.shape[1:2],
52
+ t_bar.shape[1:2],
53
+ ]
54
+ )
55
+ == c0.shape[1]
56
+ )
57
+ and np.all(
58
+ np.array(
59
+ [
60
+ c0.shape[0],
61
+ c1.shape[0],
62
+ gd.shape[0],
63
+ t.shape[0],
64
+ t_bar.shape[0],
65
+ v.shape[0],
66
+ ]
67
+ )
68
+ == c0.shape[0]
69
+ )
70
+ ):
71
+ raise ValueError("calc_c_eff_vec: inconsistencies in input shapes")
72
+
73
+ log_length = c0.shape[0]
74
+ alpha_len = v.shape[1]
75
+ v = v.reshape((log_length, 1, 1, alpha_len))
76
+ i4 = np.eye(6)
77
+
78
+ c1 = c1 + np.sum(frac_aniso * v * t + (1.0 - frac_aniso) * v * t_bar, axis=3)
79
+
80
+ return c0 + array_matrix_mult(c1, array_inverse(i4 + array_matrix_mult(gd, c1)))
81
+
82
+
83
+ def calc_c_eff_visco_vec(
84
+ vs,
85
+ k_r,
86
+ eta_f,
87
+ v,
88
+ gamma,
89
+ tau,
90
+ kd_uuvv,
91
+ kappa,
92
+ kappa_f,
93
+ c0,
94
+ s0,
95
+ c1,
96
+ td,
97
+ td_bar,
98
+ x,
99
+ x_bar,
100
+ gd,
101
+ frequency,
102
+ frac_ani,
103
+ ):
104
+ """
105
+ Returns the effective stiffness tensor C* for a visco-elastic system (6x6xnumber of frequencies).
106
+
107
+ Parameters
108
+ ----------
109
+ vs : np.ndarray
110
+ The velocity used to calculate the wave number.
111
+ k_r : np.ndarray
112
+ Klinkenberg permability.
113
+ eta_f : np.ndarray
114
+ Viscosity (P).
115
+ v : np.ndarray
116
+ Concentration of the inclusions which are connected with respect to fluid flow.
117
+ gamma : np.ndarray
118
+ Gamma factor for each inclusion (1x(number of connected inclusions) vector).
119
+ tau : float or np.ndarray
120
+ Relaxation time constant.
121
+ kd_uuvv : np.ndarray
122
+ Kd_uuvv for each connected inclusion (1x(number of connected inclusions) vector.
123
+ kappa : np.ndarray
124
+ Bulk modulus of host material.
125
+ kappa_f : np.ndarray
126
+ Bulk modulus of the fluid.
127
+ c0 : np.ndarray
128
+ The stiffness tensor of host material (6x6 matrix).
129
+ s0 : np.ndarray
130
+ Inverse of C0.
131
+ c1 : np.ndarray
132
+ First order correction matrix(6x6 matrix). If there are isolated inclusions, C1 is sum of concentration and
133
+ t-matrices of the isolated part of the porosity.
134
+ td : np.ndarray
135
+ t-matrix tensors.
136
+ td_bar : np.ndarray
137
+ t-matrices of the connected inclusions(6x6x(numbers of inclusions) matrix).
138
+ x : np.ndarray
139
+ X-tensor.
140
+ x_bar : np.ndarray
141
+ X-tensor of the connected inclusions (6x6x(numbers of inclusions) matrix).
142
+ gd : np.ndarray
143
+ Correlation function (6x6 matrix).
144
+ frequency : float
145
+ Frequency under consideration.
146
+ frac_ani : np.ndarray
147
+ Fraction of anisotropic inclusions.
148
+
149
+ Returns
150
+ -------
151
+ np.ndarray
152
+ Effective stiffness tensor.
153
+ """
154
+ dr = k_r / eta_f
155
+
156
+ omega = 2 * np.pi * frequency
157
+ k = omega / vs
158
+ theta = calc_theta_vec(v, omega, gamma, tau, kd_uuvv, dr, k, kappa, kappa_f)
159
+ z, z_bar = calc_z_vec(s0, td, td_bar, omega, gamma, v * frac_ani, tau)
160
+ t = calc_t_vec(td, theta, x, z, omega, gamma, tau, kappa_f)
161
+ t_bar = calc_t_vec(td_bar, theta, x_bar, z_bar, omega, gamma, tau, kappa_f)
162
+
163
+ return calc_c_eff_vec(c0, c1, gd, t, t_bar, v, frac_ani)
@@ -0,0 +1,95 @@
1
+ import numpy as np
2
+
3
+ from .array_functions import array_inverse, array_matrix_mult
4
+ from .g_tensor import g_tensor_vec
5
+ from .iso_av import iso_av_vec
6
+
7
+
8
+ def calc_isolated_part_vec(c0, s_0, kappa_f, alpha, v, case_iso, frac_ani):
9
+ """
10
+ Returns the first order correction tensor: sum of the concentrations and
11
+ t-matrices of the isolated porosity (6x6 matrix).
12
+ case_iso = 0 : 100% isotropic,
13
+ case_iso = 1 : mixed isotropic and anisotropic porosity,
14
+ case_iso = 2 : 100% anisotropic porosity.
15
+
16
+ Parameters
17
+ ----------
18
+ c0 : np.ndarray
19
+ Stiffness tensor of the host material (6x6xn).
20
+ s_0 : np.ndarray
21
+ Inverse of stiffness tensor.
22
+ kappa_f : np.ndarray
23
+ Bulk modulus of the fluid (n length vector).
24
+ alpha : np.ndarray
25
+ Aspect ratios of all the inclusions (1xnumber of inclusions) vector).
26
+ v : np.ndarray
27
+ Concentration of all the inclusions (1xnumber of inclusions) vector).
28
+ case_iso : int
29
+ Control parameter.
30
+ frac_ani : float
31
+ Fraction of anisotropic inclusions.
32
+
33
+ Returns
34
+ -------
35
+ np.ndarray
36
+ c1: correction tensor.
37
+
38
+ Notes
39
+ -----
40
+ 29.10.2020 HFLE: Simplification: alpha for isotropic and anisotropic part are the same. This has been default in
41
+ Remy's code, but this function had assumption that half of the inclusions could have different aspect ratio
42
+ 13.11.2020 HFLE: In case of zero porosity, this routine returns a zero tensor, whereas the correct should have
43
+ been to return the host material tensor - corrected.
44
+
45
+ """
46
+ if not (c0.ndim == 3 and s_0.ndim == 3):
47
+ raise ValueError(f"{__name__}: mismatch in inputs variables dimension/shape")
48
+
49
+ log_length = c0.shape[0]
50
+ if v.ndim != 2:
51
+ v = np.tile(v.reshape(1, v.shape[0]), (log_length, 1))
52
+
53
+ if alpha.ndim == 1 and alpha.shape[0] != c0.shape[0]:
54
+ alpha = np.tile(alpha.reshape(1, alpha.shape[0]), (log_length, 1))
55
+ alpha_len = alpha.shape[1]
56
+
57
+ cn = np.zeros_like(c0)
58
+ cn[:, 0:3, 0:3] = np.tile(kappa_f.reshape((log_length, 1, 1)), (1, 3, 3))
59
+ cn_d = cn - c0
60
+ i4 = np.tile(np.eye(6).reshape(1, 6, 6), (log_length, 1, 1))
61
+ c1 = np.zeros_like(c0)
62
+
63
+ # Will need G tensor for each alpha
64
+ g_arr = []
65
+ for i in range(alpha_len):
66
+ g_arr.append(g_tensor_vec(c0, s_0, alpha[:, i]))
67
+
68
+ if case_iso != 1:
69
+ # if there is only isotropic or anisotropic inclusions
70
+ for j in range(alpha_len):
71
+ t = array_matrix_mult(
72
+ cn_d, array_inverse(i4 - array_matrix_mult(g_arr[j], cn_d))
73
+ )
74
+ if case_iso != 2:
75
+ t = iso_av_vec(t)
76
+ c1 = c1 + v[:, j].reshape(log_length, 1, 1) * t
77
+ else:
78
+ # Isotropic and anisotropic part
79
+ for j in range(alpha_len):
80
+ t = array_matrix_mult(
81
+ cn_d, array_inverse(i4 - array_matrix_mult(g_arr[j], cn_d))
82
+ )
83
+ t = iso_av_vec(t)
84
+ c1 = c1 + ((1 - frac_ani) * v[:, j]).reshape(log_length, 1, 1) * t
85
+ for j in range(alpha_len):
86
+ t = array_matrix_mult(
87
+ cn_d, array_inverse(i4 - array_matrix_mult(g_arr[j], cn_d))
88
+ )
89
+ c1 = c1 + (frac_ani * v[:, j]).reshape(log_length, 1, 1) * t
90
+
91
+ idx_zero = np.sum(v, axis=1) == 0.0
92
+ if np.any(idx_zero):
93
+ c1[idx_zero] = c0[idx_zero]
94
+
95
+ return c1