fmu-pem 0.0.1__py3-none-any.whl → 0.0.3__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.
- fmu/pem/__main__.py +32 -16
- fmu/pem/forward_models/pem_model.py +19 -27
- fmu/pem/pem_functions/__init__.py +2 -2
- fmu/pem/pem_functions/density.py +32 -38
- fmu/pem/pem_functions/effective_pressure.py +153 -48
- fmu/pem/pem_functions/estimate_saturated_rock.py +244 -52
- fmu/pem/pem_functions/fluid_properties.py +453 -246
- fmu/pem/pem_functions/mineral_properties.py +77 -74
- fmu/pem/pem_functions/pressure_sensitivity.py +430 -0
- fmu/pem/pem_functions/regression_models.py +129 -97
- fmu/pem/pem_functions/run_friable_model.py +106 -37
- fmu/pem/pem_functions/run_patchy_cement_model.py +107 -45
- fmu/pem/pem_functions/{run_t_matrix_and_pressure.py → run_t_matrix_model.py} +48 -27
- fmu/pem/pem_utilities/__init__.py +31 -9
- fmu/pem/pem_utilities/cumsum_properties.py +29 -37
- fmu/pem/pem_utilities/delta_cumsum_time.py +8 -13
- fmu/pem/pem_utilities/enum_defs.py +77 -4
- fmu/pem/pem_utilities/export_routines.py +84 -72
- fmu/pem/pem_utilities/fipnum_pvtnum_utilities.py +217 -0
- fmu/pem/pem_utilities/import_config.py +64 -46
- fmu/pem/pem_utilities/import_routines.py +58 -69
- fmu/pem/pem_utilities/pem_class_definitions.py +81 -23
- fmu/pem/pem_utilities/pem_config_validation.py +374 -149
- fmu/pem/pem_utilities/rpm_models.py +481 -83
- fmu/pem/pem_utilities/update_grid.py +3 -2
- fmu/pem/pem_utilities/utils.py +90 -38
- fmu/pem/run_pem.py +70 -39
- fmu/pem/version.py +16 -3
- {fmu_pem-0.0.1.dist-info → fmu_pem-0.0.3.dist-info}/METADATA +33 -28
- fmu_pem-0.0.3.dist-info/RECORD +39 -0
- fmu_pem-0.0.1.dist-info/RECORD +0 -37
- {fmu_pem-0.0.1.dist-info → fmu_pem-0.0.3.dist-info}/WHEEL +0 -0
- {fmu_pem-0.0.1.dist-info → fmu_pem-0.0.3.dist-info}/entry_points.txt +0 -0
- {fmu_pem-0.0.1.dist-info → fmu_pem-0.0.3.dist-info}/licenses/LICENSE +0 -0
- {fmu_pem-0.0.1.dist-info → fmu_pem-0.0.3.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
|
-
|
|
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
|
|
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
|
|
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]
|
|
56
|
-
rho_min: npt.NDArray[np.float64]
|
|
62
|
+
porosity: npt.NDArray[np.float64],
|
|
63
|
+
rho_min: npt.NDArray[np.float64],
|
|
57
64
|
params: VpVsRegressionParams | KMuRegressionParams,
|
|
58
|
-
) ->
|
|
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.
|
|
76
|
-
#
|
|
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
|
|
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
|
-
|
|
110
|
+
matrix: EffectiveMineralProperties,
|
|
108
111
|
fluid_properties: list[EffectiveFluidProperties],
|
|
109
112
|
porosity: np.ma.MaskedArray,
|
|
110
113
|
pressure: list[PressureProperties],
|
|
111
|
-
|
|
112
|
-
vsh:
|
|
113
|
-
|
|
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
|
-
|
|
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:
|
|
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:
|
|
125
|
-
|
|
126
|
-
|
|
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
|
-
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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
|
-
|
|
156
|
-
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
171
|
+
matrix.bulk_modulus,
|
|
172
|
+
matrix.shear_modulus,
|
|
173
|
+
matrix.density,
|
|
173
174
|
fl_prop.bulk_modulus,
|
|
174
|
-
fl_prop.
|
|
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
|
-
|
|
194
|
-
|
|
195
|
-
|
|
194
|
+
matrix.bulk_modulus,
|
|
195
|
+
matrix.shear_modulus,
|
|
196
|
+
matrix.density,
|
|
196
197
|
fl_prop.bulk_modulus,
|
|
197
|
-
fl_prop.
|
|
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
|
-
|
|
203
|
-
tmp_por, tmp_min_rho,
|
|
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
|
-
|
|
207
|
-
tmp_por, tmp_min_rho,
|
|
208
|
-
)
|
|
209
|
-
dry_props_shale = dry_rock_regression(
|
|
210
|
-
tmp_por, tmp_min_rho, config.rock_matrix.rpm.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
|
-
|
|
213
|
-
|
|
212
|
+
k_shale, mu_shale, rho_shale = dry_rock_regression(
|
|
213
|
+
tmp_por, tmp_min_rho, rock_matrix.model.parameters.shale
|
|
214
214
|
)
|
|
215
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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:
|
|
20
|
-
fluid:
|
|
28
|
+
mineral: EffectiveMineralProperties,
|
|
29
|
+
fluid: list[EffectiveFluidProperties] | EffectiveFluidProperties,
|
|
21
30
|
porosity: np.ma.MaskedArray,
|
|
22
|
-
pressure:
|
|
23
|
-
|
|
24
|
-
) ->
|
|
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
|
|
34
|
-
|
|
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
|
-
|
|
45
|
-
|
|
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.
|
|
81
|
+
mineral.density,
|
|
59
82
|
fl_prop.bulk_modulus,
|
|
60
|
-
fl_prop.
|
|
83
|
+
fl_prop.density,
|
|
61
84
|
porosity,
|
|
62
|
-
pres.effective_pressure
|
|
85
|
+
pres.effective_pressure,
|
|
86
|
+
initial_effective_pressure,
|
|
87
|
+
return_numpy_array=True,
|
|
63
88
|
)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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):
|