rock-physics-open 0.2.3__py3-none-any.whl → 0.3.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rock-physics-open might be problematic. Click here for more details.
- rock_physics_open/equinor_utilities/gen_utilities/dict_to_float.py +6 -1
- rock_physics_open/equinor_utilities/gen_utilities/dim_check_vector.py +35 -5
- rock_physics_open/equinor_utilities/gen_utilities/filter_input.py +11 -6
- rock_physics_open/equinor_utilities/gen_utilities/filter_output.py +29 -19
- rock_physics_open/equinor_utilities/machine_learning_utilities/__init__.py +6 -5
- rock_physics_open/equinor_utilities/machine_learning_utilities/base_pressure_model.py +172 -0
- rock_physics_open/equinor_utilities/machine_learning_utilities/exponential_model.py +100 -86
- rock_physics_open/equinor_utilities/machine_learning_utilities/import_ml_models.py +7 -4
- rock_physics_open/equinor_utilities/machine_learning_utilities/polynomial_model.py +128 -0
- rock_physics_open/equinor_utilities/machine_learning_utilities/run_regression.py +6 -4
- rock_physics_open/equinor_utilities/machine_learning_utilities/sigmoidal_model.py +204 -155
- rock_physics_open/equinor_utilities/optimisation_utilities/__init__.py +19 -0
- rock_physics_open/equinor_utilities/snapshot_test_utilities/compare_snapshots.py +1 -2
- rock_physics_open/equinor_utilities/std_functions/backus_ave.py +16 -1
- rock_physics_open/equinor_utilities/std_functions/dvorkin_nur.py +10 -2
- rock_physics_open/equinor_utilities/std_functions/gassmann.py +32 -7
- rock_physics_open/equinor_utilities/std_functions/hashin_shtrikman.py +36 -7
- rock_physics_open/equinor_utilities/std_functions/hertz_mindlin.py +9 -1
- rock_physics_open/equinor_utilities/std_functions/moduli_velocity.py +22 -6
- rock_physics_open/equinor_utilities/std_functions/reflection_eq.py +28 -6
- rock_physics_open/equinor_utilities/std_functions/rho.py +12 -2
- rock_physics_open/equinor_utilities/std_functions/voigt_reuss_hill.py +25 -4
- rock_physics_open/equinor_utilities/std_functions/walton.py +8 -1
- rock_physics_open/equinor_utilities/std_functions/wood_brie.py +20 -3
- rock_physics_open/equinor_utilities/various_utilities/display_result_statistics.py +16 -9
- rock_physics_open/equinor_utilities/various_utilities/gassmann_dry_mod.py +21 -2
- rock_physics_open/equinor_utilities/various_utilities/gassmann_mod.py +21 -2
- rock_physics_open/equinor_utilities/various_utilities/gassmann_sub_mod.py +23 -12
- rock_physics_open/equinor_utilities/various_utilities/hs_average.py +20 -1
- rock_physics_open/equinor_utilities/various_utilities/pressure.py +9 -1
- rock_physics_open/equinor_utilities/various_utilities/reflectivity.py +26 -10
- rock_physics_open/equinor_utilities/various_utilities/timeshift.py +15 -2
- rock_physics_open/equinor_utilities/various_utilities/vp_vs_rho_set_statistics.py +40 -24
- rock_physics_open/equinor_utilities/various_utilities/vrh_3_min.py +24 -2
- rock_physics_open/fluid_models/brine_model/brine_properties.py +70 -35
- rock_physics_open/fluid_models/gas_model/gas_properties.py +79 -37
- rock_physics_open/fluid_models/oil_model/dead_oil_density.py +21 -16
- rock_physics_open/fluid_models/oil_model/dead_oil_velocity.py +9 -7
- rock_physics_open/fluid_models/oil_model/live_oil_density.py +16 -13
- rock_physics_open/fluid_models/oil_model/live_oil_velocity.py +3 -3
- rock_physics_open/fluid_models/oil_model/oil_properties.py +59 -29
- rock_physics_open/sandstone_models/__init__.py +2 -0
- rock_physics_open/sandstone_models/constant_cement_optimisation.py +4 -1
- rock_physics_open/sandstone_models/friable_models.py +6 -7
- rock_physics_open/sandstone_models/friable_optimisation.py +4 -1
- rock_physics_open/sandstone_models/patchy_cement_model.py +103 -5
- rock_physics_open/sandstone_models/patchy_cement_optimisation.py +4 -1
- rock_physics_open/t_matrix_models/__init__.py +0 -10
- rock_physics_open/t_matrix_models/carbonate_pressure_substitution.py +1 -1
- rock_physics_open/t_matrix_models/curvefit_t_matrix_exp.py +1 -2
- rock_physics_open/t_matrix_models/t_matrix_opt_fluid_sub_exp.py +3 -3
- rock_physics_open/t_matrix_models/t_matrix_opt_fluid_sub_petec.py +5 -1
- rock_physics_open/t_matrix_models/t_matrix_opt_forward_model_exp.py +5 -1
- rock_physics_open/t_matrix_models/t_matrix_opt_forward_model_min.py +4 -1
- rock_physics_open/t_matrix_models/t_matrix_parameter_optimisation_exp.py +5 -1
- rock_physics_open/t_matrix_models/t_matrix_parameter_optimisation_min.py +4 -1
- rock_physics_open/ternary_plots/ternary_plot_utilities.py +3 -3
- rock_physics_open/version.py +2 -2
- {rock_physics_open-0.2.3.dist-info → rock_physics_open-0.3.1.dist-info}/METADATA +4 -8
- {rock_physics_open-0.2.3.dist-info → rock_physics_open-0.3.1.dist-info}/RECORD +64 -61
- /rock_physics_open/{t_matrix_models → equinor_utilities/optimisation_utilities}/opt_subst_utilities.py +0 -0
- {rock_physics_open-0.2.3.dist-info → rock_physics_open-0.3.1.dist-info}/WHEEL +0 -0
- {rock_physics_open-0.2.3.dist-info → rock_physics_open-0.3.1.dist-info}/licenses/LICENSE +0 -0
- {rock_physics_open-0.2.3.dist-info → rock_physics_open-0.3.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import pickle
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
from .base_pressure_model import BasePressureModel
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class PolynomialPressureModel(BasePressureModel):
|
|
12
|
+
"""
|
|
13
|
+
Polynomial pressure sensitivity model for velocity prediction.
|
|
14
|
+
|
|
15
|
+
Uses polynomial function: v = v0 * P(p_depl) / P(p_in_situ)
|
|
16
|
+
where P(p) is a polynomial function with specified coefficients.
|
|
17
|
+
|
|
18
|
+
Input format (n,3): [velocity, p_eff_in_situ, p_eff_depleted]
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
weights: list[float],
|
|
24
|
+
model_max_pressure: float | None = None,
|
|
25
|
+
description: str = "",
|
|
26
|
+
):
|
|
27
|
+
"""
|
|
28
|
+
Initialize polynomial pressure model.
|
|
29
|
+
|
|
30
|
+
Parameters
|
|
31
|
+
----------
|
|
32
|
+
weights : list[float]
|
|
33
|
+
Polynomial coefficients [unitless]. First element is constant term,
|
|
34
|
+
second is linear coefficient, etc.
|
|
35
|
+
model_max_pressure : float | None
|
|
36
|
+
Maximum pressure for predict_max method [Pa].
|
|
37
|
+
description : str
|
|
38
|
+
Model description.
|
|
39
|
+
"""
|
|
40
|
+
super().__init__(model_max_pressure, description)
|
|
41
|
+
self._weights = weights
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def weights(self) -> list[float]:
|
|
45
|
+
"""Polynomial coefficients."""
|
|
46
|
+
return self._weights
|
|
47
|
+
|
|
48
|
+
def validate_input(self, inp_arr: np.ndarray) -> np.ndarray:
|
|
49
|
+
"""
|
|
50
|
+
Validate input for polynomial model.
|
|
51
|
+
|
|
52
|
+
Parameters
|
|
53
|
+
----------
|
|
54
|
+
inp_arr : np.ndarray
|
|
55
|
+
Input array to validate.
|
|
56
|
+
|
|
57
|
+
Returns
|
|
58
|
+
-------
|
|
59
|
+
np.ndarray
|
|
60
|
+
Validated input array.
|
|
61
|
+
|
|
62
|
+
Raises
|
|
63
|
+
------
|
|
64
|
+
ValueError
|
|
65
|
+
If input format is invalid.
|
|
66
|
+
"""
|
|
67
|
+
if not isinstance(inp_arr, np.ndarray):
|
|
68
|
+
raise ValueError("Input must be numpy ndarray.")
|
|
69
|
+
if inp_arr.ndim != 2 or inp_arr.shape[1] != 3:
|
|
70
|
+
raise ValueError(
|
|
71
|
+
"Input must be (n,3): [velocity, p_eff_in_situ, p_eff_depleted]"
|
|
72
|
+
)
|
|
73
|
+
return inp_arr
|
|
74
|
+
|
|
75
|
+
def predict_abs(self, inp_arr: np.ndarray, case: str = "in_situ") -> np.ndarray:
|
|
76
|
+
"""
|
|
77
|
+
Calculate absolute velocity for specified pressure case.
|
|
78
|
+
|
|
79
|
+
Parameters
|
|
80
|
+
----------
|
|
81
|
+
inp_arr : np.ndarray
|
|
82
|
+
Validated input array (n,3).
|
|
83
|
+
case : str
|
|
84
|
+
Pressure case: "in_situ" or "depleted".
|
|
85
|
+
|
|
86
|
+
Returns
|
|
87
|
+
-------
|
|
88
|
+
np.ndarray
|
|
89
|
+
Velocity values [m/s].
|
|
90
|
+
"""
|
|
91
|
+
arr = self.validate_input(inp_arr)
|
|
92
|
+
|
|
93
|
+
# Validate weights are set
|
|
94
|
+
if not self._weights:
|
|
95
|
+
raise ValueError('Field "weights" is not set.')
|
|
96
|
+
|
|
97
|
+
vel = arr[:, 0]
|
|
98
|
+
p_in_situ = arr[:, 1]
|
|
99
|
+
p_depleted = arr[:, 2]
|
|
100
|
+
|
|
101
|
+
# Create polynomial from weights
|
|
102
|
+
polynomial_expr = np.polynomial.Polynomial(self._weights)
|
|
103
|
+
|
|
104
|
+
# Select pressure based on case
|
|
105
|
+
p_eff = p_in_situ if case == "in_situ" else p_depleted
|
|
106
|
+
|
|
107
|
+
# Calculate velocity using polynomial pressure correction
|
|
108
|
+
return vel * polynomial_expr(p_eff) / polynomial_expr(p_in_situ)
|
|
109
|
+
|
|
110
|
+
def todict(self) -> dict[str, Any]:
|
|
111
|
+
"""Convert model to dictionary."""
|
|
112
|
+
return {
|
|
113
|
+
"weights": self._weights,
|
|
114
|
+
"model_max_pressure": self._model_max_pressure,
|
|
115
|
+
"description": self._description,
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
@classmethod
|
|
119
|
+
def load(cls, file: str | bytes) -> "PolynomialPressureModel":
|
|
120
|
+
"""Load polynomial model from pickle file."""
|
|
121
|
+
with open(file, "rb") as f_in:
|
|
122
|
+
d = pickle.load(f_in)
|
|
123
|
+
|
|
124
|
+
return cls(
|
|
125
|
+
weights=d["weights"],
|
|
126
|
+
model_max_pressure=d["model_max_pressure"],
|
|
127
|
+
description=d["description"],
|
|
128
|
+
)
|
|
@@ -108,7 +108,9 @@ def _perform_regression(
|
|
|
108
108
|
return res_frame
|
|
109
109
|
|
|
110
110
|
|
|
111
|
-
def run_regression(
|
|
111
|
+
def run_regression(
|
|
112
|
+
inp_df, first_model_file_name, second_model_file_name, model_dir=None
|
|
113
|
+
):
|
|
112
114
|
"""
|
|
113
115
|
Estimate Vp and Vs by neural network regression with multiple inputs.
|
|
114
116
|
|
|
@@ -116,9 +118,9 @@ def run_regression(inp_df, vp_model_file_name, vs_model_file_name, model_dir=Non
|
|
|
116
118
|
----------
|
|
117
119
|
inp_df : pd.DataFrame
|
|
118
120
|
Input logs required for the regression.
|
|
119
|
-
|
|
121
|
+
first_model_file_name : str
|
|
120
122
|
Full file name for vp model.
|
|
121
|
-
|
|
123
|
+
second_model_file_name : str
|
|
122
124
|
Full file name for vs model.
|
|
123
125
|
model_dir : str
|
|
124
126
|
Directory.
|
|
@@ -139,7 +141,7 @@ def run_regression(inp_df, vp_model_file_name, vs_model_file_name, model_dir=Non
|
|
|
139
141
|
category_var,
|
|
140
142
|
column_names,
|
|
141
143
|
column_units,
|
|
142
|
-
) = _read_models(
|
|
144
|
+
) = _read_models(first_model_file_name, second_model_file_name, model_dir=model_dir)
|
|
143
145
|
return _perform_regression(
|
|
144
146
|
inp_df,
|
|
145
147
|
column_names,
|
|
@@ -1,188 +1,237 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import pickle
|
|
2
|
-
from
|
|
3
|
-
from typing import Union
|
|
4
|
+
from typing import Any
|
|
4
5
|
|
|
5
6
|
import numpy as np
|
|
6
7
|
|
|
8
|
+
from .base_pressure_model import BasePressureModel
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class SigmoidalPressureModel(BasePressureModel):
|
|
12
|
+
"""
|
|
13
|
+
Sigmoidal pressure sensitivity model for velocity prediction.
|
|
14
|
+
|
|
15
|
+
Uses nested sigmoid functions: velocity amplitude varies with porosity,
|
|
16
|
+
and velocity varies sigmoidally with effective pressure using the amplitude.
|
|
17
|
+
|
|
18
|
+
Input format (n,3): [porosity, p_eff_in_situ, p_eff_depleted]
|
|
19
|
+
|
|
20
|
+
The model applies two sigmoid transformations:
|
|
21
|
+
1. Porosity -> velocity amplitude using phi_model parameters
|
|
22
|
+
2. Effective pressure -> velocity using p_eff_model parameters and amplitude
|
|
23
|
+
"""
|
|
7
24
|
|
|
8
|
-
class Sigmoid:
|
|
9
25
|
def __init__(
|
|
10
26
|
self,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
27
|
+
phi_amplitude: float,
|
|
28
|
+
phi_median_point: float,
|
|
29
|
+
phi_x_scaling: float,
|
|
30
|
+
phi_bias: float,
|
|
31
|
+
p_eff_median_point: float,
|
|
32
|
+
p_eff_x_scaling: float,
|
|
33
|
+
p_eff_bias: float,
|
|
34
|
+
model_max_pressure: float | None = None,
|
|
35
|
+
description: str = "",
|
|
16
36
|
):
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
37
|
+
"""
|
|
38
|
+
Initialize sigmoidal pressure model.
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
phi_amplitude : float
|
|
43
|
+
Amplitude parameter for porosity sigmoid [m/s].
|
|
44
|
+
phi_median_point : float
|
|
45
|
+
Median point for porosity sigmoid [fraction].
|
|
46
|
+
phi_x_scaling : float
|
|
47
|
+
X-scaling parameter for porosity sigmoid [unitless].
|
|
48
|
+
phi_bias : float
|
|
49
|
+
Bias parameter for porosity sigmoid [m/s].
|
|
50
|
+
p_eff_median_point : float
|
|
51
|
+
Median point for pressure sigmoid [Pa].
|
|
52
|
+
p_eff_x_scaling : float
|
|
53
|
+
X-scaling parameter for pressure sigmoid [1/Pa].
|
|
54
|
+
p_eff_bias : float
|
|
55
|
+
Bias parameter for pressure sigmoid [m/s].
|
|
56
|
+
model_max_pressure : float | None
|
|
57
|
+
Maximum pressure for predict_max method [Pa].
|
|
58
|
+
description : str
|
|
59
|
+
Model description.
|
|
60
|
+
"""
|
|
61
|
+
super().__init__(model_max_pressure, description)
|
|
62
|
+
# Porosity model parameters
|
|
63
|
+
self._phi_amplitude = phi_amplitude
|
|
64
|
+
self._phi_median_point = phi_median_point
|
|
65
|
+
self._phi_x_scaling = phi_x_scaling
|
|
66
|
+
self._phi_bias = phi_bias
|
|
67
|
+
# Pressure model parameters
|
|
68
|
+
self._p_eff_median_point = p_eff_median_point
|
|
69
|
+
self._p_eff_x_scaling = p_eff_x_scaling
|
|
70
|
+
self._p_eff_bias = p_eff_bias
|
|
31
71
|
|
|
32
72
|
@property
|
|
33
|
-
def
|
|
34
|
-
|
|
73
|
+
def phi_amplitude(self) -> float:
|
|
74
|
+
"""Porosity sigmoid amplitude."""
|
|
75
|
+
return self._phi_amplitude
|
|
35
76
|
|
|
36
77
|
@property
|
|
37
|
-
def
|
|
38
|
-
|
|
78
|
+
def phi_median_point(self) -> float:
|
|
79
|
+
"""Porosity sigmoid median point."""
|
|
80
|
+
return self._phi_median_point
|
|
39
81
|
|
|
40
82
|
@property
|
|
41
|
-
def
|
|
42
|
-
|
|
83
|
+
def phi_x_scaling(self) -> float:
|
|
84
|
+
"""Porosity sigmoid x-scaling."""
|
|
85
|
+
return self._phi_x_scaling
|
|
43
86
|
|
|
44
87
|
@property
|
|
45
|
-
def
|
|
46
|
-
|
|
88
|
+
def phi_bias(self) -> float:
|
|
89
|
+
"""Porosity sigmoid bias."""
|
|
90
|
+
return self._phi_bias
|
|
47
91
|
|
|
48
92
|
@property
|
|
49
|
-
def
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
def predict(self, x):
|
|
53
|
-
if isinstance(x, list):
|
|
54
|
-
x = np.array(x)
|
|
55
|
-
if not self._valid():
|
|
56
|
-
return None
|
|
57
|
-
return (
|
|
58
|
-
self._amplitude / (1 + np.exp(-self._x_scaling * (x - self._median_point)))
|
|
59
|
-
+ self._bias
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
def predict_amp(self, x, amp):
|
|
63
|
-
if isinstance(x, list):
|
|
64
|
-
x = np.array(x)
|
|
65
|
-
if isinstance(amp, list):
|
|
66
|
-
amp = np.array(amp)
|
|
67
|
-
if not self._valid(variant="amp"):
|
|
68
|
-
return None
|
|
69
|
-
return (
|
|
70
|
-
amp / (1 + np.exp(-self._x_scaling * (x - self._median_point))) + self._bias
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
@classmethod
|
|
74
|
-
def save(cls, file):
|
|
75
|
-
with open(file, "wb") as f_out:
|
|
76
|
-
pickle.dump(cls, f_out)
|
|
77
|
-
|
|
78
|
-
@classmethod
|
|
79
|
-
def load(cls, file):
|
|
80
|
-
with open(file, "rb") as f_in:
|
|
81
|
-
return pickle.load(f_in)
|
|
82
|
-
|
|
83
|
-
def _valid(self, variant=None):
|
|
84
|
-
if variant is None and self.amplitude is None:
|
|
85
|
-
raise ValueError('object field "variant" is not set')
|
|
86
|
-
if self.median_point is None:
|
|
87
|
-
raise ValueError('object field "median_point" is not set')
|
|
88
|
-
if self.x_scaling is None:
|
|
89
|
-
raise ValueError('object field "x_scaling" is not set')
|
|
90
|
-
if self.bias is None:
|
|
91
|
-
raise ValueError('object field "bias" is not set')
|
|
92
|
-
return True
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
class CarbonateSigmoidalPressure:
|
|
96
|
-
def __init__(
|
|
97
|
-
self,
|
|
98
|
-
phi_model: Union[dict, Sigmoid] = None,
|
|
99
|
-
p_eff_model: Union[dict, Sigmoid] = None,
|
|
100
|
-
):
|
|
101
|
-
if isinstance(phi_model, Sigmoid):
|
|
102
|
-
self._phi_model = phi_model
|
|
103
|
-
elif isinstance(phi_model, dict):
|
|
104
|
-
self._phi_model = Sigmoid(**phi_model)
|
|
105
|
-
else:
|
|
106
|
-
self._phi_model = None
|
|
107
|
-
if isinstance(p_eff_model, Sigmoid):
|
|
108
|
-
self._p_eff_model = p_eff_model
|
|
109
|
-
elif isinstance(p_eff_model, dict):
|
|
110
|
-
self._p_eff_model = Sigmoid(**p_eff_model)
|
|
111
|
-
else:
|
|
112
|
-
self._p_eff_model = None
|
|
93
|
+
def p_eff_median_point(self) -> float:
|
|
94
|
+
"""Pressure sigmoid median point."""
|
|
95
|
+
return self._p_eff_median_point
|
|
113
96
|
|
|
114
97
|
@property
|
|
115
|
-
def
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
@phi_model.setter
|
|
119
|
-
def phi_model(self, phi_mod):
|
|
120
|
-
if isinstance(phi_mod, Sigmoid):
|
|
121
|
-
self._phi_model = phi_mod
|
|
122
|
-
else:
|
|
123
|
-
raise ValueError(
|
|
124
|
-
f"{type(self)}: expected input Sigmoid object, received {type(phi_mod)}"
|
|
125
|
-
)
|
|
98
|
+
def p_eff_x_scaling(self) -> float:
|
|
99
|
+
"""Pressure sigmoid x-scaling."""
|
|
100
|
+
return self._p_eff_x_scaling
|
|
126
101
|
|
|
127
102
|
@property
|
|
128
|
-
def
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
def
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
103
|
+
def p_eff_bias(self) -> float:
|
|
104
|
+
"""Pressure sigmoid bias."""
|
|
105
|
+
return self._p_eff_bias
|
|
106
|
+
|
|
107
|
+
def validate_input(self, inp_arr: np.ndarray) -> np.ndarray:
|
|
108
|
+
"""
|
|
109
|
+
Validate input for sigmoidal model.
|
|
110
|
+
|
|
111
|
+
Parameters
|
|
112
|
+
----------
|
|
113
|
+
inp_arr : np.ndarray
|
|
114
|
+
Input array to validate.
|
|
115
|
+
|
|
116
|
+
Returns
|
|
117
|
+
-------
|
|
118
|
+
np.ndarray
|
|
119
|
+
Validated input array.
|
|
120
|
+
|
|
121
|
+
Raises
|
|
122
|
+
------
|
|
123
|
+
ValueError
|
|
124
|
+
If input format is invalid.
|
|
125
|
+
"""
|
|
126
|
+
if not isinstance(inp_arr, np.ndarray):
|
|
127
|
+
raise ValueError("Input must be numpy ndarray.")
|
|
128
|
+
if inp_arr.ndim != 2 or inp_arr.shape[1] != 3:
|
|
136
129
|
raise ValueError(
|
|
137
|
-
|
|
130
|
+
"Input must be (n,3): [porosity, p_eff_in_situ, p_eff_depleted]"
|
|
138
131
|
)
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
132
|
+
return inp_arr
|
|
133
|
+
|
|
134
|
+
def _sigmoid_phi(self, phi: np.ndarray) -> np.ndarray:
|
|
135
|
+
"""
|
|
136
|
+
Calculate velocity amplitude from porosity using sigmoid function.
|
|
137
|
+
|
|
138
|
+
Parameters
|
|
139
|
+
----------
|
|
140
|
+
phi : np.ndarray
|
|
141
|
+
Porosity values [fraction].
|
|
142
|
+
|
|
143
|
+
Returns
|
|
144
|
+
-------
|
|
145
|
+
np.ndarray
|
|
146
|
+
Velocity amplitude values [m/s].
|
|
147
|
+
"""
|
|
148
|
+
return (
|
|
149
|
+
self._phi_amplitude
|
|
150
|
+
/ (1 + np.exp(-self._phi_x_scaling * (phi - self._phi_median_point)))
|
|
151
|
+
+ self._phi_bias
|
|
147
152
|
)
|
|
148
|
-
|
|
149
|
-
|
|
153
|
+
|
|
154
|
+
def _sigmoid_p_eff(self, p_eff: np.ndarray, amplitude: np.ndarray) -> np.ndarray:
|
|
155
|
+
"""
|
|
156
|
+
Calculate velocity from effective pressure using sigmoid function with amplitude.
|
|
157
|
+
|
|
158
|
+
Parameters
|
|
159
|
+
----------
|
|
160
|
+
p_eff : np.ndarray
|
|
161
|
+
Effective pressure values [Pa].
|
|
162
|
+
amplitude : np.ndarray
|
|
163
|
+
Velocity amplitude values [m/s].
|
|
164
|
+
|
|
165
|
+
Returns
|
|
166
|
+
-------
|
|
167
|
+
np.ndarray
|
|
168
|
+
Velocity values [m/s].
|
|
169
|
+
"""
|
|
170
|
+
return (
|
|
171
|
+
amplitude
|
|
172
|
+
/ (1 + np.exp(-self._p_eff_x_scaling * (p_eff - self._p_eff_median_point)))
|
|
173
|
+
+ self._p_eff_bias
|
|
150
174
|
)
|
|
151
|
-
return velocity_depl - velocity_init
|
|
152
175
|
|
|
153
176
|
def predict_abs(self, inp_arr: np.ndarray, case: str = "in_situ") -> np.ndarray:
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
177
|
+
"""
|
|
178
|
+
Calculate absolute velocity for specified pressure case.
|
|
179
|
+
|
|
180
|
+
Parameters
|
|
181
|
+
----------
|
|
182
|
+
inp_arr : np.ndarray
|
|
183
|
+
Validated input array (n,3).
|
|
184
|
+
case : str
|
|
185
|
+
Pressure case: "in_situ" or "depleted".
|
|
186
|
+
|
|
187
|
+
Returns
|
|
188
|
+
-------
|
|
189
|
+
np.ndarray
|
|
190
|
+
Velocity values [m/s].
|
|
191
|
+
"""
|
|
192
|
+
arr = self.validate_input(inp_arr)
|
|
193
|
+
|
|
194
|
+
phi = arr[:, 0]
|
|
195
|
+
p_in_situ = arr[:, 1]
|
|
196
|
+
p_depleted = arr[:, 2]
|
|
197
|
+
|
|
198
|
+
# Calculate velocity amplitude from porosity
|
|
199
|
+
velocity_amplitude = self._sigmoid_phi(phi)
|
|
200
|
+
|
|
201
|
+
# Select pressure based on case
|
|
202
|
+
p_eff = p_in_situ if case == "in_situ" else p_depleted
|
|
203
|
+
|
|
204
|
+
# Calculate velocity from effective pressure and amplitude
|
|
205
|
+
return self._sigmoid_p_eff(p_eff, velocity_amplitude)
|
|
206
|
+
|
|
207
|
+
def todict(self) -> dict[str, Any]:
|
|
208
|
+
"""Convert model to dictionary."""
|
|
173
209
|
return {
|
|
174
|
-
"
|
|
175
|
-
"
|
|
210
|
+
"phi_amplitude": self._phi_amplitude,
|
|
211
|
+
"phi_median_point": self._phi_median_point,
|
|
212
|
+
"phi_x_scaling": self._phi_x_scaling,
|
|
213
|
+
"phi_bias": self._phi_bias,
|
|
214
|
+
"p_eff_median_point": self._p_eff_median_point,
|
|
215
|
+
"p_eff_x_scaling": self._p_eff_x_scaling,
|
|
216
|
+
"p_eff_bias": self._p_eff_bias,
|
|
217
|
+
"model_max_pressure": self._model_max_pressure,
|
|
218
|
+
"description": self._description,
|
|
176
219
|
}
|
|
177
220
|
|
|
178
|
-
def save(self, file: Union[str, BufferedIOBase]):
|
|
179
|
-
with open(file, "wb") as f_out:
|
|
180
|
-
pickle.dump(self.todict(), f_out)
|
|
181
|
-
|
|
182
221
|
@classmethod
|
|
183
|
-
def load(cls, file:
|
|
222
|
+
def load(cls, file: str | bytes) -> "SigmoidalPressureModel":
|
|
223
|
+
"""Load sigmoidal model from pickle file."""
|
|
184
224
|
with open(file, "rb") as f_in:
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
225
|
+
d = pickle.load(f_in)
|
|
226
|
+
|
|
227
|
+
return cls(
|
|
228
|
+
phi_amplitude=d["phi_amplitude"],
|
|
229
|
+
phi_median_point=d["phi_median_point"],
|
|
230
|
+
phi_x_scaling=d["phi_x_scaling"],
|
|
231
|
+
phi_bias=d["phi_bias"],
|
|
232
|
+
p_eff_median_point=d["p_eff_median_point"],
|
|
233
|
+
p_eff_x_scaling=d["p_eff_x_scaling"],
|
|
234
|
+
p_eff_bias=d["p_eff_bias"],
|
|
235
|
+
model_max_pressure=d["model_max_pressure"],
|
|
236
|
+
description=d["description"],
|
|
237
|
+
)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from .opt_subst_utilities import (
|
|
2
|
+
gen_mod_routine,
|
|
3
|
+
gen_opt_routine,
|
|
4
|
+
gen_sub_routine,
|
|
5
|
+
load_opt_params,
|
|
6
|
+
opt_param_info,
|
|
7
|
+
opt_param_to_ascii,
|
|
8
|
+
save_opt_params,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"gen_mod_routine",
|
|
13
|
+
"gen_sub_routine",
|
|
14
|
+
"gen_opt_routine",
|
|
15
|
+
"opt_param_to_ascii",
|
|
16
|
+
"opt_param_info",
|
|
17
|
+
"save_opt_params",
|
|
18
|
+
"load_opt_params",
|
|
19
|
+
]
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import inspect
|
|
2
2
|
import math
|
|
3
3
|
import re
|
|
4
|
-
from typing import Union
|
|
5
4
|
from warnings import warn
|
|
6
5
|
|
|
7
6
|
import numpy as np
|
|
@@ -13,7 +12,7 @@ from .snapshots import get_snapshot_name
|
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
def compare_snapshots(
|
|
16
|
-
test_results:
|
|
15
|
+
test_results: np.ndarray | tuple | DataFrame,
|
|
17
16
|
saved_results: tuple,
|
|
18
17
|
name_arr=None,
|
|
19
18
|
display_results: bool = False,
|
|
@@ -1,7 +1,22 @@
|
|
|
1
1
|
import numpy as np
|
|
2
|
+
import numpy.typing as npt
|
|
2
3
|
|
|
3
4
|
|
|
4
|
-
def backus_average(
|
|
5
|
+
def backus_average(
|
|
6
|
+
vp1: npt.NDArray[np.float64],
|
|
7
|
+
vs1: npt.NDArray[np.float64],
|
|
8
|
+
rho1: npt.NDArray[np.float64],
|
|
9
|
+
vp2: npt.NDArray[np.float64],
|
|
10
|
+
vs2: npt.NDArray[np.float64],
|
|
11
|
+
rho2: npt.NDArray[np.float64],
|
|
12
|
+
f1: npt.NDArray[np.float64],
|
|
13
|
+
) -> tuple[
|
|
14
|
+
npt.NDArray[np.float64],
|
|
15
|
+
npt.NDArray[np.float64],
|
|
16
|
+
npt.NDArray[np.float64],
|
|
17
|
+
npt.NDArray[np.float64],
|
|
18
|
+
npt.NDArray[np.float64],
|
|
19
|
+
]:
|
|
5
20
|
"""
|
|
6
21
|
Backus average for a combination of two phases. The individual phases are isotropic
|
|
7
22
|
but the resulting effective medium is not.
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import numpy as np
|
|
2
|
+
import numpy.typing as npt
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
def dvorkin_contact_cement(
|
|
5
|
-
frac_cem
|
|
6
|
-
|
|
6
|
+
frac_cem: npt.NDArray[np.float64],
|
|
7
|
+
por0_sst: npt.NDArray[np.float64],
|
|
8
|
+
mu0_sst: npt.NDArray[np.float64],
|
|
9
|
+
k0_sst: npt.NDArray[np.float64],
|
|
10
|
+
mu0_cem: npt.NDArray[np.float64],
|
|
11
|
+
k0_cem: npt.NDArray[np.float64],
|
|
12
|
+
vs_red: npt.NDArray[np.float64],
|
|
13
|
+
c: float,
|
|
14
|
+
) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]:
|
|
7
15
|
"""
|
|
8
16
|
Dvorkin-Nur contact cement model for estimation of elastic moduli.
|
|
9
17
|
|