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,235 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from rock_physics_open import sandstone_models
|
|
4
|
+
from rock_physics_open.equinor_utilities import gen_utilities, std_functions
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def friable_shaly_sand_sandy_shale_model(
|
|
8
|
+
k_sst,
|
|
9
|
+
mu_sst,
|
|
10
|
+
rho_sst,
|
|
11
|
+
k_mud,
|
|
12
|
+
mu_mud,
|
|
13
|
+
rho_mud,
|
|
14
|
+
k_fl_sst,
|
|
15
|
+
rho_fl_sst,
|
|
16
|
+
k_fl_mud,
|
|
17
|
+
rho_fl_mud,
|
|
18
|
+
phi,
|
|
19
|
+
p_eff_sst,
|
|
20
|
+
p_eff_mud,
|
|
21
|
+
shale_frac,
|
|
22
|
+
phi_c_sst,
|
|
23
|
+
phi_c_mud,
|
|
24
|
+
phi_intr_mud,
|
|
25
|
+
coord_num_func_sst,
|
|
26
|
+
n_sst,
|
|
27
|
+
coord_num_func_mud,
|
|
28
|
+
n_mud,
|
|
29
|
+
shear_red_sst,
|
|
30
|
+
shear_red_mud,
|
|
31
|
+
):
|
|
32
|
+
"""
|
|
33
|
+
Model for mixing of friable sand and friable shale.
|
|
34
|
+
|
|
35
|
+
It is no point to use this model to calculate the shale response only,
|
|
36
|
+
in that case Friable Model with shale parameters does the job.
|
|
37
|
+
|
|
38
|
+
The shale fluid should be brine.
|
|
39
|
+
|
|
40
|
+
Shale fraction shaleFrac is in the range 0 to 1. For shaleFrac = 0 we
|
|
41
|
+
have a pure sand end member with phi = phiC for sand. For shaleFrac = 1
|
|
42
|
+
we have pure shale with phi = intrinsic porosity. For shaleFrac < phiC
|
|
43
|
+
the model is on the shaly sand trend, for shaleFrac > phiC it is on the
|
|
44
|
+
sandy shale trend.
|
|
45
|
+
|
|
46
|
+
Parameters
|
|
47
|
+
----------
|
|
48
|
+
k_sst : np.ndarray
|
|
49
|
+
Sandstone bulk modulus [Pa].
|
|
50
|
+
mu_sst : np.ndarray
|
|
51
|
+
Sandstone shear modulus [Pa].
|
|
52
|
+
rho_sst : np.ndarray
|
|
53
|
+
Sandstone bulk density [kg/m^3].
|
|
54
|
+
k_mud : np.ndarray
|
|
55
|
+
Shale bulk modulus [Pa].
|
|
56
|
+
mu_mud : np.ndarray
|
|
57
|
+
Shale shear modulus [Pa].
|
|
58
|
+
rho_mud : np.ndarray
|
|
59
|
+
Shale bulk density [kg/m^3].
|
|
60
|
+
k_fl_sst : np.ndarray
|
|
61
|
+
Fluid bulk modulus for sandstone fluid [Pa].
|
|
62
|
+
rho_fl_sst : np.ndarray
|
|
63
|
+
Fluid bulk density for sandstone fluid [kg/m^3].
|
|
64
|
+
k_fl_mud : np.ndarray
|
|
65
|
+
Fluid bulk modulus for shale fluid [Pa].
|
|
66
|
+
rho_fl_mud : np.ndarray
|
|
67
|
+
Fluid bulk density for shale fluid[kg/m^3].
|
|
68
|
+
phi : np.ndarray
|
|
69
|
+
Total porosity [fraction].
|
|
70
|
+
p_eff_sst : np.ndarray
|
|
71
|
+
Effective pressure in sandstone [Pa].
|
|
72
|
+
p_eff_mud : np.ndarray
|
|
73
|
+
Effective pressure in mud [Pa].
|
|
74
|
+
shale_frac : np.ndarray
|
|
75
|
+
Shale fraction [fraction].
|
|
76
|
+
phi_c_sst : float
|
|
77
|
+
Critical porosity for sandstone [fraction].
|
|
78
|
+
phi_c_mud : float
|
|
79
|
+
Critical porosity for mud [fraction].
|
|
80
|
+
phi_intr_mud : float
|
|
81
|
+
Intrinsic shale porosity [fraction].
|
|
82
|
+
coord_num_func_sst : str
|
|
83
|
+
Indication if coordination number should be calculated from porosity or kept constant for sandstone.
|
|
84
|
+
coord_num_func_mud : str
|
|
85
|
+
Indication if coordination number should be calculated from porosity or kept constant for shale.
|
|
86
|
+
n_sst : float
|
|
87
|
+
Coordination number for sandstone [unitless].
|
|
88
|
+
n_mud : float
|
|
89
|
+
Coordination number for shale [unitless].
|
|
90
|
+
shear_red_sst : float
|
|
91
|
+
Shear reduction factor for sandstone [fraction].
|
|
92
|
+
shear_red_mud : float
|
|
93
|
+
Shear reduction factor for mud [fraction].
|
|
94
|
+
|
|
95
|
+
Returns
|
|
96
|
+
-------
|
|
97
|
+
tuple
|
|
98
|
+
vp, vs, rho, ai, vpvs : (np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray)
|
|
99
|
+
vp [m/s] and vs [m/s], bulk density [kg/m^3], ai [m/s x kg/m^3], vpvs [ratio] of saturated rock.
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
# Filter out values of phi that are above phi_c, assumed only to apply for the sandstone
|
|
103
|
+
(
|
|
104
|
+
idx_phi,
|
|
105
|
+
(
|
|
106
|
+
k_sst,
|
|
107
|
+
mu_sst,
|
|
108
|
+
rho_sst,
|
|
109
|
+
k_mud,
|
|
110
|
+
mu_mud,
|
|
111
|
+
rho_mud,
|
|
112
|
+
k_fl_sst,
|
|
113
|
+
rho_fl_sst,
|
|
114
|
+
k_fl_mud,
|
|
115
|
+
rho_fl_mud,
|
|
116
|
+
phi,
|
|
117
|
+
p_eff_sst,
|
|
118
|
+
p_eff_mud,
|
|
119
|
+
shale_frac,
|
|
120
|
+
_,
|
|
121
|
+
_,
|
|
122
|
+
),
|
|
123
|
+
) = gen_utilities.filter_input_log(
|
|
124
|
+
(
|
|
125
|
+
k_sst,
|
|
126
|
+
mu_sst,
|
|
127
|
+
rho_sst,
|
|
128
|
+
k_mud,
|
|
129
|
+
mu_mud,
|
|
130
|
+
rho_mud,
|
|
131
|
+
k_fl_sst,
|
|
132
|
+
rho_fl_sst,
|
|
133
|
+
k_fl_mud,
|
|
134
|
+
rho_fl_mud,
|
|
135
|
+
phi,
|
|
136
|
+
p_eff_sst,
|
|
137
|
+
p_eff_mud,
|
|
138
|
+
shale_frac,
|
|
139
|
+
phi_c_sst - phi,
|
|
140
|
+
phi - phi_intr_mud,
|
|
141
|
+
),
|
|
142
|
+
no_zero=False,
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
# Expand the needed variables from float to numpy array
|
|
146
|
+
phi, phi_intr_mud = gen_utilities.dim_check_vector((phi, phi_intr_mud))
|
|
147
|
+
|
|
148
|
+
sandy_shale_idx = shale_frac > phi
|
|
149
|
+
shaly_sand_idx = ~sandy_shale_idx
|
|
150
|
+
|
|
151
|
+
# Fraction of silt in silt - shale trend
|
|
152
|
+
frac_silt = (1 - shale_frac) / (1 - phi)
|
|
153
|
+
# Fraction of sand in sand - silt trend
|
|
154
|
+
frac_sand = 1 - shale_frac / phi
|
|
155
|
+
|
|
156
|
+
# Shale properties for intrinsic porosity point
|
|
157
|
+
vp_sat_mud, vs_sat_mud, rho_b_mud = sandstone_models.friable_model(
|
|
158
|
+
k_mud,
|
|
159
|
+
mu_mud,
|
|
160
|
+
rho_mud,
|
|
161
|
+
k_fl_mud,
|
|
162
|
+
rho_fl_mud,
|
|
163
|
+
phi_intr_mud,
|
|
164
|
+
p_eff_mud,
|
|
165
|
+
phi_c_mud,
|
|
166
|
+
coord_num_func_mud,
|
|
167
|
+
n_mud,
|
|
168
|
+
shear_red_mud,
|
|
169
|
+
)[0:3]
|
|
170
|
+
k_sat_mud, mu_sat_mud = std_functions.moduli(vp_sat_mud, vs_sat_mud, rho_b_mud)
|
|
171
|
+
|
|
172
|
+
# Silt end member
|
|
173
|
+
k_silt, mu_silt = std_functions.hashin_shtrikman_walpole(
|
|
174
|
+
k_sat_mud, mu_sat_mud, k_sst, mu_sst, phi_c_sst
|
|
175
|
+
)
|
|
176
|
+
rho_silt = rho_b_mud * phi + rho_sst * (1 - phi)
|
|
177
|
+
|
|
178
|
+
# Estimate the sand end member through the friable model with phi = phiC
|
|
179
|
+
vp_sat_sst, vs_sat_sst, rho_sat_sst = sandstone_models.friable_model(
|
|
180
|
+
k_sst,
|
|
181
|
+
mu_sst,
|
|
182
|
+
rho_sst,
|
|
183
|
+
k_fl_sst,
|
|
184
|
+
rho_fl_sst,
|
|
185
|
+
phi,
|
|
186
|
+
p_eff_sst,
|
|
187
|
+
phi_c_sst,
|
|
188
|
+
coord_num_func_sst,
|
|
189
|
+
n_sst,
|
|
190
|
+
shear_red_sst,
|
|
191
|
+
)[0:3]
|
|
192
|
+
k_sat_sst, mu_sat_sst = std_functions.moduli(vp_sat_sst, vs_sat_sst, rho_sat_sst)
|
|
193
|
+
|
|
194
|
+
k = np.ones(shale_frac.shape) * np.nan
|
|
195
|
+
mu = np.ones(shale_frac.shape) * np.nan
|
|
196
|
+
rho = np.ones(shale_frac.shape) * np.nan
|
|
197
|
+
|
|
198
|
+
# Points on sandy shale trend
|
|
199
|
+
k[sandy_shale_idx], mu[sandy_shale_idx] = std_functions.hashin_shtrikman_walpole(
|
|
200
|
+
k_silt[sandy_shale_idx],
|
|
201
|
+
mu_silt[sandy_shale_idx],
|
|
202
|
+
k_sat_mud[sandy_shale_idx],
|
|
203
|
+
mu_sat_mud[sandy_shale_idx],
|
|
204
|
+
frac_silt[sandy_shale_idx],
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
rho[sandy_shale_idx] = (
|
|
208
|
+
rho_b_mud[sandy_shale_idx] * (1 - frac_silt[sandy_shale_idx])
|
|
209
|
+
+ rho_silt[sandy_shale_idx] * frac_silt[sandy_shale_idx]
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
# Points on shaly sand trend
|
|
213
|
+
k[shaly_sand_idx], mu[shaly_sand_idx] = std_functions.hashin_shtrikman_walpole(
|
|
214
|
+
k_sat_sst[shaly_sand_idx],
|
|
215
|
+
mu_sat_sst[shaly_sand_idx],
|
|
216
|
+
k_silt[shaly_sand_idx],
|
|
217
|
+
mu_silt[shaly_sand_idx],
|
|
218
|
+
frac_sand[shaly_sand_idx],
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
rho[shaly_sand_idx] = (
|
|
222
|
+
(1 - phi[shaly_sand_idx]) * rho_sst[shaly_sand_idx]
|
|
223
|
+
+ phi[shaly_sand_idx] * rho_fl_sst[shaly_sand_idx]
|
|
224
|
+
) * frac_sand[shaly_sand_idx] + (1 - frac_sand[shaly_sand_idx]) * rho_silt[
|
|
225
|
+
shaly_sand_idx
|
|
226
|
+
]
|
|
227
|
+
|
|
228
|
+
vp, vs, ai, vpvs = std_functions.velocity(k, mu, rho)
|
|
229
|
+
|
|
230
|
+
# Restore original array length
|
|
231
|
+
vp, vs, rho, ai, vpvs = gen_utilities.filter_output(
|
|
232
|
+
idx_phi, (vp, vs, rho, ai, vpvs)
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
return vp, vs, rho, ai, vpvs
|
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
from warnings import warn
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from rock_physics_open.equinor_utilities import std_functions
|
|
6
|
+
|
|
7
|
+
from .constant_cement_models import constant_cement_model_dry
|
|
8
|
+
from .friable_models import friable_model_dry
|
|
9
|
+
from .patchy_cement_model import constant_cement_model_pcm
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def patchy_cement_pressure_fluid_substitution(
|
|
13
|
+
k_min,
|
|
14
|
+
mu_min,
|
|
15
|
+
rho_min,
|
|
16
|
+
k_cem,
|
|
17
|
+
mu_cem,
|
|
18
|
+
rho_cem,
|
|
19
|
+
k_fl_old,
|
|
20
|
+
rho_fl_old,
|
|
21
|
+
k_fl_new,
|
|
22
|
+
rho_fl_new,
|
|
23
|
+
phi,
|
|
24
|
+
p_eff_old,
|
|
25
|
+
p_eff_new,
|
|
26
|
+
vp_old,
|
|
27
|
+
vs_old,
|
|
28
|
+
rho_b_old,
|
|
29
|
+
p_eff_low,
|
|
30
|
+
frac_cem_up,
|
|
31
|
+
frac_cem,
|
|
32
|
+
shear_red,
|
|
33
|
+
phi_c,
|
|
34
|
+
coord_num_func,
|
|
35
|
+
n,
|
|
36
|
+
model_type="weight",
|
|
37
|
+
phi_below_zero="disregard",
|
|
38
|
+
phi_above_phi_c="snap",
|
|
39
|
+
k_sat_above_k_min="disregard",
|
|
40
|
+
above_upper_bound="snap",
|
|
41
|
+
below_lower_bound="disregard",
|
|
42
|
+
):
|
|
43
|
+
"""
|
|
44
|
+
Patchy cement model, developed by Per Avseth and Norunn Skjei. A sandstone model in which part of the
|
|
45
|
+
matrix is pressure sensitive, and part is cemented.
|
|
46
|
+
|
|
47
|
+
Control parameters with default value:
|
|
48
|
+
model_type = 'weight': A sample by sample weight between cemented (upper) and friable (lower) bound are calculated.
|
|
49
|
+
The alternative is 'cement_fraction', in which the weights are calculated from one constant cement model
|
|
50
|
+
|
|
51
|
+
phi_below_zero='disregard': Values with negative porosity will either have their value snapped to zero ('snap')
|
|
52
|
+
or the input value will be returned ('disregard'). These option should give the same
|
|
53
|
+
result.
|
|
54
|
+
|
|
55
|
+
phi_above_phi_c = 'disregard': Values with porosity above critical porosity will either have their values snapped
|
|
56
|
+
to critical porosity ('sbap') or the input value will be returned ('disregard').
|
|
57
|
+
|
|
58
|
+
k_sat_above_k_min='disregard': Values with saturated bulk modulus above the mineral bulk modulus will have their
|
|
59
|
+
value snapped to the mineral modulus ('snap') or the input value will be returned ('disregard').
|
|
60
|
+
|
|
61
|
+
above_upper_bound='snap': Values with moduli above upper bound will either be snapped to upper bound ('snap')
|
|
62
|
+
or the input value will be returned ('disregard').
|
|
63
|
+
|
|
64
|
+
below_lower_bound='disregard': Values with moduli below lower bound will either be snapped to lower bound ('snap')
|
|
65
|
+
or the input value returned ('disregard').
|
|
66
|
+
|
|
67
|
+
Comment
|
|
68
|
+
-------
|
|
69
|
+
Based on program by Norunn Skjei.
|
|
70
|
+
Translated to Python by Harald Flesche.
|
|
71
|
+
|
|
72
|
+
Parameters
|
|
73
|
+
----------
|
|
74
|
+
k_min : np.ndarray
|
|
75
|
+
Mineral bulk modulus [Pa].
|
|
76
|
+
mu_min : np.ndarray
|
|
77
|
+
Mineral shear modulus [Pa].
|
|
78
|
+
rho_min : np.ndarray
|
|
79
|
+
Mineral density [kg/m^3]
|
|
80
|
+
k_cem : np.ndarray
|
|
81
|
+
Sandstone cement bulk modulus [Pa].
|
|
82
|
+
mu_cem : np.ndarray
|
|
83
|
+
Sandstone cement shear modulus [Pa].
|
|
84
|
+
rho_cem : np.ndarray
|
|
85
|
+
Cement density [kg/m^3]
|
|
86
|
+
k_fl_old : np.ndarray
|
|
87
|
+
Initial fluid bulk modulus for sandstone fluid [Pa].
|
|
88
|
+
rho_fl_old : np.ndarray
|
|
89
|
+
Initial fluid bulk density for sandstone fluid [kg/m^3].
|
|
90
|
+
k_fl_new : np.ndarray
|
|
91
|
+
Substituted fluid bulk modulus for sandstone fluid [Pa].
|
|
92
|
+
rho_fl_new : np.ndarray
|
|
93
|
+
Substituted fluid bulk density for sandstone fluid [kg/m^3].
|
|
94
|
+
phi : np.ndarray
|
|
95
|
+
Total porosity [fraction].
|
|
96
|
+
p_eff_old : np.ndarray
|
|
97
|
+
Initial effective pressure [Pa].
|
|
98
|
+
p_eff_new : np.ndarray
|
|
99
|
+
Substituted effective pressure [Pa].
|
|
100
|
+
p_eff_low : float
|
|
101
|
+
Lower bound effective pressure [Pa].
|
|
102
|
+
frac_cem_up : float
|
|
103
|
+
Upper bound cement volume fraction [fraction].
|
|
104
|
+
frac_cem : cement fraction of constant cement model - representative for observed data. Must be lower than
|
|
105
|
+
frac_cem_up
|
|
106
|
+
shear_red : float
|
|
107
|
+
Shear reduction factor for sandstone [fraction].
|
|
108
|
+
phi_c : float
|
|
109
|
+
Critical porosity [fraction].
|
|
110
|
+
n : float
|
|
111
|
+
Coordination number [unitless].
|
|
112
|
+
coord_num_func : str
|
|
113
|
+
Indication if coordination number should be calculated from porosity or kept constant.
|
|
114
|
+
vp_old : np.ndarray
|
|
115
|
+
Initial p-wave velocity [m/s].
|
|
116
|
+
vs_old : np.ndarray
|
|
117
|
+
Initial s-wave velocity [m/s].
|
|
118
|
+
rho_b_old : np.ndarray
|
|
119
|
+
Initial bulk density [kg/m^3].
|
|
120
|
+
model_type : str
|
|
121
|
+
Version of model, either 'weight' or 'cement_fraction'
|
|
122
|
+
phi_below_zero : str
|
|
123
|
+
Control for handling of negative porosity samples.
|
|
124
|
+
phi_above_phi_c : str
|
|
125
|
+
Control for handling of porosity samples above critical porosity.
|
|
126
|
+
k_sat_above_k_min : str
|
|
127
|
+
Control for handling of bulk modulus samples above mineral bulk modulus.
|
|
128
|
+
above_upper_bound : str
|
|
129
|
+
Control for handling of samples above the upper bound.
|
|
130
|
+
below_lower_bound : str
|
|
131
|
+
Control for handling of samples below the lower bound.
|
|
132
|
+
|
|
133
|
+
Returns
|
|
134
|
+
-------
|
|
135
|
+
tuple
|
|
136
|
+
vp_new, vs_new, rho_b_new, ai_new, vpvs_new, k_sat_new, mu_new, wk, wmu, idx_valid :
|
|
137
|
+
(np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray).
|
|
138
|
+
vp_new :Saturated P-velocity [m/s] after fluid and pressure substitution,
|
|
139
|
+
vs_new : Saturated S-velocity [m/s] after fluid and pressure substitution,
|
|
140
|
+
rho_b_new : Saturated density [kg/m3] after fluid and pressure substitution,
|
|
141
|
+
ai_new : Saturated acoustic impedance [kg/m3 x m/s] after fluid and pressure substitution,
|
|
142
|
+
vpvs_new : Saturated Vp/Vs ratio [unitless] after fluid and pressure substitution,
|
|
143
|
+
k_sat_new : New saturated rock bulk modulus [Pa],
|
|
144
|
+
mu_new : New shear modulus [Pa],
|
|
145
|
+
wk, wmu : weights for k and mu between upper and lower bound,
|
|
146
|
+
idx_valid : samples fluid substitution is performed
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
# Original saturated bulk and shear modulus
|
|
150
|
+
k_sat_old, mu_old = std_functions.moduli(vp_old, vs_old, rho_b_old)
|
|
151
|
+
|
|
152
|
+
# Handling of samples that violate the assumptions of the Patchy Cement
|
|
153
|
+
# substitution:
|
|
154
|
+
# 1: phi <= 0
|
|
155
|
+
# 2: phi > phi_c
|
|
156
|
+
# 3: k_sat > k_min
|
|
157
|
+
idx1 = _handle_exceptions_part_1(
|
|
158
|
+
phi,
|
|
159
|
+
phi_c,
|
|
160
|
+
k_sat_old,
|
|
161
|
+
mu_old,
|
|
162
|
+
k_min,
|
|
163
|
+
mu_min,
|
|
164
|
+
phi_below_zero=phi_below_zero,
|
|
165
|
+
phi_above_phi_c=phi_above_phi_c,
|
|
166
|
+
k_sat_above_k_min=k_sat_above_k_min,
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
# k_dry for original pressure from Gassmann for valid samples
|
|
170
|
+
k_dry_old = np.ones_like(phi) * np.nan
|
|
171
|
+
k_dry_old[~idx1] = std_functions.gassmann_dry(
|
|
172
|
+
k_sat_old[~idx1], phi[~idx1], k_fl_old[~idx1], k_min[~idx1]
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
# For common handling of zero-porosity point: calculate effective
|
|
176
|
+
# properties using Hashin-Shtrikman
|
|
177
|
+
k_zero, mu_zero = std_functions.hashin_shtrikman_walpole(
|
|
178
|
+
k_cem, mu_cem, k_min, mu_min, frac_cem_up, bound="lower"
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
# Lower bound for estimation of weight W (input moduli in Pa, pressure in Pa)
|
|
182
|
+
k_low, mu_low = friable_model_dry(
|
|
183
|
+
k_zero,
|
|
184
|
+
mu_zero,
|
|
185
|
+
phi,
|
|
186
|
+
p_eff_low * np.ones_like(phi),
|
|
187
|
+
phi_c,
|
|
188
|
+
coord_num_func,
|
|
189
|
+
n,
|
|
190
|
+
shear_red,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
# Upper bounds for estimation of weight W
|
|
194
|
+
k_up, mu_up = constant_cement_model_dry(
|
|
195
|
+
k_min, mu_min, k_cem, mu_cem, phi, frac_cem_up, phi_c, n, shear_red
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
# Handling of samples that violate the assumptions of the Patchy Cement
|
|
199
|
+
# substitution:
|
|
200
|
+
# 4: Model violation in Gassmann (k_dry < 0.0), friable model or constant cement
|
|
201
|
+
# model
|
|
202
|
+
# 5: k_dry, mu below lower bound
|
|
203
|
+
# 6: k_dry, mu above upper bound
|
|
204
|
+
|
|
205
|
+
idx2 = _handle_exceptions_part_2(
|
|
206
|
+
k_dry_old,
|
|
207
|
+
mu_old,
|
|
208
|
+
k_up,
|
|
209
|
+
mu_up,
|
|
210
|
+
k_low,
|
|
211
|
+
mu_low,
|
|
212
|
+
idx1,
|
|
213
|
+
above_upper_bound=above_upper_bound,
|
|
214
|
+
below_lower_bound=below_lower_bound,
|
|
215
|
+
)
|
|
216
|
+
idx_valid = np.logical_not(idx2)
|
|
217
|
+
|
|
218
|
+
# Pressure sensitive model for initial pressure
|
|
219
|
+
k_dry_p_init, mu_p_init = friable_model_dry(
|
|
220
|
+
k_zero, mu_zero, phi, p_eff_old, phi_c, coord_num_func, n, shear_red
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
# Pressure sensitive model for final pressure
|
|
224
|
+
k_dry_p_final, mu_p_final = friable_model_dry(
|
|
225
|
+
k_zero, mu_zero, phi, p_eff_new, phi_c, coord_num_func, n, shear_red
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
# Weights - either on a sample basis or by a representative constant cement model
|
|
229
|
+
if model_type == "weight":
|
|
230
|
+
w_k = _calculate_weight(k_dry_old, k_low, k_up)
|
|
231
|
+
w_mu = _calculate_weight(mu_old, mu_low, mu_up)
|
|
232
|
+
else:
|
|
233
|
+
k_cc, mu_cc = constant_cement_model_pcm(
|
|
234
|
+
k_min,
|
|
235
|
+
mu_min,
|
|
236
|
+
k_cem,
|
|
237
|
+
mu_cem,
|
|
238
|
+
k_zero,
|
|
239
|
+
mu_zero,
|
|
240
|
+
phi,
|
|
241
|
+
frac_cem,
|
|
242
|
+
phi_c,
|
|
243
|
+
n,
|
|
244
|
+
shear_red,
|
|
245
|
+
)[0:2]
|
|
246
|
+
w_k = _calculate_weight(k_cc, k_low, k_up)
|
|
247
|
+
w_mu = _calculate_weight(mu_cc, mu_low, mu_up)
|
|
248
|
+
|
|
249
|
+
w_cem = 0.5 * (w_mu + w_k)
|
|
250
|
+
k_mod_dry = np.nan * np.ones_like(phi)
|
|
251
|
+
k_mod = np.nan * np.ones_like(phi)
|
|
252
|
+
mu_mod = np.nan * np.ones_like(phi)
|
|
253
|
+
rho_mod = np.nan * np.ones_like(phi)
|
|
254
|
+
|
|
255
|
+
# Calculate modelled values - first for the valid samples
|
|
256
|
+
k_mod_dry[idx_valid] = k_dry_p_init[idx_valid] + w_k[idx_valid] * (
|
|
257
|
+
k_up[idx_valid] - k_low[idx_valid]
|
|
258
|
+
)
|
|
259
|
+
k_mod[idx_valid] = std_functions.gassmann(
|
|
260
|
+
k_mod_dry[idx_valid], phi[idx_valid], k_fl_old[idx_valid], k_min[idx_valid]
|
|
261
|
+
)
|
|
262
|
+
mu_mod[idx_valid] = mu_p_init[idx_valid] + w_mu[idx_valid] * (
|
|
263
|
+
mu_up[idx_valid] - mu_low[idx_valid]
|
|
264
|
+
)
|
|
265
|
+
rho_mod[idx_valid] = (
|
|
266
|
+
phi[idx_valid] * rho_fl_old[idx_valid]
|
|
267
|
+
+ (1.0 - phi[idx_valid] - w_cem[idx_valid] * frac_cem_up) * rho_min[idx_valid]
|
|
268
|
+
+ w_cem[idx_valid] * frac_cem_up * rho_cem[idx_valid]
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
# Fill in input values for invalid samples
|
|
272
|
+
k_mod[idx2] = k_sat_old[idx2]
|
|
273
|
+
mu_mod[idx2] = mu_old[idx2]
|
|
274
|
+
rho_mod[idx2] = rho_b_old[idx2]
|
|
275
|
+
vp_mod, vs_mod = std_functions.velocity(k_mod, mu_mod, rho_mod)[0:2]
|
|
276
|
+
|
|
277
|
+
# Calculate residuals. For invalid samples, the residuals will be set to zero
|
|
278
|
+
vp_res = vp_old - vp_mod
|
|
279
|
+
vs_res = vs_old - vs_mod
|
|
280
|
+
rho_res = rho_b_old - rho_mod
|
|
281
|
+
|
|
282
|
+
# Estimate dry moduli values according to initial dry values, changed
|
|
283
|
+
# pressure and estimated pressure sensitivity
|
|
284
|
+
k_dry_new = (
|
|
285
|
+
k_dry_old
|
|
286
|
+
* (k_dry_p_final + w_k * (k_up - k_dry_p_final))
|
|
287
|
+
/ (k_dry_p_init + w_k * (k_up - k_dry_p_init))
|
|
288
|
+
)
|
|
289
|
+
mu_new = (
|
|
290
|
+
mu_old
|
|
291
|
+
* (mu_p_final + w_mu * (mu_up - mu_p_final))
|
|
292
|
+
/ (mu_p_init + w_mu * (mu_up - mu_p_init))
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
# New k_sat for new pressure from Gassmann
|
|
296
|
+
k_sat_new = np.ones_like(phi) * np.nan
|
|
297
|
+
if np.any(idx_valid):
|
|
298
|
+
k_sat_new[idx_valid] = std_functions.gassmann(
|
|
299
|
+
k_dry_new[idx_valid], phi[idx_valid], k_fl_new[idx_valid], k_min[idx_valid]
|
|
300
|
+
)
|
|
301
|
+
k_sat_new[idx2] = k_sat_old[idx2]
|
|
302
|
+
mu_new[idx2] = mu_old[idx2]
|
|
303
|
+
|
|
304
|
+
# New saturated density
|
|
305
|
+
rho_b_new = np.ones_like(phi) * np.nan
|
|
306
|
+
rho_b_new[idx_valid] = rho_b_old[idx_valid] + phi[idx_valid] * (
|
|
307
|
+
rho_fl_new[idx_valid] - rho_fl_old[idx_valid]
|
|
308
|
+
)
|
|
309
|
+
rho_b_new[idx2] = rho_b_old[idx2]
|
|
310
|
+
|
|
311
|
+
# New saturated velocities and derived values
|
|
312
|
+
vp_new, vs_new = std_functions.velocity(k_sat_new, mu_new, rho_b_new)[0:2]
|
|
313
|
+
ai_new = vp_new * rho_b_new
|
|
314
|
+
vpvs_new = vp_new / vs_new
|
|
315
|
+
|
|
316
|
+
return (
|
|
317
|
+
vp_new,
|
|
318
|
+
vs_new,
|
|
319
|
+
rho_b_new,
|
|
320
|
+
ai_new,
|
|
321
|
+
vpvs_new,
|
|
322
|
+
w_k,
|
|
323
|
+
w_mu,
|
|
324
|
+
idx_valid,
|
|
325
|
+
vp_res,
|
|
326
|
+
vs_res,
|
|
327
|
+
rho_res,
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def _handle_exceptions_part_1(
|
|
332
|
+
phi_vec: np.ndarray,
|
|
333
|
+
phi_c_const: float,
|
|
334
|
+
k_sat: np.ndarray,
|
|
335
|
+
mu: np.ndarray,
|
|
336
|
+
k_min: np.ndarray,
|
|
337
|
+
mu_min: np.ndarray,
|
|
338
|
+
phi_below_zero: str = "disregard",
|
|
339
|
+
phi_above_phi_c: str = "snap",
|
|
340
|
+
k_sat_above_k_min: str = "disregard",
|
|
341
|
+
) -> np.ndarray:
|
|
342
|
+
# Handling of samples that violate assumptions of the Patchy Cement substitution:
|
|
343
|
+
# 1: phi < 0
|
|
344
|
+
# 2: phi > phi_c
|
|
345
|
+
# 3: k_sat > k_min, mu > mu_min
|
|
346
|
+
|
|
347
|
+
# Handling of case 1:
|
|
348
|
+
idx1 = phi_vec < 0.0
|
|
349
|
+
if phi_below_zero == "snap":
|
|
350
|
+
phi_vec[idx1] = 0.0
|
|
351
|
+
idx1 = np.zeros(phi_vec.shape).astype(bool)
|
|
352
|
+
elif phi_below_zero == "disregard":
|
|
353
|
+
pass
|
|
354
|
+
else:
|
|
355
|
+
raise ValueError('unknown argument for parameter "phi_below_zero"')
|
|
356
|
+
|
|
357
|
+
# Handling of case 2:
|
|
358
|
+
idx2 = phi_vec > phi_c_const
|
|
359
|
+
if phi_above_phi_c == "snap":
|
|
360
|
+
phi_vec[idx2] = phi_c_const
|
|
361
|
+
idx2 = np.zeros(phi_vec.shape).astype(bool)
|
|
362
|
+
elif phi_above_phi_c == "disregard":
|
|
363
|
+
pass
|
|
364
|
+
else:
|
|
365
|
+
raise ValueError('unknown argument for parameter "phi_above_phi_c"')
|
|
366
|
+
|
|
367
|
+
# Handling of case 3:
|
|
368
|
+
idx3 = np.logical_or(k_sat > k_min, mu > mu_min)
|
|
369
|
+
if k_sat_above_k_min == "snap":
|
|
370
|
+
k_min[idx3] = k_sat[idx3]
|
|
371
|
+
mu_min[idx3] = mu[idx3]
|
|
372
|
+
idx3 = np.zeros(k_sat.shape).astype(bool)
|
|
373
|
+
elif k_sat_above_k_min == "disregard":
|
|
374
|
+
pass
|
|
375
|
+
else:
|
|
376
|
+
raise ValueError('unknown argument for parameter "k_sat_above_k_min"')
|
|
377
|
+
return np.any(np.vstack((idx1, idx2, idx3)), axis=0)
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
def _handle_exceptions_part_2(
|
|
381
|
+
k_dry: np.ndarray,
|
|
382
|
+
mu: np.ndarray,
|
|
383
|
+
k_up: np.ndarray,
|
|
384
|
+
mu_up: np.ndarray,
|
|
385
|
+
k_low: np.ndarray,
|
|
386
|
+
mu_low: np.ndarray,
|
|
387
|
+
idx: np.ndarray,
|
|
388
|
+
above_upper_bound: str = "snap",
|
|
389
|
+
below_lower_bound: str = "disregard",
|
|
390
|
+
) -> np.ndarray:
|
|
391
|
+
# Handling of samples that violate the assumptions of the Patchy Cement
|
|
392
|
+
# substitution:
|
|
393
|
+
# 4: Model violation in Gassmann (k_dry < 0.0), friable model or constant cement
|
|
394
|
+
# model
|
|
395
|
+
# 5: k_dry, mu below lower bound
|
|
396
|
+
# 6: k_dry, mu above upper bound
|
|
397
|
+
|
|
398
|
+
# Identification of case 4 and calculation of dry rock properties:
|
|
399
|
+
# gassmann_dry returns dry property < 0 as NaN
|
|
400
|
+
idx_nan = np.isnan(k_dry)
|
|
401
|
+
|
|
402
|
+
# Can be non-physical cases in friable model
|
|
403
|
+
idx_nan = np.logical_or(idx_nan, np.isnan(k_low))
|
|
404
|
+
|
|
405
|
+
# Can be non-physical cases in constant cement model
|
|
406
|
+
idx_nan = np.logical_or(idx_nan, np.isnan(k_up))
|
|
407
|
+
|
|
408
|
+
# Handling of case 5:
|
|
409
|
+
idx5k = np.zeros_like(k_dry).astype(bool)
|
|
410
|
+
idx5mu = np.zeros_like(k_dry).astype(bool)
|
|
411
|
+
np.less(k_dry, k_low, out=idx5k, where=~idx_nan)
|
|
412
|
+
np.less(mu, mu_low, out=idx5mu, where=~idx_nan)
|
|
413
|
+
if below_lower_bound == "snap":
|
|
414
|
+
k_dry[idx5k] = k_low[idx5k]
|
|
415
|
+
mu[idx5mu] = mu_low[idx5mu]
|
|
416
|
+
idx5 = np.zeros(k_dry.shape).astype(bool)
|
|
417
|
+
elif below_lower_bound == "disregard":
|
|
418
|
+
idx5 = np.logical_or(idx5k, idx5mu)
|
|
419
|
+
else:
|
|
420
|
+
raise ValueError('unknown argument for parameter "below_lower_bound"')
|
|
421
|
+
|
|
422
|
+
# Handling of case 6:
|
|
423
|
+
if above_upper_bound == "snap":
|
|
424
|
+
idx6k = np.zeros_like(k_dry).astype(bool)
|
|
425
|
+
idx6mu = np.zeros_like(k_dry).astype(bool)
|
|
426
|
+
np.greater(k_dry, k_up, out=idx6k, where=~idx_nan)
|
|
427
|
+
np.greater(mu, mu_up, out=idx6mu, where=~idx_nan)
|
|
428
|
+
k_dry[idx6k] = k_up[idx6k]
|
|
429
|
+
mu[idx6mu] = mu_up[idx6mu]
|
|
430
|
+
idx6 = np.zeros(k_dry.shape).astype(bool)
|
|
431
|
+
elif above_upper_bound == "disregard":
|
|
432
|
+
idx6 = np.logical_or(
|
|
433
|
+
np.greater(k_dry, k_up, where=~idx_nan),
|
|
434
|
+
np.greater(mu, mu_up, where=~idx_nan),
|
|
435
|
+
)
|
|
436
|
+
else:
|
|
437
|
+
raise ValueError('unknown argument for parameter "above_upper_bound"')
|
|
438
|
+
|
|
439
|
+
# Exception for all cases 1-6:
|
|
440
|
+
return np.any(np.vstack((idx, idx5, idx6, idx_nan)), axis=0)
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
def _calculate_weight(
|
|
444
|
+
dry_modulus: np.ndarray,
|
|
445
|
+
low_modulus: np.ndarray,
|
|
446
|
+
high_modulus: np.ndarray,
|
|
447
|
+
force_full_range: str = False,
|
|
448
|
+
) -> np.ndarray:
|
|
449
|
+
"""
|
|
450
|
+
Calculates a weight for a value between a lower and upper bound. Used for moduli
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
Parameters
|
|
454
|
+
----------
|
|
455
|
+
dry_modulus: value to be evaluated
|
|
456
|
+
low_modulus: lower bound
|
|
457
|
+
high_modulus: upper bound
|
|
458
|
+
force_full_range: do not clip weight to a range of [0.0, 1.0]
|
|
459
|
+
|
|
460
|
+
Returns
|
|
461
|
+
-------
|
|
462
|
+
weight: value between [0.0, 1.0]
|
|
463
|
+
"""
|
|
464
|
+
idx = np.abs(high_modulus - low_modulus) < 2.0 * np.finfo(float).eps
|
|
465
|
+
if np.any(idx):
|
|
466
|
+
warn(
|
|
467
|
+
f"weight estimation: high and low bound is identical for "
|
|
468
|
+
f"{np.sum(high_modulus == low_modulus)} samples"
|
|
469
|
+
)
|
|
470
|
+
weight = np.ones_like(dry_modulus)
|
|
471
|
+
weight[~idx] = (dry_modulus[~idx] - low_modulus[~idx]) / (
|
|
472
|
+
high_modulus[~idx] - low_modulus[~idx]
|
|
473
|
+
)
|
|
474
|
+
# Catch cases outside the allowed range
|
|
475
|
+
if not force_full_range:
|
|
476
|
+
weight = np.clip(weight, 0.0, 1.0)
|
|
477
|
+
return weight
|