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.
- fmu/pem/__init__.py +2 -0
- fmu/pem/__main__.py +72 -19
- fmu/pem/forward_models/pem_model.py +21 -26
- fmu/pem/pem_functions/__init__.py +2 -2
- fmu/pem/pem_functions/density.py +32 -38
- fmu/pem/pem_functions/effective_pressure.py +153 -49
- fmu/pem/pem_functions/estimate_saturated_rock.py +244 -52
- fmu/pem/pem_functions/fluid_properties.py +447 -245
- 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 +30 -10
- 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 +65 -8
- 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 +76 -50
- fmu/pem/pem_utilities/import_routines.py +57 -69
- fmu/pem/pem_utilities/pem_class_definitions.py +81 -23
- fmu/pem/pem_utilities/pem_config_validation.py +364 -172
- fmu/pem/pem_utilities/rpm_models.py +473 -100
- fmu/pem/pem_utilities/update_grid.py +3 -2
- fmu/pem/pem_utilities/utils.py +90 -38
- fmu/pem/run_pem.py +66 -48
- fmu/pem/version.py +16 -3
- {fmu_pem-0.0.2.dist-info → fmu_pem-0.0.4.dist-info}/METADATA +19 -11
- fmu_pem-0.0.4.dist-info/RECORD +39 -0
- {fmu_pem-0.0.2.dist-info → fmu_pem-0.0.4.dist-info}/WHEEL +1 -1
- fmu_pem-0.0.2.dist-info/RECORD +0 -37
- {fmu_pem-0.0.2.dist-info → fmu_pem-0.0.4.dist-info}/entry_points.txt +0 -0
- {fmu_pem-0.0.2.dist-info → fmu_pem-0.0.4.dist-info}/licenses/LICENSE +0 -0
- {fmu_pem-0.0.2.dist-info → fmu_pem-0.0.4.dist-info}/top_level.txt +0 -0
|
@@ -1,29 +1,33 @@
|
|
|
1
|
-
from typing import List, Union
|
|
2
|
-
|
|
3
1
|
import numpy as np
|
|
4
|
-
from rock_physics_open.
|
|
5
|
-
|
|
2
|
+
from rock_physics_open.equinor_utilities.std_functions import (
|
|
3
|
+
gassmann,
|
|
4
|
+
velocity,
|
|
6
5
|
)
|
|
6
|
+
from rock_physics_open.sandstone_models import patchy_cement_model_dry
|
|
7
7
|
|
|
8
8
|
from fmu.pem.pem_utilities import (
|
|
9
|
+
DryRockProperties,
|
|
9
10
|
EffectiveFluidProperties,
|
|
10
|
-
|
|
11
|
-
PemConfig,
|
|
11
|
+
EffectiveMineralProperties,
|
|
12
12
|
PressureProperties,
|
|
13
|
+
RockMatrixProperties,
|
|
13
14
|
SaturatedRockProperties,
|
|
14
15
|
filter_and_one_dim,
|
|
15
16
|
reverse_filter_and_restore,
|
|
16
17
|
)
|
|
18
|
+
from fmu.pem.pem_utilities.enum_defs import ParameterTypes
|
|
19
|
+
|
|
20
|
+
from .pressure_sensitivity import apply_dry_rock_pressure_sensitivity_model
|
|
17
21
|
|
|
18
22
|
|
|
19
23
|
def run_patchy_cement(
|
|
20
|
-
mineral:
|
|
21
|
-
fluid:
|
|
22
|
-
cement:
|
|
24
|
+
mineral: EffectiveMineralProperties,
|
|
25
|
+
fluid: list[EffectiveFluidProperties] | EffectiveFluidProperties,
|
|
26
|
+
cement: EffectiveMineralProperties,
|
|
23
27
|
porosity: np.ma.MaskedArray,
|
|
24
|
-
pressure:
|
|
25
|
-
|
|
26
|
-
) ->
|
|
28
|
+
pressure: list[PressureProperties] | PressureProperties,
|
|
29
|
+
rock_matrix_props: RockMatrixProperties,
|
|
30
|
+
) -> tuple[list[SaturatedRockProperties], list[DryRockProperties]]:
|
|
27
31
|
"""Prepare inputs and parameters for running the Patchy Cement model
|
|
28
32
|
|
|
29
33
|
Args:
|
|
@@ -32,19 +36,34 @@ def run_patchy_cement(
|
|
|
32
36
|
properties in a list
|
|
33
37
|
cement: cement properties containing k [Pa], mu [Pa] and rho [kg/m3]
|
|
34
38
|
porosity: porosity fraction
|
|
35
|
-
pressure: steps in effective pressure
|
|
36
|
-
|
|
39
|
+
pressure: steps in effective pressure, unit Pa
|
|
40
|
+
rock_matrix_props: parameters for the PEM
|
|
37
41
|
|
|
38
42
|
Returns:
|
|
39
43
|
saturated rock properties with vp [m/s], vs [m/s], density [kg/m^3], ai
|
|
40
44
|
(vp * density), si (vs * density), vpvs (vp / vs)
|
|
45
|
+
dry rock properties with bulk modulus [Pa], shear modulus [Pa] and density
|
|
46
|
+
[kg/m^3]
|
|
41
47
|
"""
|
|
42
48
|
# Mineral and porosity are assumed to be single objects, fluid and
|
|
43
49
|
# effective_pressure can be lists
|
|
44
50
|
fluid, pressure = _verify_inputs(fluid, pressure)
|
|
51
|
+
|
|
52
|
+
# Calculate depletion from the initial effective pressure
|
|
53
|
+
initial_effective_pressure = pressure[0].effective_pressure
|
|
54
|
+
# Container for saturated properties
|
|
45
55
|
saturated_props = []
|
|
46
|
-
|
|
47
|
-
|
|
56
|
+
dry_props = []
|
|
57
|
+
|
|
58
|
+
# to please the IDE:
|
|
59
|
+
k_dry = None
|
|
60
|
+
mu = None
|
|
61
|
+
rho_dry = None
|
|
62
|
+
k_init = None
|
|
63
|
+
mu_init = None
|
|
64
|
+
|
|
65
|
+
pat_cem_params = rock_matrix_props.model.parameters
|
|
66
|
+
for time_step, (fl_prop, pres) in enumerate(zip(fluid, pressure)):
|
|
48
67
|
(
|
|
49
68
|
mask,
|
|
50
69
|
tmp_min_k,
|
|
@@ -57,45 +76,88 @@ def run_patchy_cement(
|
|
|
57
76
|
tmp_fl_prop_rho,
|
|
58
77
|
tmp_por,
|
|
59
78
|
tmp_pres,
|
|
79
|
+
init_pres,
|
|
60
80
|
) = filter_and_one_dim(
|
|
61
81
|
mineral.bulk_modulus,
|
|
62
82
|
mineral.shear_modulus,
|
|
63
|
-
mineral.
|
|
83
|
+
mineral.density,
|
|
64
84
|
cement.bulk_modulus,
|
|
65
85
|
cement.shear_modulus,
|
|
66
|
-
cement.
|
|
86
|
+
cement.density,
|
|
67
87
|
fl_prop.bulk_modulus,
|
|
68
|
-
fl_prop.
|
|
88
|
+
fl_prop.density,
|
|
69
89
|
porosity,
|
|
70
|
-
pres.effective_pressure
|
|
90
|
+
pres.effective_pressure,
|
|
91
|
+
initial_effective_pressure,
|
|
71
92
|
return_numpy_array=True,
|
|
72
93
|
)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
+
# At initial pressure, there is no need to estimate pressure effect on dry rock.
|
|
95
|
+
# If there is no pressure sensitivity, we use the initial pressure for the dry
|
|
96
|
+
# rock also after start of production, and the only differences will be due to
|
|
97
|
+
# changes in fluid properties or saturation
|
|
98
|
+
if time_step == 0:
|
|
99
|
+
k_dry, mu, rho_dry = patchy_cement_model_dry(
|
|
100
|
+
tmp_min_k,
|
|
101
|
+
tmp_min_mu,
|
|
102
|
+
tmp_min_rho,
|
|
103
|
+
tmp_cem_k,
|
|
104
|
+
tmp_cem_mu,
|
|
105
|
+
tmp_cem_rho,
|
|
106
|
+
tmp_por,
|
|
107
|
+
tmp_pres,
|
|
108
|
+
pat_cem_params.cement_fraction,
|
|
109
|
+
pat_cem_params.critical_porosity,
|
|
110
|
+
pat_cem_params.coordination_number_function,
|
|
111
|
+
pat_cem_params.coord_num,
|
|
112
|
+
pat_cem_params.shear_reduction,
|
|
113
|
+
)
|
|
114
|
+
# For use at depleted pressure
|
|
115
|
+
k_init = k_dry
|
|
116
|
+
mu_init = mu
|
|
117
|
+
if time_step > 0 and rock_matrix_props.pressure_sensitivity:
|
|
118
|
+
# estimate the properties for the initial pressure by friable model,
|
|
119
|
+
# then apply correction for depletion
|
|
120
|
+
|
|
121
|
+
# Prepare in situ properties
|
|
122
|
+
in_situ_dict = {
|
|
123
|
+
ParameterTypes.K.value: k_init,
|
|
124
|
+
ParameterTypes.MU.value: mu_init,
|
|
125
|
+
ParameterTypes.RHO.value: tmp_min_rho,
|
|
126
|
+
ParameterTypes.POROSITY.value: tmp_por,
|
|
127
|
+
}
|
|
128
|
+
tmp_matrix = EffectiveMineralProperties(
|
|
129
|
+
bulk_modulus=tmp_min_k,
|
|
130
|
+
shear_modulus=tmp_min_mu,
|
|
131
|
+
density=tmp_min_rho,
|
|
132
|
+
)
|
|
133
|
+
depl_props = apply_dry_rock_pressure_sensitivity_model(
|
|
134
|
+
model=rock_matrix_props.pressure_sensitivity_model,
|
|
135
|
+
initial_eff_pressure=init_pres,
|
|
136
|
+
depleted_eff_pressure=tmp_pres,
|
|
137
|
+
in_situ_dict=in_situ_dict,
|
|
138
|
+
mineral_properties=tmp_matrix,
|
|
139
|
+
cement_properties=rock_matrix_props.minerals[rock_matrix_props.cement],
|
|
140
|
+
)
|
|
141
|
+
k_dry = depl_props[ParameterTypes.K.value]
|
|
142
|
+
mu = depl_props[ParameterTypes.MU.value]
|
|
143
|
+
|
|
144
|
+
# Saturate rock
|
|
145
|
+
k_sat = gassmann(k_dry, tmp_por, tmp_fl_prop_k, tmp_min_k)
|
|
146
|
+
rho_sat = rho_dry + tmp_por * tmp_fl_prop_rho
|
|
147
|
+
vp, vs = velocity(k_sat, mu, rho_sat)[0:2]
|
|
148
|
+
|
|
149
|
+
vp, vs, rho_sat, k_dry, mu, rho_dry = reverse_filter_and_restore(
|
|
150
|
+
mask, vp, vs, rho_sat, k_dry, mu, rho_dry
|
|
151
|
+
)
|
|
152
|
+
saturated_props.append(SaturatedRockProperties(vp=vp, vs=vs, density=rho_sat))
|
|
153
|
+
dry_props.append(
|
|
154
|
+
DryRockProperties(
|
|
155
|
+
bulk_modulus=k_dry,
|
|
156
|
+
shear_modulus=mu,
|
|
157
|
+
density=rho_dry,
|
|
158
|
+
)
|
|
94
159
|
)
|
|
95
|
-
|
|
96
|
-
props = SaturatedRockProperties(vp=vp, vs=vs, dens=rho)
|
|
97
|
-
saturated_props.append(props)
|
|
98
|
-
return saturated_props
|
|
160
|
+
return saturated_props, dry_props
|
|
99
161
|
|
|
100
162
|
|
|
101
163
|
def _verify_inputs(fl_prop, pres_prop):
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
|
-
from typing import List, Union
|
|
3
2
|
|
|
4
3
|
import numpy as np
|
|
5
4
|
from rock_physics_open.t_matrix_models import (
|
|
@@ -9,10 +8,11 @@ from rock_physics_open.t_matrix_models import (
|
|
|
9
8
|
)
|
|
10
9
|
|
|
11
10
|
from fmu.pem.pem_utilities import (
|
|
11
|
+
DryRockProperties,
|
|
12
12
|
EffectiveFluidProperties,
|
|
13
|
-
|
|
14
|
-
PemConfig,
|
|
13
|
+
EffectiveMineralProperties,
|
|
15
14
|
PressureProperties,
|
|
15
|
+
RockMatrixProperties,
|
|
16
16
|
SaturatedRockProperties,
|
|
17
17
|
filter_and_one_dim,
|
|
18
18
|
reverse_filter_and_restore,
|
|
@@ -21,18 +21,19 @@ from fmu.pem.pem_utilities import (
|
|
|
21
21
|
from .run_patchy_cement_model import _verify_inputs
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
def
|
|
25
|
-
mineral_properties:
|
|
26
|
-
fluid_properties:
|
|
24
|
+
def run_t_matrix_model(
|
|
25
|
+
mineral_properties: EffectiveMineralProperties,
|
|
26
|
+
fluid_properties: list[EffectiveFluidProperties] | EffectiveFluidProperties,
|
|
27
27
|
porosity: np.ma.MaskedArray,
|
|
28
|
-
vsh:
|
|
29
|
-
pressure:
|
|
30
|
-
|
|
28
|
+
vsh: None | np.ma.MaskedArray,
|
|
29
|
+
pressure: list[PressureProperties] | PressureProperties,
|
|
30
|
+
rock_matrix: RockMatrixProperties,
|
|
31
|
+
model_directory: Path,
|
|
31
32
|
petec_parameter_file: Path = Path("t_mat_params_petec.pkl"),
|
|
32
33
|
exp_parameter_file: Path = Path("t_mat_params_exp.pkl"),
|
|
33
34
|
pres_model_vp: Path = Path("carbonate_pressure_model_vp_exp.pkl"),
|
|
34
35
|
pres_model_vs: Path = Path("carbonate_pressure_model_vs_exp.pkl"),
|
|
35
|
-
) ->
|
|
36
|
+
) -> tuple[list[SaturatedRockProperties], list[DryRockProperties]]:
|
|
36
37
|
"""Model for carbonate rock with possibility to estimate changes due to
|
|
37
38
|
production, i.e., saturation changes, changes in the fluids due to pore pressure
|
|
38
39
|
change and also changes in the properties of the matrix by increase in effective
|
|
@@ -40,11 +41,21 @@ def run_t_matrix_and_pressure_models(
|
|
|
40
41
|
|
|
41
42
|
The first timestep is regarded as in situ conditions for the pressure
|
|
42
43
|
substitution, any later timestep also takes into account the changes in effective
|
|
43
|
-
pressure from the initial one.
|
|
44
|
+
pressure from the initial one. Pressure sensitivity can be deselected in the
|
|
45
|
+
configuration of the PEM.
|
|
44
46
|
|
|
45
47
|
Calibration of parameters for the T-Matrix model must be made before running the
|
|
46
48
|
forward model, this is only possible in RokDoc with 1D match to logs.
|
|
47
49
|
|
|
50
|
+
Notice that t-matrix differs from the other saturated rock physics models in that
|
|
51
|
+
there is no intermediate step for dry rock properties. For this reason, the pressure
|
|
52
|
+
sensitive model is fixed, as this is a model that is adapted to saturated carbonate
|
|
53
|
+
rocks. This model can be overridden by saving an alternative model with the same
|
|
54
|
+
format as the default ones.
|
|
55
|
+
|
|
56
|
+
To comply with other functions for saturated rock properties, we also return
|
|
57
|
+
dry rock properties, but for the time being, the values are set to NaN.
|
|
58
|
+
|
|
48
59
|
Args:
|
|
49
60
|
mineral_properties: bulk modulus (k) [Pa], shear modulus (mu) [Pa],
|
|
50
61
|
density [kg/m^3]
|
|
@@ -53,7 +64,8 @@ def run_t_matrix_and_pressure_models(
|
|
|
53
64
|
porosity: porosity [fraction]
|
|
54
65
|
vsh: shale volume [fraction]
|
|
55
66
|
pressure: overburden, effective and formation (pore) pressure per restart date
|
|
56
|
-
|
|
67
|
+
rock_matrix: rock matrix properties
|
|
68
|
+
model_directory: folder for model files
|
|
57
69
|
petec_parameter_file: additional parameters for the T-Matrix model, determined
|
|
58
70
|
through optimisation to well logs
|
|
59
71
|
exp_parameter_file: additional parameters for the T-Matrix model, determined
|
|
@@ -64,16 +76,18 @@ def run_t_matrix_and_pressure_models(
|
|
|
64
76
|
Returns:
|
|
65
77
|
saturated rock properties with vp [m/s], vs [m/s], density [kg/m^3],
|
|
66
78
|
ai (vp * density), si (vs * density), vpvs (vp / vs)
|
|
79
|
+
dry rock properties with values set to NaN
|
|
67
80
|
"""
|
|
68
81
|
fluid_properties, pressure = _verify_inputs(fluid_properties, pressure)
|
|
69
82
|
|
|
70
83
|
# All model files are gathered with the config file for the PEM model,
|
|
71
84
|
# i.e. in ../sim2seis/model
|
|
72
|
-
petec_parameter_file =
|
|
73
|
-
exp_parameter_file =
|
|
85
|
+
petec_parameter_file = model_directory / petec_parameter_file
|
|
86
|
+
exp_parameter_file = model_directory / exp_parameter_file
|
|
74
87
|
|
|
75
88
|
saturated_props = []
|
|
76
|
-
|
|
89
|
+
dry_props = []
|
|
90
|
+
t_mat_params = rock_matrix.model.parameters
|
|
77
91
|
|
|
78
92
|
if vsh is None and t_mat_params.t_mat_model_version == "EXP":
|
|
79
93
|
raise ValueError("Shale volume must be provided for EXP model")
|
|
@@ -83,13 +97,13 @@ def run_t_matrix_and_pressure_models(
|
|
|
83
97
|
vsh = np.ma.array(
|
|
84
98
|
np.zeros_like(porosity), mask=np.zeros_like(porosity).astype(bool)
|
|
85
99
|
)
|
|
86
|
-
#
|
|
87
|
-
pres_ovb = pressure[0].overburden_pressure
|
|
88
|
-
pres_form = pressure[0].formation_pressure
|
|
100
|
+
# Pressures for initial conditions
|
|
101
|
+
pres_ovb = pressure[0].overburden_pressure
|
|
102
|
+
pres_form = pressure[0].formation_pressure
|
|
89
103
|
|
|
90
104
|
for time_step, fl_prop in enumerate(fluid_properties):
|
|
91
105
|
if time_step > 0:
|
|
92
|
-
pres_depl = pressure[time_step].formation_pressure
|
|
106
|
+
pres_depl = pressure[time_step].formation_pressure
|
|
93
107
|
(
|
|
94
108
|
mask,
|
|
95
109
|
tmp_min_k,
|
|
@@ -105,9 +119,9 @@ def run_t_matrix_and_pressure_models(
|
|
|
105
119
|
) = filter_and_one_dim(
|
|
106
120
|
mineral_properties.bulk_modulus,
|
|
107
121
|
mineral_properties.shear_modulus,
|
|
108
|
-
mineral_properties.
|
|
122
|
+
mineral_properties.density,
|
|
109
123
|
fl_prop.bulk_modulus,
|
|
110
|
-
fl_prop.
|
|
124
|
+
fl_prop.density,
|
|
111
125
|
porosity,
|
|
112
126
|
vsh,
|
|
113
127
|
pres_ovb,
|
|
@@ -128,9 +142,9 @@ def run_t_matrix_and_pressure_models(
|
|
|
128
142
|
) = filter_and_one_dim(
|
|
129
143
|
mineral_properties.bulk_modulus,
|
|
130
144
|
mineral_properties.shear_modulus,
|
|
131
|
-
mineral_properties.
|
|
145
|
+
mineral_properties.density,
|
|
132
146
|
fl_prop.bulk_modulus,
|
|
133
|
-
fl_prop.
|
|
147
|
+
fl_prop.density,
|
|
134
148
|
porosity,
|
|
135
149
|
vsh,
|
|
136
150
|
)
|
|
@@ -162,7 +176,7 @@ def run_t_matrix_and_pressure_models(
|
|
|
162
176
|
t_mat_params.freq,
|
|
163
177
|
str(exp_parameter_file),
|
|
164
178
|
)
|
|
165
|
-
if time_step > 0:
|
|
179
|
+
if time_step > 0 and rock_matrix.pressure_sensitivity:
|
|
166
180
|
vp, vs, rho, _, _ = carbonate_pressure_model(
|
|
167
181
|
tmp_fl_rho,
|
|
168
182
|
vp,
|
|
@@ -177,10 +191,17 @@ def run_t_matrix_and_pressure_models(
|
|
|
177
191
|
tmp_pres_depl,
|
|
178
192
|
pres_model_vp,
|
|
179
193
|
pres_model_vs,
|
|
180
|
-
|
|
194
|
+
model_directory.absolute(),
|
|
181
195
|
False,
|
|
182
196
|
)
|
|
183
197
|
vp, vs, rho = reverse_filter_and_restore(mask, vp, vs, rho)
|
|
184
|
-
props = SaturatedRockProperties(vp=vp, vs=vs,
|
|
198
|
+
props = SaturatedRockProperties(vp=vp, vs=vs, density=rho)
|
|
185
199
|
saturated_props.append(props)
|
|
186
|
-
|
|
200
|
+
dry_props.append(
|
|
201
|
+
DryRockProperties(
|
|
202
|
+
bulk_modulus=np.full_like(vp, np.nan),
|
|
203
|
+
shear_modulus=np.full_like(vp, np.nan),
|
|
204
|
+
density=np.full_like(vp, np.nan),
|
|
205
|
+
)
|
|
206
|
+
)
|
|
207
|
+
return saturated_props, dry_props
|
|
@@ -4,39 +4,57 @@ from .delta_cumsum_time import (
|
|
|
4
4
|
estimate_sum_delta_time,
|
|
5
5
|
)
|
|
6
6
|
from .export_routines import save_results
|
|
7
|
+
from .fipnum_pvtnum_utilities import (
|
|
8
|
+
detect_overlaps,
|
|
9
|
+
input_num_string_to_list,
|
|
10
|
+
missing_num_areas,
|
|
11
|
+
num_boolean_array,
|
|
12
|
+
validate_zone_coverage,
|
|
13
|
+
)
|
|
7
14
|
from .import_config import get_global_params_and_dates, read_pem_config
|
|
8
15
|
from .import_routines import (
|
|
9
16
|
import_fractions,
|
|
10
|
-
read_geogrid,
|
|
11
|
-
read_ntg_grid,
|
|
12
17
|
read_sim_grid_props,
|
|
13
18
|
)
|
|
14
19
|
from .pem_class_definitions import (
|
|
15
20
|
DryRockProperties,
|
|
16
21
|
EffectiveFluidProperties,
|
|
17
|
-
|
|
22
|
+
EffectiveMineralProperties,
|
|
18
23
|
PressureProperties,
|
|
19
24
|
SaturatedRockProperties,
|
|
20
25
|
SimInitProperties,
|
|
21
26
|
SimRstProperties,
|
|
22
27
|
)
|
|
23
|
-
from .pem_config_validation import
|
|
28
|
+
from .pem_config_validation import (
|
|
29
|
+
Fluids,
|
|
30
|
+
MineralProperties,
|
|
31
|
+
PemConfig,
|
|
32
|
+
RockMatrixProperties,
|
|
33
|
+
)
|
|
24
34
|
from .update_grid import update_inactive_grid_cells
|
|
25
35
|
from .utils import (
|
|
36
|
+
bar_to_pa,
|
|
26
37
|
estimate_cement,
|
|
27
38
|
filter_and_one_dim,
|
|
39
|
+
get_masked_array_mask,
|
|
28
40
|
get_shale_fraction,
|
|
29
|
-
|
|
41
|
+
pa_to_bar,
|
|
30
42
|
restore_dir,
|
|
31
43
|
reverse_filter_and_restore,
|
|
44
|
+
set_mask,
|
|
32
45
|
to_masked_array,
|
|
33
46
|
update_dict_list,
|
|
34
47
|
)
|
|
35
48
|
|
|
36
49
|
__all__ = [
|
|
37
50
|
"PemConfig",
|
|
51
|
+
"RockMatrixProperties",
|
|
52
|
+
"MineralProperties",
|
|
38
53
|
"Fluids",
|
|
54
|
+
"bar_to_pa",
|
|
55
|
+
"pa_to_bar",
|
|
39
56
|
"calculate_diff_properties",
|
|
57
|
+
"detect_overlaps",
|
|
40
58
|
"estimate_cement",
|
|
41
59
|
"estimate_sum_delta_time",
|
|
42
60
|
"estimate_delta_time",
|
|
@@ -44,21 +62,23 @@ __all__ = [
|
|
|
44
62
|
"get_global_params_and_dates",
|
|
45
63
|
"get_shale_fraction",
|
|
46
64
|
"import_fractions",
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"read_ntg_grid",
|
|
65
|
+
"input_num_string_to_list",
|
|
66
|
+
"missing_num_areas",
|
|
67
|
+
"num_boolean_array",
|
|
51
68
|
"read_pem_config",
|
|
52
69
|
"read_sim_grid_props",
|
|
53
70
|
"restore_dir",
|
|
54
71
|
"reverse_filter_and_restore",
|
|
55
72
|
"save_results",
|
|
56
73
|
"to_masked_array",
|
|
74
|
+
"get_masked_array_mask",
|
|
75
|
+
"set_mask",
|
|
57
76
|
"update_dict_list",
|
|
58
77
|
"update_inactive_grid_cells",
|
|
78
|
+
"validate_zone_coverage",
|
|
59
79
|
"DryRockProperties",
|
|
60
80
|
"EffectiveFluidProperties",
|
|
61
|
-
"
|
|
81
|
+
"EffectiveMineralProperties",
|
|
62
82
|
"PressureProperties",
|
|
63
83
|
"SaturatedRockProperties",
|
|
64
84
|
"SimInitProperties",
|
|
@@ -1,19 +1,29 @@
|
|
|
1
1
|
from dataclasses import asdict
|
|
2
|
-
from typing import Tuple
|
|
3
2
|
|
|
4
|
-
from .
|
|
3
|
+
from .enum_defs import DifferenceAttribute, DifferenceMethod
|
|
5
4
|
|
|
6
5
|
|
|
7
|
-
def calculate_diff_properties(
|
|
6
|
+
def calculate_diff_properties(
|
|
7
|
+
props: list,
|
|
8
|
+
diff_dates: list[list[str]],
|
|
9
|
+
seis_dates: list[str],
|
|
10
|
+
diff_calculation: dict[DifferenceAttribute, list[DifferenceMethod]],
|
|
11
|
+
) -> tuple[list, list]:
|
|
8
12
|
"""
|
|
9
13
|
Function to calculate difference attributes between grid properties
|
|
10
14
|
|
|
11
|
-
:
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
Args:
|
|
16
|
+
props: grid properties
|
|
17
|
+
diff_dates: list of simulation model dates for difference calculation
|
|
18
|
+
seis_dates: list of simulation model dates
|
|
19
|
+
diff_calculation: dictionary of difference calculation attributes and methods
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
diff_prop: difference properties
|
|
23
|
+
date_str: formatted string for difference dates
|
|
14
24
|
"""
|
|
15
|
-
_verify_diff_inputs(props,
|
|
16
|
-
props = _filter_diff_inputs(props,
|
|
25
|
+
_verify_diff_inputs(props, seis_dates, diff_dates)
|
|
26
|
+
props = _filter_diff_inputs(props, diff_calculation)
|
|
17
27
|
|
|
18
28
|
def diff(x, y):
|
|
19
29
|
return x - y
|
|
@@ -24,21 +34,16 @@ def calculate_diff_properties(props: list, conf_params: PemConfig) -> Tuple[list
|
|
|
24
34
|
def ratio(x, y):
|
|
25
35
|
return x / y
|
|
26
36
|
|
|
27
|
-
lookup = dict(
|
|
28
|
-
zip(
|
|
29
|
-
conf_params.global_params.seis_dates, # type: ignore
|
|
30
|
-
range(len(conf_params.global_params.seis_dates)), # type: ignore
|
|
31
|
-
)
|
|
32
|
-
)
|
|
37
|
+
lookup = dict(zip(seis_dates, range(len(seis_dates))))
|
|
33
38
|
date_str = []
|
|
34
39
|
diff_prop = []
|
|
35
40
|
# Need to iterate over the lists in props, which contain the properties
|
|
36
41
|
# for each date
|
|
37
|
-
for monitor, base in
|
|
42
|
+
for monitor, base in diff_dates: # type: ignore
|
|
38
43
|
tmp_dict = {}
|
|
39
44
|
for k, v_base in props[lookup[base]].items():
|
|
40
|
-
if k
|
|
41
|
-
operations =
|
|
45
|
+
if k in diff_calculation:
|
|
46
|
+
operations = diff_calculation[k]
|
|
42
47
|
v_monitor = props[lookup[monitor]][k]
|
|
43
48
|
for op in operations:
|
|
44
49
|
if op in locals():
|
|
@@ -54,7 +59,7 @@ def calculate_diff_properties(props: list, conf_params: PemConfig) -> Tuple[list
|
|
|
54
59
|
return diff_prop, date_str
|
|
55
60
|
|
|
56
61
|
|
|
57
|
-
def _verify_diff_inputs(prop_set,
|
|
62
|
+
def _verify_diff_inputs(prop_set, seis_dates, diff_dates):
|
|
58
63
|
if not isinstance(prop_set, list):
|
|
59
64
|
raise ValueError(
|
|
60
65
|
f"{__file__}: input grid properties must be contained in a list "
|
|
@@ -62,15 +67,13 @@ def _verify_diff_inputs(prop_set, conf):
|
|
|
62
67
|
f"date in the inner lists"
|
|
63
68
|
)
|
|
64
69
|
for prop_list in prop_set:
|
|
65
|
-
if len(prop_list) != len(
|
|
70
|
+
if len(prop_list) != len(seis_dates):
|
|
66
71
|
raise ValueError(
|
|
67
72
|
f"{__file__}: mismatch between property sets and "
|
|
68
73
|
f"simulation model dates: "
|
|
69
|
-
f"{len(prop_list)} vs. {len(
|
|
74
|
+
f"{len(prop_list)} vs. {len(seis_dates)}"
|
|
70
75
|
)
|
|
71
|
-
if not {a for ll in
|
|
72
|
-
set(conf.global_params.seis_dates)
|
|
73
|
-
):
|
|
76
|
+
if not {a for ll in diff_dates for a in ll}.issubset(set(seis_dates)):
|
|
74
77
|
raise ValueError(
|
|
75
78
|
f"{__file__}: trying to take difference between dates not saved from "
|
|
76
79
|
f"simulation model"
|
|
@@ -78,27 +81,16 @@ def _verify_diff_inputs(prop_set, conf):
|
|
|
78
81
|
return
|
|
79
82
|
|
|
80
83
|
|
|
81
|
-
def _filter_diff_inputs(prop_list_list,
|
|
84
|
+
def _filter_diff_inputs(prop_list_list, diff_calculation):
|
|
82
85
|
# Filter out the properties that are not in the diff_calculation list.
|
|
83
86
|
# Keep the time-step order in the list
|
|
84
87
|
return_list = [{} for _ in range(len(prop_list_list[0]))]
|
|
85
88
|
for prop_list in prop_list_list:
|
|
86
89
|
for i, prop_set in enumerate(prop_list):
|
|
87
90
|
tmp_dict = {
|
|
88
|
-
k: v
|
|
89
|
-
for k, v in asdict(prop_set).items()
|
|
90
|
-
if k.upper() in conf.diff_calculation
|
|
91
|
+
k: v for k, v in asdict(prop_set).items() if k in diff_calculation
|
|
91
92
|
}
|
|
92
93
|
if tmp_dict:
|
|
93
94
|
return_list[i].update(tmp_dict)
|
|
94
|
-
|
|
95
|
-
raise ValueError(
|
|
96
|
-
f"{__file__}: unable to calculate cumsum values, global "
|
|
97
|
-
f"settings are missing"
|
|
98
|
-
)
|
|
99
|
-
if conf.global_params.seis_dates is None:
|
|
100
|
-
raise ValueError(
|
|
101
|
-
f"{__file__}: unable to calculate cumsum values, global "
|
|
102
|
-
f"settings seismic dates are missing"
|
|
103
|
-
)
|
|
95
|
+
|
|
104
96
|
return return_list
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Dict, List, Union
|
|
2
|
-
|
|
3
1
|
import numpy as np
|
|
4
2
|
|
|
5
3
|
from .pem_class_definitions import (
|
|
@@ -7,12 +5,11 @@ from .pem_class_definitions import (
|
|
|
7
5
|
SimInitProperties,
|
|
8
6
|
TwoWayTime,
|
|
9
7
|
)
|
|
10
|
-
from .pem_config_validation import PemConfig
|
|
11
8
|
|
|
12
9
|
|
|
13
10
|
def estimate_delta_time(
|
|
14
11
|
delta_z: np.ma.MaskedArray, vp: np.ma.MaskedArray, vs: np.ma.MaskedArray
|
|
15
|
-
) ->
|
|
12
|
+
) -> dict[str, np.ma.MaskedArray]:
|
|
16
13
|
"""Estimate seismic TWT parameters - PP, PS, SS modes
|
|
17
14
|
|
|
18
15
|
Args:
|
|
@@ -29,7 +26,7 @@ def estimate_delta_time(
|
|
|
29
26
|
return {"twtpp": dt_pp, "twtss": dt_ss, "twtps": (dt_pp + dt_ss) / 2.0}
|
|
30
27
|
|
|
31
28
|
|
|
32
|
-
def _verify_delta_t(arrays:
|
|
29
|
+
def _verify_delta_t(arrays: list[np.ma.MaskedArray]) -> None:
|
|
33
30
|
for arr in arrays:
|
|
34
31
|
if not isinstance(arr, np.ma.MaskedArray):
|
|
35
32
|
raise TypeError(
|
|
@@ -45,8 +42,8 @@ def _verify_delta_t(arrays: List[np.ma.MaskedArray]) -> None:
|
|
|
45
42
|
|
|
46
43
|
|
|
47
44
|
def calculate_time_cumsum(
|
|
48
|
-
props:
|
|
49
|
-
) -> list[
|
|
45
|
+
props: list | dict,
|
|
46
|
+
) -> list[dict[str, np.ma.MaskedArray]]:
|
|
50
47
|
"""
|
|
51
48
|
Function to calculate cumulative sum of time difference properties
|
|
52
49
|
|
|
@@ -81,15 +78,13 @@ def _verify_cumsum_inputs(input_set):
|
|
|
81
78
|
|
|
82
79
|
def estimate_sum_delta_time(
|
|
83
80
|
constant_props: SimInitProperties,
|
|
84
|
-
sat_rock_props:
|
|
85
|
-
|
|
86
|
-
) -> List[TwoWayTime]:
|
|
81
|
+
sat_rock_props: list[SaturatedRockProperties],
|
|
82
|
+
) -> list[TwoWayTime]:
|
|
87
83
|
"""Calculate TWT (two-way-time) for seismic signal for each restart date
|
|
88
84
|
|
|
89
85
|
Args:
|
|
90
86
|
constant_props: constant properties, here the delta Z property of the eclipse
|
|
91
|
-
grid is used
|
|
92
|
-
restart date
|
|
87
|
+
grid is used
|
|
93
88
|
sat_rock_props: effective properties for the saturated rock per restart date
|
|
94
89
|
config: configuration parameters
|
|
95
90
|
|
|
@@ -100,5 +95,5 @@ def estimate_sum_delta_time(
|
|
|
100
95
|
estimate_delta_time(constant_props.delta_z, sat_rock.vp, sat_rock.vs)
|
|
101
96
|
for sat_rock in sat_rock_props
|
|
102
97
|
]
|
|
103
|
-
cum_time_list = calculate_time_cumsum(delta_time
|
|
98
|
+
cum_time_list = calculate_time_cumsum(delta_time)
|
|
104
99
|
return [TwoWayTime(**time_set) for time_set in cum_time_list]
|