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.

Files changed (64) hide show
  1. rock_physics_open/equinor_utilities/gen_utilities/dict_to_float.py +6 -1
  2. rock_physics_open/equinor_utilities/gen_utilities/dim_check_vector.py +35 -5
  3. rock_physics_open/equinor_utilities/gen_utilities/filter_input.py +11 -6
  4. rock_physics_open/equinor_utilities/gen_utilities/filter_output.py +29 -19
  5. rock_physics_open/equinor_utilities/machine_learning_utilities/__init__.py +6 -5
  6. rock_physics_open/equinor_utilities/machine_learning_utilities/base_pressure_model.py +172 -0
  7. rock_physics_open/equinor_utilities/machine_learning_utilities/exponential_model.py +100 -86
  8. rock_physics_open/equinor_utilities/machine_learning_utilities/import_ml_models.py +7 -4
  9. rock_physics_open/equinor_utilities/machine_learning_utilities/polynomial_model.py +128 -0
  10. rock_physics_open/equinor_utilities/machine_learning_utilities/run_regression.py +6 -4
  11. rock_physics_open/equinor_utilities/machine_learning_utilities/sigmoidal_model.py +204 -155
  12. rock_physics_open/equinor_utilities/optimisation_utilities/__init__.py +19 -0
  13. rock_physics_open/equinor_utilities/snapshot_test_utilities/compare_snapshots.py +1 -2
  14. rock_physics_open/equinor_utilities/std_functions/backus_ave.py +16 -1
  15. rock_physics_open/equinor_utilities/std_functions/dvorkin_nur.py +10 -2
  16. rock_physics_open/equinor_utilities/std_functions/gassmann.py +32 -7
  17. rock_physics_open/equinor_utilities/std_functions/hashin_shtrikman.py +36 -7
  18. rock_physics_open/equinor_utilities/std_functions/hertz_mindlin.py +9 -1
  19. rock_physics_open/equinor_utilities/std_functions/moduli_velocity.py +22 -6
  20. rock_physics_open/equinor_utilities/std_functions/reflection_eq.py +28 -6
  21. rock_physics_open/equinor_utilities/std_functions/rho.py +12 -2
  22. rock_physics_open/equinor_utilities/std_functions/voigt_reuss_hill.py +25 -4
  23. rock_physics_open/equinor_utilities/std_functions/walton.py +8 -1
  24. rock_physics_open/equinor_utilities/std_functions/wood_brie.py +20 -3
  25. rock_physics_open/equinor_utilities/various_utilities/display_result_statistics.py +16 -9
  26. rock_physics_open/equinor_utilities/various_utilities/gassmann_dry_mod.py +21 -2
  27. rock_physics_open/equinor_utilities/various_utilities/gassmann_mod.py +21 -2
  28. rock_physics_open/equinor_utilities/various_utilities/gassmann_sub_mod.py +23 -12
  29. rock_physics_open/equinor_utilities/various_utilities/hs_average.py +20 -1
  30. rock_physics_open/equinor_utilities/various_utilities/pressure.py +9 -1
  31. rock_physics_open/equinor_utilities/various_utilities/reflectivity.py +26 -10
  32. rock_physics_open/equinor_utilities/various_utilities/timeshift.py +15 -2
  33. rock_physics_open/equinor_utilities/various_utilities/vp_vs_rho_set_statistics.py +40 -24
  34. rock_physics_open/equinor_utilities/various_utilities/vrh_3_min.py +24 -2
  35. rock_physics_open/fluid_models/brine_model/brine_properties.py +70 -35
  36. rock_physics_open/fluid_models/gas_model/gas_properties.py +79 -37
  37. rock_physics_open/fluid_models/oil_model/dead_oil_density.py +21 -16
  38. rock_physics_open/fluid_models/oil_model/dead_oil_velocity.py +9 -7
  39. rock_physics_open/fluid_models/oil_model/live_oil_density.py +16 -13
  40. rock_physics_open/fluid_models/oil_model/live_oil_velocity.py +3 -3
  41. rock_physics_open/fluid_models/oil_model/oil_properties.py +59 -29
  42. rock_physics_open/sandstone_models/__init__.py +2 -0
  43. rock_physics_open/sandstone_models/constant_cement_optimisation.py +4 -1
  44. rock_physics_open/sandstone_models/friable_models.py +6 -7
  45. rock_physics_open/sandstone_models/friable_optimisation.py +4 -1
  46. rock_physics_open/sandstone_models/patchy_cement_model.py +103 -5
  47. rock_physics_open/sandstone_models/patchy_cement_optimisation.py +4 -1
  48. rock_physics_open/t_matrix_models/__init__.py +0 -10
  49. rock_physics_open/t_matrix_models/carbonate_pressure_substitution.py +1 -1
  50. rock_physics_open/t_matrix_models/curvefit_t_matrix_exp.py +1 -2
  51. rock_physics_open/t_matrix_models/t_matrix_opt_fluid_sub_exp.py +3 -3
  52. rock_physics_open/t_matrix_models/t_matrix_opt_fluid_sub_petec.py +5 -1
  53. rock_physics_open/t_matrix_models/t_matrix_opt_forward_model_exp.py +5 -1
  54. rock_physics_open/t_matrix_models/t_matrix_opt_forward_model_min.py +4 -1
  55. rock_physics_open/t_matrix_models/t_matrix_parameter_optimisation_exp.py +5 -1
  56. rock_physics_open/t_matrix_models/t_matrix_parameter_optimisation_min.py +4 -1
  57. rock_physics_open/ternary_plots/ternary_plot_utilities.py +3 -3
  58. rock_physics_open/version.py +2 -2
  59. {rock_physics_open-0.2.3.dist-info → rock_physics_open-0.3.1.dist-info}/METADATA +4 -8
  60. {rock_physics_open-0.2.3.dist-info → rock_physics_open-0.3.1.dist-info}/RECORD +64 -61
  61. /rock_physics_open/{t_matrix_models → equinor_utilities/optimisation_utilities}/opt_subst_utilities.py +0 -0
  62. {rock_physics_open-0.2.3.dist-info → rock_physics_open-0.3.1.dist-info}/WHEEL +0 -0
  63. {rock_physics_open-0.2.3.dist-info → rock_physics_open-0.3.1.dist-info}/licenses/LICENSE +0 -0
  64. {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(inp_df, vp_model_file_name, vs_model_file_name, model_dir=None):
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
- vp_model_file_name : str
121
+ first_model_file_name : str
120
122
  Full file name for vp model.
121
- vs_model_file_name : str
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(vp_model_file_name, vs_model_file_name, model_dir=model_dir)
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 io import BufferedIOBase
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
- amplitude: float = None,
12
- median_point: float = None,
13
- x_scaling: float = None,
14
- bias: float = None,
15
- description="",
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
- self._amplitude = amplitude
18
- self._median_point = median_point
19
- self._x_scaling = x_scaling
20
- self._bias = bias
21
- self._description = description
22
-
23
- def todict(self):
24
- return {
25
- "amplitude": self._amplitude,
26
- "median_point": self._median_point,
27
- "x_scaling": self._x_scaling,
28
- "bias": self._bias,
29
- "description": self._description,
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 amplitude(self):
34
- return self._amplitude
73
+ def phi_amplitude(self) -> float:
74
+ """Porosity sigmoid amplitude."""
75
+ return self._phi_amplitude
35
76
 
36
77
  @property
37
- def median_point(self):
38
- return self._median_point
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 x_scaling(self):
42
- return self._x_scaling
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 bias(self):
46
- return self._bias
88
+ def phi_bias(self) -> float:
89
+ """Porosity sigmoid bias."""
90
+ return self._phi_bias
47
91
 
48
92
  @property
49
- def description(self):
50
- return self._description
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 phi_model(self):
116
- return self._phi_model
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 p_eff_model(self):
129
- return self._p_eff_model
130
-
131
- @p_eff_model.setter
132
- def p_eff_model(self, p_eff_mod):
133
- if isinstance(p_eff_mod, Sigmoid):
134
- self._p_eff_model = p_eff_mod
135
- else:
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
- f"{type(self)}: expected input Sigmoid object, received {type(p_eff_mod)}"
130
+ "Input must be (n,3): [porosity, p_eff_in_situ, p_eff_depleted]"
138
131
  )
139
-
140
- def predict(self, inp_arr: np.ndarray) -> np.ndarray:
141
- # Don't save any of the intermediate calculations, only return the difference between the effective pressure
142
- # cases. The method name is set to be the same as for other machine learning models
143
- self._validate_input(inp_arr)
144
- velocity_amp = self._phi_model.predict(inp_arr[:, 0].flatten())
145
- velocity_init = self._p_eff_model.predict_amp(
146
- inp_arr[:, 1].flatten(), velocity_amp
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
- velocity_depl = self._p_eff_model.predict_amp(
149
- inp_arr[:, 2].flatten(), velocity_amp
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
- # Method for access to absolute results, not just the difference
155
- self._validate_input(inp_arr)
156
- velocity_amp = self._phi_model.predict(inp_arr[:, 0].flatten())
157
- if case == "in_situ":
158
- return self._p_eff_model.predict_amp(inp_arr[:, 1].flatten(), velocity_amp)
159
- return self._p_eff_model.predict_amp(inp_arr[:, 2].flatten(), velocity_amp)
160
-
161
- def _validate_input(self, input_array):
162
- if not isinstance(input_array, np.ndarray):
163
- raise ValueError(
164
- f"{type(input_array)}: should be numpy array with shape n x 3"
165
- )
166
- if not ((input_array.ndim == 2) and (input_array.shape[1] == 3)):
167
- raise ValueError(
168
- f'{type(self)}: Input array should be of shape n x 3, with columns in sequence "PHIT", '
169
- f'"P_EFF_in_situ" and "P_EFF_depleted"'
170
- )
171
-
172
- def todict(self):
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
- "phi_model": self._phi_model.todict(),
175
- "p_eff_model": self._p_eff_model.todict(),
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: Union[str, BufferedIOBase]):
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
- load_dict = pickle.load(f_in)
186
- return cls(
187
- phi_model=load_dict["phi_model"], p_eff_model=load_dict["p_eff_model"]
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: Union[np.ndarray, tuple, DataFrame],
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(vp1, vs1, rho1, vp2, vs2, rho2, f1):
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, por0_sst, mu0_sst, k0_sst, mu0_cem, k0_cem, vs_red, c
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