fmu-pem 0.0.2__py3-none-any.whl → 0.0.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. fmu/pem/__init__.py +2 -0
  2. fmu/pem/__main__.py +72 -19
  3. fmu/pem/forward_models/pem_model.py +21 -26
  4. fmu/pem/pem_functions/__init__.py +2 -2
  5. fmu/pem/pem_functions/density.py +32 -38
  6. fmu/pem/pem_functions/effective_pressure.py +153 -49
  7. fmu/pem/pem_functions/estimate_saturated_rock.py +244 -52
  8. fmu/pem/pem_functions/fluid_properties.py +447 -245
  9. fmu/pem/pem_functions/mineral_properties.py +77 -74
  10. fmu/pem/pem_functions/pressure_sensitivity.py +430 -0
  11. fmu/pem/pem_functions/regression_models.py +129 -97
  12. fmu/pem/pem_functions/run_friable_model.py +106 -37
  13. fmu/pem/pem_functions/run_patchy_cement_model.py +107 -45
  14. fmu/pem/pem_functions/{run_t_matrix_and_pressure.py → run_t_matrix_model.py} +48 -27
  15. fmu/pem/pem_utilities/__init__.py +30 -10
  16. fmu/pem/pem_utilities/cumsum_properties.py +29 -37
  17. fmu/pem/pem_utilities/delta_cumsum_time.py +8 -13
  18. fmu/pem/pem_utilities/enum_defs.py +65 -8
  19. fmu/pem/pem_utilities/export_routines.py +84 -72
  20. fmu/pem/pem_utilities/fipnum_pvtnum_utilities.py +217 -0
  21. fmu/pem/pem_utilities/import_config.py +76 -50
  22. fmu/pem/pem_utilities/import_routines.py +57 -69
  23. fmu/pem/pem_utilities/pem_class_definitions.py +81 -23
  24. fmu/pem/pem_utilities/pem_config_validation.py +364 -172
  25. fmu/pem/pem_utilities/rpm_models.py +473 -100
  26. fmu/pem/pem_utilities/update_grid.py +3 -2
  27. fmu/pem/pem_utilities/utils.py +90 -38
  28. fmu/pem/run_pem.py +66 -48
  29. fmu/pem/version.py +16 -3
  30. {fmu_pem-0.0.2.dist-info → fmu_pem-0.0.4.dist-info}/METADATA +19 -11
  31. fmu_pem-0.0.4.dist-info/RECORD +39 -0
  32. {fmu_pem-0.0.2.dist-info → fmu_pem-0.0.4.dist-info}/WHEEL +1 -1
  33. fmu_pem-0.0.2.dist-info/RECORD +0 -37
  34. {fmu_pem-0.0.2.dist-info → fmu_pem-0.0.4.dist-info}/entry_points.txt +0 -0
  35. {fmu_pem-0.0.2.dist-info → fmu_pem-0.0.4.dist-info}/licenses/LICENSE +0 -0
  36. {fmu_pem-0.0.2.dist-info → fmu_pem-0.0.4.dist-info}/top_level.txt +0 -0
@@ -4,9 +4,6 @@ Regression based on polynomial models for saturated sandstones. The models are
4
4
  based on porosity polynomials to estimate either Vp and Vs, or K and Mu.
5
5
  """
6
6
 
7
- from pathlib import Path
8
- from typing import List, Union
9
-
10
7
  import numpy as np
11
8
  import numpy.typing as npt
12
9
  from rock_physics_open.equinor_utilities.std_functions import (
@@ -16,24 +13,31 @@ from rock_physics_open.equinor_utilities.std_functions import (
16
13
  velocity,
17
14
  voigt_reuss_hill,
18
15
  )
19
- from rock_physics_open.t_matrix_models import carbonate_pressure_model
20
16
 
21
17
  from fmu.pem.pem_utilities import (
22
18
  DryRockProperties,
23
19
  EffectiveFluidProperties,
24
- MatrixProperties,
25
- PemConfig,
20
+ EffectiveMineralProperties,
26
21
  PressureProperties,
22
+ RockMatrixProperties,
27
23
  SaturatedRockProperties,
28
24
  filter_and_one_dim,
29
25
  reverse_filter_and_restore,
30
26
  )
31
- from fmu.pem.pem_utilities.enum_defs import MineralMixModel
27
+ from fmu.pem.pem_utilities.enum_defs import (
28
+ MineralMixModel,
29
+ ParameterTypes,
30
+ PhysicsPressureModelTypes,
31
+ )
32
32
  from fmu.pem.pem_utilities.rpm_models import (
33
33
  KMuRegressionParams,
34
34
  VpVsRegressionParams,
35
35
  )
36
36
 
37
+ from .pressure_sensitivity import (
38
+ apply_dry_rock_pressure_sensitivity_model,
39
+ )
40
+
37
41
 
38
42
  def gen_regression(
39
43
  porosity: np.ndarray, polynom_weights: list | np.ndarray
@@ -48,14 +52,17 @@ def gen_regression(
48
52
  Vp [m/s]
49
53
  """
50
54
  pol = np.polynomial.Polynomial(polynom_weights)
51
- return pol(porosity)
55
+ # Call to Polynomial class will return ndarray or float, depending on input.
56
+ # This is not recognised by the
57
+ poly_val: np.ndarray = pol(porosity) # type: ignore
58
+ return poly_val
52
59
 
53
60
 
54
61
  def dry_rock_regression(
55
- porosity: npt.NDArray[np.float64] | np.ma.MaskedArray,
56
- rho_min: npt.NDArray[np.float64] | np.ma.MaskedArray,
62
+ porosity: npt.NDArray[np.float64],
63
+ rho_min: npt.NDArray[np.float64],
57
64
  params: VpVsRegressionParams | KMuRegressionParams,
58
- ) -> DryRockProperties:
65
+ ) -> tuple[npt.NDArray[np.float64], ...]:
59
66
  """
60
67
  Calculates dry rock properties based on porosity and polynomial weights.
61
68
 
@@ -72,11 +79,11 @@ def dry_rock_regression(
72
79
  ValueError: If an invalid mode is provided or necessary weights for
73
80
  the selected mode are missing.
74
81
  """
75
- if not params.rho_regression:
76
- # rho_regression = False, use mineral density
82
+ if not params.rho_model:
83
+ # rho_model = False, use mineral density
77
84
  rho_dry = rho_min * (1 - porosity)
78
85
  else:
79
- rho_dry = gen_regression(porosity, params.rho_weights)
86
+ rho_dry = gen_regression(porosity, params.rho_model.rho_weights)
80
87
 
81
88
  if (
82
89
  params.mode == "vp_vs"
@@ -96,47 +103,39 @@ def dry_rock_regression(
96
103
  else:
97
104
  raise ValueError("Invalid mode or missing weights for the selected mode.")
98
105
 
99
- return DryRockProperties(
100
- bulk_modulus=np.ma.MaskedArray(k_dry),
101
- shear_modulus=np.ma.MaskedArray(mu),
102
- dens=np.ma.MaskedArray(rho_dry),
103
- )
106
+ return k_dry, mu, rho_dry
104
107
 
105
108
 
106
109
  def run_regression_models(
107
- mineral: MatrixProperties,
110
+ matrix: EffectiveMineralProperties,
108
111
  fluid_properties: list[EffectiveFluidProperties],
109
112
  porosity: np.ma.MaskedArray,
110
113
  pressure: list[PressureProperties],
111
- config: PemConfig,
112
- vsh: Union[np.ma.MaskedArray, None] = None,
113
- pres_model_vp: Path = Path("carbonate_pressure_model_vp_exp.pkl"),
114
- pres_model_vs: Path = Path("carbonate_pressure_model_vs_exp.pkl"),
115
- ) -> List[SaturatedRockProperties]:
114
+ rock_matrix: RockMatrixProperties,
115
+ vsh: np.ma.MaskedArray | None = None,
116
+ ) -> tuple[list[SaturatedRockProperties], list[DryRockProperties]]:
116
117
  """Run regression models for saturated rock properties.
117
118
 
118
119
  Args:
119
- mineral: Mineral properties containing bulk modulus (k) [Pa],
120
+ matrix: Effective mineral properties containing bulk modulus (k) [Pa],
120
121
  shear modulus (mu) [Pa] and density (rho_sat) [kg/m3]
121
- fluid_properties: List of fluid properties,
122
+ fluid_properties: list of fluid properties,
122
123
  each containing bulk modulus (k) [Pa] and density (rho_sat) [kg/m3]
123
124
  porosity: Porosity as a masked array [fraction]
124
- pressure: List of pressure properties containing effective pressure values
125
- [bar] following Eclipse reservoir simulator convention
126
- config: Parameters for the PEM
125
+ pressure: list of pressure properties containing effective pressure values
126
+ in unit Pa
127
+ rock_matrix: rock matrix properties
127
128
  vsh: Volume of shale as a masked array [fraction], optional
128
- pres_model_vp: Path to the pressure sensitivity model file for P-wave velocity
129
- (default: "carbonate_pressure_model_vp_exp_2023.pkl")
130
- pres_model_vs: Path to the pressure sensitivity model file for S-wave velocity
131
- (default: "carbonate_pressure_model_vs_exp_2023.pkl")
132
-
133
129
 
134
130
  Returns:
135
- List[SaturatedRockProperties]: Saturated rock properties for each time step.
131
+ list[SaturatedRockProperties]: Saturated rock properties for each time step.
136
132
  Only fluid properties change between time steps in this model.
133
+ list[DryRockProperties]: dry rock properties with bulk modulus [Pa], shear
134
+ modulus [Pa] and density [kg/m^3]
137
135
  """
138
136
 
139
137
  saturated_props = []
138
+ dry_props = []
140
139
  tmp_pres_over = None
141
140
  tmp_pres_form = None
142
141
  tmp_pres_depl = None
@@ -148,12 +147,14 @@ def run_regression_models(
148
147
  multiple_lithologies = False
149
148
  else:
150
149
  multiple_lithologies = True
151
- # Convert pressure from bar to Pa
152
- pres_ovb = pressure[0].overburden_pressure * 1.0e5
153
- pres_form = pressure[0].formation_pressure * 1.0e5
150
+
151
+ # Initial pressure conditions
152
+ pres_ovb = pressure[0].overburden_pressure
153
+ pres_form = pressure[0].formation_pressure
154
154
  for time_step, fl_prop in enumerate(fluid_properties):
155
- if time_step > 0 and config.rock_matrix.pressure_sensitivity:
156
- pres_depl = pressure[time_step].formation_pressure * 1.0e5
155
+ # Prepare data using filter_and_one_dim
156
+ if time_step > 0 and rock_matrix.pressure_sensitivity:
157
+ pres_depl = pressure[time_step].formation_pressure
157
158
  (
158
159
  mask,
159
160
  tmp_min_k,
@@ -167,11 +168,11 @@ def run_regression_models(
167
168
  tmp_pres_form,
168
169
  tmp_pres_depl,
169
170
  ) = filter_and_one_dim(
170
- mineral.bulk_modulus,
171
- mineral.shear_modulus,
172
- mineral.dens,
171
+ matrix.bulk_modulus,
172
+ matrix.shear_modulus,
173
+ matrix.density,
173
174
  fl_prop.bulk_modulus,
174
- fl_prop.dens,
175
+ fl_prop.density,
175
176
  porosity,
176
177
  vsh,
177
178
  pres_ovb,
@@ -190,72 +191,103 @@ def run_regression_models(
190
191
  tmp_por,
191
192
  tmp_vsh,
192
193
  ) = filter_and_one_dim(
193
- mineral.bulk_modulus,
194
- mineral.shear_modulus,
195
- mineral.dens,
194
+ matrix.bulk_modulus,
195
+ matrix.shear_modulus,
196
+ matrix.density,
196
197
  fl_prop.bulk_modulus,
197
- fl_prop.dens,
198
+ fl_prop.density,
198
199
  porosity,
199
200
  vsh,
201
+ return_numpy_array=True,
200
202
  )
203
+
201
204
  if not multiple_lithologies:
202
- dry_props = dry_rock_regression(
203
- tmp_por, tmp_min_rho, config.rock_matrix.model.parameters.sandstone
205
+ k_dry, mu, rho_dry = dry_rock_regression(
206
+ tmp_por, tmp_min_rho, rock_matrix.model.parameters.sandstone
204
207
  )
205
208
  else:
206
- dry_props_sand = dry_rock_regression(
207
- tmp_por, tmp_min_rho, config.rock_matrix.model.parameters.sandstone
208
- )
209
- dry_props_shale = dry_rock_regression(
210
- tmp_por, tmp_min_rho, config.rock_matrix.model.parameters.shale
209
+ k_sand, mu_sand, rho_sand = dry_rock_regression(
210
+ tmp_por, tmp_min_rho, rock_matrix.model.parameters.sandstone
211
211
  )
212
- dry_rho = (
213
- dry_props_sand.dens * (1.0 - tmp_vsh) + dry_props_shale.dens * tmp_vsh
212
+ k_shale, mu_shale, rho_shale = dry_rock_regression(
213
+ tmp_por, tmp_min_rho, rock_matrix.model.parameters.shale
214
214
  )
215
- if config.rock_matrix.mineral_mix_model == MineralMixModel.HASHIN_SHTRIKMAN:
215
+ rho_dry = rho_sand * (1.0 - tmp_vsh) + rho_shale * tmp_vsh
216
+ if rock_matrix.mineral_mix_model == MineralMixModel.HASHIN_SHTRIKMAN:
216
217
  k_dry, mu = hashin_shtrikman_average(
217
- dry_props_sand.bulk_modulus,
218
- dry_props_shale.bulk_modulus,
219
- dry_props_sand.shear_modulus,
220
- dry_props_shale.shear_modulus,
221
- (1.0 - tmp_vsh),
218
+ k1=k_sand, mu1=mu_sand, k2=k_shale, mu2=mu_shale, f=(1.0 - tmp_vsh)
222
219
  )
223
220
  else:
224
221
  k_dry, mu = voigt_reuss_hill(
225
- dry_props_sand.bulk_modulus,
226
- dry_props_shale.bulk_modulus,
227
- dry_props_sand.shear_modulus,
228
- dry_props_shale.shear_modulus,
229
- (1.0 - tmp_vsh),
222
+ k1=k_sand, mu1=mu_sand, k2=k_shale, mu2=mu_shale, f1=(1.0 - tmp_vsh)
230
223
  )
231
- dry_props = DryRockProperties(
232
- bulk_modulus=k_dry, shear_modulus=mu, dens=dry_rho
233
- )
234
224
 
235
- k_sat = gassmann(dry_props.bulk_modulus, tmp_por, tmp_fl_prop_k, tmp_min_k)
236
- rho_sat = dry_props.dens + tmp_por * tmp_fl_prop_rho
237
- vp, vs = velocity(k_sat, dry_props.shear_modulus, rho_sat)[0:2]
238
- if time_step > 0 and config.rock_matrix.pressure_sensitivity:
239
- # Inputs must be numpy arrays, not masked arrays
240
- vp, vs, rho_sat, _, _ = carbonate_pressure_model(
241
- tmp_fl_prop_rho,
242
- vp.data,
243
- vs.data,
244
- rho_sat,
245
- vp.data,
246
- vs.data,
247
- rho_sat,
248
- tmp_por,
249
- tmp_pres_over,
250
- tmp_pres_form,
251
- tmp_pres_depl,
252
- pres_model_vp,
253
- pres_model_vs,
254
- config.paths.rel_path_pem.absolute(),
255
- False,
225
+ # Perform pressure correction on dry rock properties
226
+ if time_step > 0 and rock_matrix.pressure_sensitivity:
227
+ # Prepare in-situ properties dictionary based on what we have
228
+ in_situ_dict = {
229
+ ParameterTypes.K.value: k_dry,
230
+ ParameterTypes.MU.value: mu,
231
+ ParameterTypes.RHO.value: rho_dry,
232
+ ParameterTypes.POROSITY.value: tmp_por,
233
+ }
234
+
235
+ mineral_props = None
236
+ cement_props = None
237
+
238
+ # Regression model requirements are met as default, but in the case of a
239
+ # "physics model" (friable or patchy cement), extra matrix properties are
240
+ # needed
241
+ if hasattr(
242
+ rock_matrix.pressure_sensitivity_model, "model_type"
243
+ ) and rock_matrix.pressure_sensitivity_model.model_type in list(
244
+ PhysicsPressureModelTypes
245
+ ):
246
+ # Create mineral properties from matrix properties
247
+ mineral_props = EffectiveMineralProperties(
248
+ bulk_modulus=tmp_min_k,
249
+ shear_modulus=tmp_min_mu,
250
+ density=tmp_min_rho,
251
+ )
252
+
253
+ # If patchy cement model, create cement properties
254
+ if (
255
+ rock_matrix.pressure_sensitivity_model.model_type
256
+ == PhysicsPressureModelTypes.PATCHY_CEMENT
257
+ ):
258
+ # Use specified cement mineral
259
+ cement_props = rock_matrix.minerals[rock_matrix.cement]
260
+
261
+ # Apply pressure sensitivity model
262
+ depleted_props = apply_dry_rock_pressure_sensitivity_model(
263
+ model=rock_matrix.pressure_sensitivity_model,
264
+ initial_eff_pressure=(
265
+ tmp_pres_over - tmp_pres_form
266
+ ), # effective initial pressure
267
+ depleted_eff_pressure=(
268
+ tmp_pres_over - tmp_pres_depl
269
+ ), # effective depleted pressure
270
+ in_situ_dict=in_situ_dict,
271
+ mineral_properties=mineral_props,
272
+ cement_properties=cement_props,
256
273
  )
257
- vp, vs, rho_sat = reverse_filter_and_restore(mask, vp, vs, rho_sat)
258
- props = SaturatedRockProperties(vp=vp, vs=vs, dens=rho_sat)
259
- saturated_props.append(props)
260
274
 
261
- return saturated_props
275
+ # Update dry properties with pressure-corrected values
276
+ k_dry = depleted_props[ParameterTypes.K.value]
277
+ mu = depleted_props[ParameterTypes.MU.value]
278
+ rho_dry = depleted_props[ParameterTypes.RHO.value]
279
+
280
+ # Saturate rock
281
+ k_sat = gassmann(k_dry, tmp_por, tmp_fl_prop_k, tmp_min_k)
282
+ rho_sat = rho_dry + tmp_por * tmp_fl_prop_rho
283
+ vp, vs = velocity(k_sat, mu, rho_sat)[0:2]
284
+
285
+ vp, vs, rho_sat, k_dry, mu, rho_dry = reverse_filter_and_restore(
286
+ mask, vp, vs, rho_sat, k_dry, mu, rho_dry
287
+ )
288
+ saturated_props.append(SaturatedRockProperties(vp=vp, vs=vs, density=rho_sat))
289
+ dry_props.append(
290
+ DryRockProperties(bulk_modulus=k_dry, shear_modulus=mu, density=rho_dry)
291
+ )
292
+
293
+ return saturated_props, dry_props
@@ -1,27 +1,36 @@
1
1
  from dataclasses import asdict
2
- from typing import List, Union
3
2
 
4
3
  import numpy as np
5
- from rock_physics_open.sandstone_models import friable_model
4
+ from rock_physics_open.equinor_utilities.std_functions import (
5
+ gassmann,
6
+ velocity,
7
+ )
8
+ from rock_physics_open.sandstone_models import friable_model_dry
6
9
 
7
10
  from fmu.pem.pem_utilities import (
11
+ DryRockProperties,
8
12
  EffectiveFluidProperties,
9
- MatrixProperties,
10
- PemConfig,
13
+ EffectiveMineralProperties,
11
14
  PressureProperties,
15
+ RockMatrixProperties,
12
16
  SaturatedRockProperties,
13
17
  filter_and_one_dim,
14
18
  reverse_filter_and_restore,
15
19
  )
20
+ from fmu.pem.pem_utilities.enum_defs import (
21
+ ParameterTypes,
22
+ )
23
+
24
+ from .pressure_sensitivity import apply_dry_rock_pressure_sensitivity_model
16
25
 
17
26
 
18
27
  def run_friable(
19
- mineral: MatrixProperties,
20
- fluid: Union[list[EffectiveFluidProperties], EffectiveFluidProperties],
28
+ mineral: EffectiveMineralProperties,
29
+ fluid: list[EffectiveFluidProperties] | EffectiveFluidProperties,
21
30
  porosity: np.ma.MaskedArray,
22
- pressure: Union[list[PressureProperties], PressureProperties],
23
- config: PemConfig,
24
- ) -> List[SaturatedRockProperties]:
31
+ pressure: list[PressureProperties] | PressureProperties,
32
+ rock_matrix: RockMatrixProperties,
33
+ ) -> tuple[list[SaturatedRockProperties], list[DryRockProperties]]:
25
34
  """
26
35
  Prepare inputs and parameters for running the Friable sandstone model
27
36
 
@@ -30,19 +39,32 @@ def run_friable(
30
39
  fluid: fluid properties containing k [Pa] and rho [kg/m3], can be several fluid
31
40
  properties in a list
32
41
  porosity: porosity fraction
33
- pressure: steps in effective pressure in [bar] due to Eclipse standard
34
- config: parameters for the PEM
42
+ pressure: steps in effective pressure, unit Pa
43
+ rock_matrix: parameters rock matrix
35
44
 
36
45
  Returns:
37
46
  saturated rock properties with vp [m/s], vs [m/s], density [kg/m^3], ai
38
47
  (vp * density), si (vs * density), vpvs (vp / vs)
48
+ dry rock properties with bulk modulus [Pa], shear modulus [Pa] and density
49
+ [kg/m^3]
39
50
  """
40
51
  # Mineral and porosity are assumed to be single objects, fluid and
41
52
  # effective_pressure can be lists
42
53
  fluid, pressure = _verify_inputs(fluid, pressure)
54
+
55
+ # Depletion is calculated from the initial effective pressure
56
+ initial_effective_pressure = pressure[0].effective_pressure
57
+ # Container for saturated properties
43
58
  saturated_props = []
44
- friable_params = config.rock_matrix.model.parameters
45
- for fl_prop, pres in zip(fluid, pressure):
59
+ dry_props = []
60
+
61
+ # to please the IDE:
62
+ k_dry = None
63
+ mu = None
64
+ k_init = None
65
+ mu_init = None
66
+
67
+ for time_step, (fl_prop, pres) in enumerate(zip(fluid, pressure)):
46
68
  (
47
69
  mask,
48
70
  tmp_min_k,
@@ -52,37 +74,84 @@ def run_friable(
52
74
  tmp_fl_prop_rho,
53
75
  tmp_por,
54
76
  tmp_pres,
77
+ init_press,
55
78
  ) = filter_and_one_dim(
56
79
  mineral.bulk_modulus,
57
80
  mineral.shear_modulus,
58
- mineral.dens,
81
+ mineral.density,
59
82
  fl_prop.bulk_modulus,
60
- fl_prop.dens,
83
+ fl_prop.density,
61
84
  porosity,
62
- pres.effective_pressure * 1.0e5,
85
+ pres.effective_pressure,
86
+ initial_effective_pressure,
87
+ return_numpy_array=True,
63
88
  )
64
- """Estimation of effective mineral properties must be able to handle cases where
65
- there is a more complex combination of minerals than the standard sand/shale
66
- case. For carbonates the input can be based on minerals (e.g. calcite,
67
- dolomite, quartz, smectite, ...) or PRTs (petrophysical rock types) that each
68
- have been assigned elastic properties to."""
69
- vp, vs, rho, _, _ = friable_model(
70
- tmp_min_k,
71
- tmp_min_mu,
72
- tmp_min_rho,
73
- tmp_fl_prop_k,
74
- tmp_fl_prop_rho,
75
- tmp_por,
76
- tmp_pres,
77
- friable_params.critical_porosity,
78
- friable_params.coordination_number_function.fcn,
79
- friable_params.coordination_number,
80
- friable_params.shear_reduction,
89
+ # At initial pressure, there is no need to estimate pressure effect on dry rock.
90
+ # If there is no pressure sensitivity, we use the initial pressure for the dry
91
+ # rock also after start of production, and the only differences will be due to
92
+ # changes in fluid properties or saturation
93
+ if time_step == 0:
94
+ k_dry, mu = friable_model_dry(
95
+ k_min=tmp_min_k,
96
+ mu_min=tmp_min_mu,
97
+ phi=tmp_por,
98
+ p_eff=init_press,
99
+ phi_c=rock_matrix.model.parameters.critical_porosity,
100
+ coord_num_func=rock_matrix.model.parameters.coordination_number_function,
101
+ n=rock_matrix.model.parameters.coord_num,
102
+ shear_red=rock_matrix.model.parameters.shear_reduction,
103
+ )
104
+ # For use at depleted pressure
105
+ k_init = k_dry
106
+ mu_init = mu
107
+ if time_step > 0 and rock_matrix.pressure_sensitivity:
108
+ # estimate the properties for the initial pressure by friable model,
109
+ # then apply correction for depletion
110
+
111
+ # Prepare in situ properties
112
+ in_situ_dict = {
113
+ ParameterTypes.K.value: k_init,
114
+ ParameterTypes.MU.value: mu_init,
115
+ ParameterTypes.RHO.value: tmp_min_rho,
116
+ ParameterTypes.POROSITY.value: tmp_por,
117
+ }
118
+ tmp_matrix = EffectiveMineralProperties(
119
+ bulk_modulus=tmp_min_k,
120
+ shear_modulus=tmp_min_mu,
121
+ density=tmp_min_rho,
122
+ )
123
+ depl_props = apply_dry_rock_pressure_sensitivity_model(
124
+ model=rock_matrix.pressure_sensitivity_model,
125
+ initial_eff_pressure=init_press,
126
+ depleted_eff_pressure=tmp_pres,
127
+ in_situ_dict=in_situ_dict,
128
+ mineral_properties=tmp_matrix,
129
+ cement_properties=rock_matrix.minerals[rock_matrix.cement],
130
+ )
131
+ k_dry = depl_props[ParameterTypes.K.value]
132
+ mu = depl_props[ParameterTypes.MU.value]
133
+
134
+ # Saturate rock
135
+ k_sat = gassmann(k_dry, tmp_por, tmp_fl_prop_k, tmp_min_k)
136
+ rho_dry = (1.0 - tmp_por) * tmp_min_rho
137
+ rho_sat = rho_dry + tmp_por * tmp_fl_prop_rho
138
+ vp, vs = velocity(k_sat, mu, rho_sat)[0:2]
139
+
140
+ # Restore original size and shape
141
+ vp, vs, rho_sat, k_dry, mu, rho_dry = reverse_filter_and_restore(
142
+ mask, vp, vs, rho_sat, k_dry, mu, rho_dry
81
143
  )
82
- vp, vs, rho = reverse_filter_and_restore(mask, vp, vs, rho)
83
- props = SaturatedRockProperties(vp=vp, vs=vs, dens=rho)
84
- saturated_props.append(props)
85
- return saturated_props
144
+ # Add results to list
145
+ saturated_props.append(SaturatedRockProperties(vp=vp, vs=vs, density=rho_sat))
146
+ dry_props.append(
147
+ DryRockProperties(
148
+ bulk_modulus=k_dry,
149
+ shear_modulus=mu,
150
+ density=(1.0 - tmp_por) * tmp_min_rho,
151
+ )
152
+ )
153
+
154
+ return saturated_props, dry_props
86
155
 
87
156
 
88
157
  def _verify_inputs(fl_prop, pres_prop):