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.
- rock_physics_open/__init__.py +0 -0
- rock_physics_open/equinor_utilities/__init__.py +0 -0
- rock_physics_open/equinor_utilities/anisotropy.py +211 -0
- rock_physics_open/equinor_utilities/classification_functions/__init__.py +17 -0
- rock_physics_open/equinor_utilities/classification_functions/class_stats.py +68 -0
- rock_physics_open/equinor_utilities/classification_functions/lin_class.py +53 -0
- rock_physics_open/equinor_utilities/classification_functions/mahal_class.py +63 -0
- rock_physics_open/equinor_utilities/classification_functions/norm_class.py +73 -0
- rock_physics_open/equinor_utilities/classification_functions/poly_class.py +45 -0
- rock_physics_open/equinor_utilities/classification_functions/post_prob.py +27 -0
- rock_physics_open/equinor_utilities/classification_functions/two_step_classification.py +60 -0
- rock_physics_open/equinor_utilities/conversions.py +10 -0
- rock_physics_open/equinor_utilities/gen_utilities/__init__.py +11 -0
- rock_physics_open/equinor_utilities/gen_utilities/dict_to_float.py +38 -0
- rock_physics_open/equinor_utilities/gen_utilities/dim_check_vector.py +113 -0
- rock_physics_open/equinor_utilities/gen_utilities/filter_input.py +131 -0
- rock_physics_open/equinor_utilities/gen_utilities/filter_output.py +88 -0
- rock_physics_open/equinor_utilities/machine_learning_utilities/__init__.py +15 -0
- rock_physics_open/equinor_utilities/machine_learning_utilities/base_pressure_model.py +170 -0
- rock_physics_open/equinor_utilities/machine_learning_utilities/dummy_vars.py +53 -0
- rock_physics_open/equinor_utilities/machine_learning_utilities/exponential_model.py +137 -0
- rock_physics_open/equinor_utilities/machine_learning_utilities/import_ml_models.py +77 -0
- rock_physics_open/equinor_utilities/machine_learning_utilities/polynomial_model.py +132 -0
- rock_physics_open/equinor_utilities/machine_learning_utilities/run_regression.py +209 -0
- rock_physics_open/equinor_utilities/machine_learning_utilities/sigmoidal_model.py +241 -0
- rock_physics_open/equinor_utilities/optimisation_utilities/__init__.py +19 -0
- rock_physics_open/equinor_utilities/optimisation_utilities/opt_subst_utilities.py +455 -0
- rock_physics_open/equinor_utilities/snapshot_test_utilities/__init__.py +10 -0
- rock_physics_open/equinor_utilities/snapshot_test_utilities/compare_snapshots.py +184 -0
- rock_physics_open/equinor_utilities/snapshot_test_utilities/snapshots.py +97 -0
- rock_physics_open/equinor_utilities/std_functions/__init__.py +43 -0
- rock_physics_open/equinor_utilities/std_functions/backus_ave.py +68 -0
- rock_physics_open/equinor_utilities/std_functions/dvorkin_nur.py +77 -0
- rock_physics_open/equinor_utilities/std_functions/gassmann.py +165 -0
- rock_physics_open/equinor_utilities/std_functions/hashin_shtrikman.py +224 -0
- rock_physics_open/equinor_utilities/std_functions/hertz_mindlin.py +51 -0
- rock_physics_open/equinor_utilities/std_functions/moduli_velocity.py +67 -0
- rock_physics_open/equinor_utilities/std_functions/reflection_eq.py +120 -0
- rock_physics_open/equinor_utilities/std_functions/rho.py +69 -0
- rock_physics_open/equinor_utilities/std_functions/voigt_reuss_hill.py +149 -0
- rock_physics_open/equinor_utilities/std_functions/walton.py +45 -0
- rock_physics_open/equinor_utilities/std_functions/wood_brie.py +94 -0
- rock_physics_open/equinor_utilities/various_utilities/Equinor_logo.gif +0 -0
- rock_physics_open/equinor_utilities/various_utilities/Equinor_logo.ico +0 -0
- rock_physics_open/equinor_utilities/various_utilities/__init__.py +24 -0
- rock_physics_open/equinor_utilities/various_utilities/display_result_statistics.py +90 -0
- rock_physics_open/equinor_utilities/various_utilities/gassmann_dry_mod.py +56 -0
- rock_physics_open/equinor_utilities/various_utilities/gassmann_mod.py +56 -0
- rock_physics_open/equinor_utilities/various_utilities/gassmann_sub_mod.py +64 -0
- rock_physics_open/equinor_utilities/various_utilities/hs_average.py +59 -0
- rock_physics_open/equinor_utilities/various_utilities/pressure.py +96 -0
- rock_physics_open/equinor_utilities/various_utilities/reflectivity.py +101 -0
- rock_physics_open/equinor_utilities/various_utilities/timeshift.py +104 -0
- rock_physics_open/equinor_utilities/various_utilities/vp_vs_rho_set_statistics.py +170 -0
- rock_physics_open/equinor_utilities/various_utilities/vrh_3_min.py +83 -0
- rock_physics_open/fluid_models/__init__.py +9 -0
- rock_physics_open/fluid_models/brine_model/__init__.py +5 -0
- rock_physics_open/fluid_models/brine_model/brine_properties.py +178 -0
- rock_physics_open/fluid_models/gas_model/__init__.py +5 -0
- rock_physics_open/fluid_models/gas_model/gas_properties.py +319 -0
- rock_physics_open/fluid_models/oil_model/__init__.py +5 -0
- rock_physics_open/fluid_models/oil_model/dead_oil_density.py +65 -0
- rock_physics_open/fluid_models/oil_model/dead_oil_velocity.py +30 -0
- rock_physics_open/fluid_models/oil_model/live_oil_density.py +82 -0
- rock_physics_open/fluid_models/oil_model/live_oil_velocity.py +24 -0
- rock_physics_open/fluid_models/oil_model/oil_bubble_point.py +69 -0
- rock_physics_open/fluid_models/oil_model/oil_properties.py +146 -0
- rock_physics_open/sandstone_models/__init__.py +59 -0
- rock_physics_open/sandstone_models/cemented_shalysand_sandyshale_models.py +304 -0
- rock_physics_open/sandstone_models/constant_cement_models.py +204 -0
- rock_physics_open/sandstone_models/constant_cement_optimisation.py +125 -0
- rock_physics_open/sandstone_models/contact_cement_model.py +138 -0
- rock_physics_open/sandstone_models/curvefit_sandstone_models.py +143 -0
- rock_physics_open/sandstone_models/friable_models.py +177 -0
- rock_physics_open/sandstone_models/friable_optimisation.py +115 -0
- rock_physics_open/sandstone_models/friable_shalysand_sandyshale_models.py +235 -0
- rock_physics_open/sandstone_models/patchy_cement_fluid_substitution_model.py +477 -0
- rock_physics_open/sandstone_models/patchy_cement_model.py +384 -0
- rock_physics_open/sandstone_models/patchy_cement_optimisation.py +254 -0
- rock_physics_open/sandstone_models/unresolved_cemented_sandshale_models.py +134 -0
- rock_physics_open/sandstone_models/unresolved_friable_sandshale_models.py +126 -0
- rock_physics_open/shale_models/__init__.py +19 -0
- rock_physics_open/shale_models/dem.py +174 -0
- rock_physics_open/shale_models/dem_dual_por.py +61 -0
- rock_physics_open/shale_models/kus_tok.py +59 -0
- rock_physics_open/shale_models/multi_sca.py +133 -0
- rock_physics_open/shale_models/pq.py +102 -0
- rock_physics_open/shale_models/sca.py +90 -0
- rock_physics_open/shale_models/shale4_mineral.py +147 -0
- rock_physics_open/shale_models/shale4_mineral_dem_overlay.py +92 -0
- rock_physics_open/span_wagner/__init__.py +5 -0
- rock_physics_open/span_wagner/co2_properties.py +444 -0
- rock_physics_open/span_wagner/coefficients.py +165 -0
- rock_physics_open/span_wagner/equations.py +104 -0
- rock_physics_open/span_wagner/tables/__init__.py +0 -0
- rock_physics_open/span_wagner/tables/carbon_dioxide_density.npz +0 -0
- rock_physics_open/span_wagner/tables/lookup_table.py +33 -0
- rock_physics_open/t_matrix_models/Equinor_logo.ico +0 -0
- rock_physics_open/t_matrix_models/__init__.py +35 -0
- rock_physics_open/t_matrix_models/carbonate_pressure_substitution.py +124 -0
- rock_physics_open/t_matrix_models/curvefit_t_matrix_exp.py +123 -0
- rock_physics_open/t_matrix_models/curvefit_t_matrix_min.py +86 -0
- rock_physics_open/t_matrix_models/parse_t_matrix_inputs.py +297 -0
- rock_physics_open/t_matrix_models/run_t_matrix.py +243 -0
- rock_physics_open/t_matrix_models/t_matrix_C.py +210 -0
- rock_physics_open/t_matrix_models/t_matrix_opt_fluid_sub_exp.py +137 -0
- rock_physics_open/t_matrix_models/t_matrix_opt_fluid_sub_petec.py +167 -0
- rock_physics_open/t_matrix_models/t_matrix_opt_forward_model_exp.py +76 -0
- rock_physics_open/t_matrix_models/t_matrix_opt_forward_model_min.py +89 -0
- rock_physics_open/t_matrix_models/t_matrix_parameter_optimisation_exp.py +176 -0
- rock_physics_open/t_matrix_models/t_matrix_parameter_optimisation_min.py +162 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/__init__.py +12 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/array_functions.py +75 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/calc_c_eff.py +163 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/calc_isolated.py +95 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/calc_kd.py +40 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/calc_kd_eff.py +116 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/calc_kd_uuv.py +18 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/calc_pressure.py +140 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/calc_t.py +71 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/calc_td.py +42 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/calc_theta.py +43 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/calc_x.py +33 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/calc_z.py +50 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/check_and_tile.py +43 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/g_tensor.py +140 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/iso_av.py +60 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/iso_ave_all.py +55 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/pressure_input.py +44 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/t_matrix_vec.py +278 -0
- rock_physics_open/t_matrix_models/t_matrix_vector/velocity_vti_angles.py +81 -0
- rock_physics_open/t_matrix_models/tmatrix_python.dll +0 -0
- rock_physics_open/t_matrix_models/tmatrix_python.so +0 -0
- rock_physics_open/ternary_plots/__init__.py +3 -0
- rock_physics_open/ternary_plots/gen_ternary_plot.py +73 -0
- rock_physics_open/ternary_plots/shale_prop_ternary.py +337 -0
- rock_physics_open/ternary_plots/ternary_patches.py +277 -0
- rock_physics_open/ternary_plots/ternary_plot_utilities.py +197 -0
- rock_physics_open/ternary_plots/unconventionals_ternary.py +75 -0
- rock_physics_open/version.py +34 -0
- rock_physics_open-0.3.2.dist-info/METADATA +90 -0
- rock_physics_open-0.3.2.dist-info/RECORD +145 -0
- rock_physics_open-0.3.2.dist-info/WHEEL +5 -0
- rock_physics_open-0.3.2.dist-info/licenses/LICENSE +165 -0
- 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
|