fmu-pem 0.0.1__py3-none-any.whl → 0.0.2__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.
@@ -35,7 +35,7 @@ def estimate_bulk_density(
35
35
  Raises:
36
36
  ValueError: If fluid_props is an empty list.
37
37
  """
38
- if config.rock_matrix.rpm == PatchyCementRPM:
38
+ if isinstance(config.rock_matrix.model, PatchyCementRPM):
39
39
  # Get cement mineral properties
40
40
  cement_mineral = config.rock_matrix.cement
41
41
  mineral = config.rock_matrix.minerals[cement_mineral]
@@ -44,7 +44,7 @@ def estimate_bulk_density(
44
44
  mineral.bulk_modulus, mineral.shear_modulus, mineral.density, init_prop.poro
45
45
  )
46
46
  rel_frac_cem = (
47
- config.rock_matrix.rpm.parameters.cement_fraction / init_prop.poro
47
+ config.rock_matrix.model.parameters.cement_fraction / init_prop.poro
48
48
  )
49
49
  rho_m = (
50
50
  rel_frac_cem * cement_properties.dens
@@ -11,7 +11,7 @@ from fmu.pem.pem_utilities import (
11
11
  SimRstProperties,
12
12
  to_masked_array,
13
13
  )
14
- from fmu.pem.pem_utilities.enum_defs import OverburdenPressure
14
+ from fmu.pem.pem_utilities.enum_defs import OverburdenPressureTypes
15
15
 
16
16
  from .density import estimate_bulk_density
17
17
 
@@ -44,13 +44,14 @@ def estimate_pressure(
44
44
  # Saturated rock bulk density bulk
45
45
  bulk_density = estimate_bulk_density(config, sim_init, fluid_props, matrix_props)
46
46
 
47
- ovb = config.pressure.overburden
48
- if ovb.type == OverburdenPressure.CONSTANT:
47
+ # ovb = config.pressure.overburden
48
+ ovb = config.pressure
49
+ if ovb.type == OverburdenPressureTypes.CONSTANT:
49
50
  eff_pres = [
50
51
  estimate_effective_pressure(
51
52
  formation_pressure=sim_date.pressure * 1.0e5,
52
53
  bulk_density=dens,
53
- reference_overburden_pressure=ovb.constant,
54
+ reference_overburden_pressure=ovb.value,
54
55
  )
55
56
  for (sim_date, dens) in zip(sim_rst, bulk_density)
56
57
  ]
@@ -60,8 +61,8 @@ def estimate_pressure(
60
61
  formation_pressure=sim_date.pressure * 1.0e5,
61
62
  bulk_density=dens,
62
63
  reference_overburden_pressure=overburden_pressure_from_trend(
63
- inter=ovb.trend.intercept,
64
- grad=ovb.trend.gradient,
64
+ inter=ovb.intercept,
65
+ grad=ovb.gradient,
65
66
  depth=sim_init.depth,
66
67
  ),
67
68
  )
@@ -40,7 +40,7 @@ def estimate_saturated_rock(
40
40
  Returns:
41
41
  saturated rock properties per restart date
42
42
  """
43
- if isinstance(config.rock_matrix.rpm, PatchyCementRPM):
43
+ if isinstance(config.rock_matrix.model, PatchyCementRPM):
44
44
  # Patchy cement model
45
45
  cement = config.rock_matrix.minerals[config.rock_matrix.cement]
46
46
  cement_properties = estimate_cement(
@@ -57,7 +57,7 @@ def estimate_saturated_rock(
57
57
  eff_pres,
58
58
  config,
59
59
  )
60
- elif isinstance(config.rock_matrix.rpm, FriableRPM):
60
+ elif isinstance(config.rock_matrix.model, FriableRPM):
61
61
  # Friable sandstone model
62
62
  sat_rock_props = run_friable(
63
63
  matrix_props,
@@ -66,7 +66,7 @@ def estimate_saturated_rock(
66
66
  eff_pres,
67
67
  config,
68
68
  )
69
- elif isinstance(config.rock_matrix.rpm, RegressionModels):
69
+ elif isinstance(config.rock_matrix.model, RegressionModels):
70
70
  # Regression models for dry rock properties, saturation by Gassmann
71
71
  sat_rock_props = run_regression_models(
72
72
  matrix_props,
@@ -22,7 +22,7 @@ from fmu.pem.pem_utilities import (
22
22
  reverse_filter_and_restore,
23
23
  to_masked_array,
24
24
  )
25
- from fmu.pem.pem_utilities.enum_defs import CO2Models, FluidMixModel
25
+ from fmu.pem.pem_utilities.enum_defs import CO2Models, FluidMixModel, TemperatureMethod
26
26
 
27
27
 
28
28
  def effective_fluid_properties(
@@ -61,8 +61,6 @@ def effective_fluid_properties(
61
61
 
62
62
  # Convert pressure from bar to Pa
63
63
  pres = 1.0e5 * prop.pressure
64
- mix_model = fluid_params.mix_method
65
- brie_exp = fluid_params.brie_exponent
66
64
 
67
65
  # Salinity and temperature are either taken as constants from config file or
68
66
  # from eclipse simulator model
@@ -73,10 +71,17 @@ def effective_fluid_properties(
73
71
  salinity = to_masked_array(fluid_params.brine.salinity, sat_wat)
74
72
  # Temperature will normally be set as a constant. It can come from eclipse in
75
73
  # the case a compositional fluid model is run.
76
- if fluid_params.temperature_from_sim:
77
- temp = prop.temp
74
+ if fluid_params.temperature.type == TemperatureMethod.FROMSIM:
75
+ if hasattr(prop, "temp") and prop.temp is not None:
76
+ temp = prop.temp
77
+ else:
78
+ raise ValueError(
79
+ "eclipse simulation restart file does not have "
80
+ "temperature attribute. Constant temperature must "
81
+ "be set in parameter file"
82
+ )
78
83
  else:
79
- temp = to_masked_array(fluid_params.temperature, sat_wat)
84
+ temp = to_masked_array(fluid_params.temperature.temperature_value, sat_wat)
80
85
 
81
86
  # Gas gravity has to be expanded to a masked array if it comes as a float
82
87
  if isinstance(fluid_params.gas.gas_gravity, float):
@@ -217,7 +222,7 @@ def effective_fluid_properties(
217
222
 
218
223
  gas = dict(zip(fluid_keys, gas_props))
219
224
 
220
- if mix_model == FluidMixModel.WOOD:
225
+ if fluid_params.fluid_mix_method == FluidMixModel.WOOD:
221
226
  mixed_fluid_bulk_modulus = multi_wood(
222
227
  [sat_wat, sat_gas, sat_oil],
223
228
  [brine["bulk_modulus"], gas["bulk_modulus"], oil["bulk_modulus"]],
@@ -230,7 +235,7 @@ def effective_fluid_properties(
230
235
  brine["bulk_modulus"],
231
236
  sat_oil,
232
237
  oil["bulk_modulus"],
233
- brie_exp,
238
+ fluid_params.fluid_mix_method.brie_exponent,
234
239
  )
235
240
  mixed_fluid_density = (
236
241
  sat_wat * brine["density"]
@@ -200,14 +200,14 @@ def run_regression_models(
200
200
  )
201
201
  if not multiple_lithologies:
202
202
  dry_props = dry_rock_regression(
203
- tmp_por, tmp_min_rho, config.rock_matrix.rpm.parameters.sandstone
203
+ tmp_por, tmp_min_rho, config.rock_matrix.model.parameters.sandstone
204
204
  )
205
205
  else:
206
206
  dry_props_sand = dry_rock_regression(
207
- tmp_por, tmp_min_rho, config.rock_matrix.rpm.parameters.sandstone
207
+ tmp_por, tmp_min_rho, config.rock_matrix.model.parameters.sandstone
208
208
  )
209
209
  dry_props_shale = dry_rock_regression(
210
- tmp_por, tmp_min_rho, config.rock_matrix.rpm.parameters.shale
210
+ tmp_por, tmp_min_rho, config.rock_matrix.model.parameters.shale
211
211
  )
212
212
  dry_rho = (
213
213
  dry_props_sand.dens * (1.0 - tmp_vsh) + dry_props_shale.dens * tmp_vsh
@@ -41,7 +41,7 @@ def run_friable(
41
41
  # effective_pressure can be lists
42
42
  fluid, pressure = _verify_inputs(fluid, pressure)
43
43
  saturated_props = []
44
- friable_params = config.rock_matrix.rpm.parameters
44
+ friable_params = config.rock_matrix.model.parameters
45
45
  for fl_prop, pres in zip(fluid, pressure):
46
46
  (
47
47
  mask,
@@ -75,7 +75,7 @@ def run_friable(
75
75
  tmp_por,
76
76
  tmp_pres,
77
77
  friable_params.critical_porosity,
78
- friable_params.coord_num_function,
78
+ friable_params.coordination_number_function.fcn,
79
79
  friable_params.coordination_number,
80
80
  friable_params.shear_reduction,
81
81
  )
@@ -43,7 +43,7 @@ def run_patchy_cement(
43
43
  # effective_pressure can be lists
44
44
  fluid, pressure = _verify_inputs(fluid, pressure)
45
45
  saturated_props = []
46
- pat_cem_params = config.rock_matrix.rpm.parameters
46
+ pat_cem_params = config.rock_matrix.model.parameters
47
47
  for fl_prop, pres in zip(fluid, pressure):
48
48
  (
49
49
  mask,
@@ -88,7 +88,7 @@ def run_patchy_cement(
88
88
  tmp_pres,
89
89
  pat_cem_params.cement_fraction,
90
90
  pat_cem_params.critical_porosity,
91
- pat_cem_params.coord_num_function,
91
+ pat_cem_params.coordination_number_function.fcn,
92
92
  pat_cem_params.coordination_number,
93
93
  pat_cem_params.shear_reduction,
94
94
  )
@@ -73,7 +73,7 @@ def run_t_matrix_and_pressure_models(
73
73
  exp_parameter_file = config.paths.rel_path_pem / exp_parameter_file
74
74
 
75
75
  saturated_props = []
76
- t_mat_params = config.rock_matrix.rpm.parameters
76
+ t_mat_params = config.rock_matrix.model.parameters
77
77
 
78
78
  if vsh is None and t_mat_params.t_mat_model_version == "EXP":
79
79
  raise ValueError("Shale volume must be provided for EXP model")
@@ -5,7 +5,7 @@ Define enumerated strings
5
5
  from enum import Enum
6
6
 
7
7
 
8
- class OverburdenPressure(str, Enum):
8
+ class OverburdenPressureTypes(str, Enum):
9
9
  CONSTANT = "constant"
10
10
  TREND = "trend"
11
11
 
@@ -52,3 +52,19 @@ class RPMType(str, Enum):
52
52
  class VolumeFractions(str, Enum):
53
53
  NTG_SIM = "ntg_sim"
54
54
  VOL_FRAC = "fraction_files"
55
+
56
+
57
+ class GasModels(str, Enum):
58
+ GLOBAL = "Global"
59
+ LIGHT = "Light"
60
+ HC2016 = "HC2016"
61
+
62
+
63
+ class CoordinationNumberFunction(str, Enum):
64
+ PORBASED = "PorBased"
65
+ CONSTANT = "ConstVal"
66
+
67
+
68
+ class TemperatureMethod(str, Enum):
69
+ CONSTANT = "constant"
70
+ FROMSIM = "from_sim"
@@ -92,7 +92,8 @@ def read_sim_grid_props(
92
92
 
93
93
  init_props = read_init_properties(init_property_file, sim_grid)
94
94
 
95
- RST_PROPS = ["SWAT", "SGAS", "SOIL", "RS", "RV", "PRESSURE", "SALT"]
95
+ # TEMP will only be available for eclipse-300
96
+ RST_PROPS = ["SWAT", "SGAS", "SOIL", "RS", "RV", "PRESSURE", "SALT", "TEMP"]
96
97
 
97
98
  # Restart properties - set strict to False, False in case RV is not included in
98
99
  # the UNRST file
@@ -6,9 +6,9 @@ from typing import Any, Dict, List, Literal, Optional, Self, Union
6
6
  import numpy as np
7
7
  from pydantic import (
8
8
  BaseModel,
9
+ ConfigDict,
9
10
  DirectoryPath,
10
11
  Field,
11
- FilePath,
12
12
  field_validator,
13
13
  model_validator,
14
14
  )
@@ -20,8 +20,10 @@ from fmu.pem import INTERNAL_EQUINOR
20
20
  from .enum_defs import (
21
21
  CO2Models,
22
22
  FluidMixModel,
23
+ GasModels,
23
24
  MineralMixModel,
24
- OverburdenPressure,
25
+ OverburdenPressureTypes,
26
+ TemperatureMethod,
25
27
  VolumeFractions,
26
28
  )
27
29
  from .rpm_models import MineralProperties, PatchyCementRPM, RegressionRPM, TMatrixRPM
@@ -43,7 +45,7 @@ class FractionFiles(BaseModel):
43
45
  default=Path("../../sim2seis/input/pem"),
44
46
  description="Directory for volume fractions",
45
47
  )
46
- fractions_grid_file_name: FilePath = Field(
48
+ fractions_grid_file_name: Path = Field(
47
49
  description="Grid definition of the volume fractions"
48
50
  )
49
51
  fractions_prop_file_names: list[Path] = Field(description="Volume fractions")
@@ -54,6 +56,21 @@ class FractionFiles(BaseModel):
54
56
  "they have to represent real volume fractions, and this will be ignored",
55
57
  )
56
58
 
59
+ @model_validator(mode="after")
60
+ def check_fractions(self) -> Self:
61
+ full_fraction_grid = self.rel_path_fractions / self.fractions_grid_file_name
62
+ if not full_fraction_grid.exists():
63
+ raise FileNotFoundError(
64
+ f"fraction grid file is missing: {full_fraction_grid}"
65
+ )
66
+ for frac_prop in self.fractions_prop_file_names:
67
+ full_fraction_prop = self.rel_path_fractions / frac_prop
68
+ if not full_fraction_prop.exists():
69
+ raise FileNotFoundError(
70
+ f"fraction prop file is missing: {full_fraction_prop}"
71
+ )
72
+ return self
73
+
57
74
 
58
75
  class RockMatrixProperties(BaseModel):
59
76
  """Configuration for rock matrix properties.
@@ -63,7 +80,9 @@ class RockMatrixProperties(BaseModel):
63
80
  and other lithologies.
64
81
  """
65
82
 
66
- rpm: Union[PatchyCementRPM, TMatrixRPM, RegressionRPM] = Field(
83
+ model_config = ConfigDict(title="Rock matrix properties:")
84
+
85
+ model: Union[PatchyCementRPM, TMatrixRPM, RegressionRPM] = Field(
67
86
  description="Selection of parameter set for rock physics model"
68
87
  )
69
88
  minerals: Dict[str, MineralProperties] = Field(
@@ -174,23 +193,15 @@ class RockMatrixProperties(BaseModel):
174
193
 
175
194
 
176
195
  # Pressure
177
- class Trend(BaseModel):
196
+ class OverburdenPressureTrend(BaseModel):
197
+ type: SkipJsonSchema[OverburdenPressureTypes] = "trend"
178
198
  intercept: float = Field(description="Intercept in pressure depth trend")
179
199
  gradient: float = Field(description="Gradient in pressure depth trend")
180
200
 
181
201
 
182
- class Overburden(BaseModel):
183
- type: OverburdenPressure = Field(
184
- description="Selection of 'trend' or 'constant' type for overburden pressure"
185
- )
186
- trend: Trend = Field(
187
- description="Setting of intercept and gradient for pressure trend vs. depth"
188
- )
189
- constant: float = Field(description="Constant overburden pressure setting")
190
-
191
-
192
- class Pressure(BaseModel):
193
- overburden: Overburden
202
+ class OverburdenPressureConstant(BaseModel):
203
+ type: SkipJsonSchema[OverburdenPressureTypes] = "constant"
204
+ value: float = Field(description="Constant pressure")
194
205
 
195
206
 
196
207
  # Fluids
@@ -269,12 +280,34 @@ class Gas(BaseModel):
269
280
  le=0.87,
270
281
  description="Gas gravity is a ratio of gas molecular weight to that air",
271
282
  )
272
- model: str = Field(
283
+ model: GasModels = Field(
273
284
  default="HC2016",
274
285
  description="Gas model is one of 'Global', 'Light', or 'HC2016' (default)",
275
286
  )
276
287
 
277
288
 
289
+ class MixModelWood(BaseModel):
290
+ method: SkipJsonSchema[FluidMixModel] = "wood"
291
+
292
+
293
+ class MixModelBrie(BaseModel):
294
+ method: SkipJsonSchema[FluidMixModel] = "brie"
295
+ brie_exponent: float = Field(
296
+ default=3.0,
297
+ description="Brie exponent selects the mixing curve shape, from linear mix to "
298
+ "harmonic mean",
299
+ )
300
+
301
+
302
+ class ConstantTemperature(BaseModel):
303
+ type: SkipJsonSchema[TemperatureMethod] = "constant"
304
+ temperature_value: float
305
+
306
+
307
+ class TemperatureFromSim(BaseModel):
308
+ type: SkipJsonSchema[TemperatureMethod] = "from_sim"
309
+
310
+
278
311
  # Note that CO2 does not require a separate definition here, as it's properties only
279
312
  # depend on temperature and pressure
280
313
  class Fluids(BaseModel):
@@ -285,18 +318,16 @@ class Fluids(BaseModel):
285
318
  gas: Gas = Field(description="Gas model parameters")
286
319
  condensate: Oil | None = Field(
287
320
  default=None,
321
+ title="Condensate properties",
288
322
  description="Condensate is defined by the same set of parameters as oil, "
289
323
  "optional setting for condensate cases",
290
324
  )
291
- mix_method: FluidMixModel = Field(
325
+ fluid_mix_method: MixModelBrie | MixModelWood = Field(
326
+ default=MixModelBrie,
292
327
  description="Selection between Wood's or Brie model. Wood's model gives more "
293
- "radical response to adding small amounts of gas in brine or oil"
328
+ "radical response to adding small amounts of gas in brine or oil",
294
329
  )
295
- brie_exponent: int = Field(
296
- description="Brie exponent selects the mixing curve shape, from linear mix to "
297
- "harmonic mean"
298
- )
299
- temperature: float = Field(
330
+ temperature: ConstantTemperature | TemperatureFromSim = Field(
300
331
  description="In most cases it is sufficient with a constant temperature "
301
332
  "setting for the reservoir. If temperature is modelled in the "
302
333
  "simulation model, it is preferred to use that"
@@ -308,10 +339,6 @@ class Fluids(BaseModel):
308
339
  "between formation water and injected water. If salinity is "
309
340
  "modelled in the simulation model, it is preferred to use that",
310
341
  )
311
- temperature_from_sim: bool = Field(
312
- default=False,
313
- description="Flag to use temperature estimate from simulation model",
314
- )
315
342
  gas_saturation_is_co2: bool = Field(
316
343
  default=False,
317
344
  description="Eclipse model only provides one parameter for gas saturation, "
@@ -453,6 +480,7 @@ class Results(BaseModel):
453
480
 
454
481
  class PemConfig(BaseModel):
455
482
  paths: SkipJsonSchema[PemPaths] = Field(
483
+ default_factory=PemPaths,
456
484
  description="Default path settings exist, it is possible to override them, "
457
485
  "mostly relevant for input paths",
458
486
  )
@@ -463,7 +491,8 @@ class PemConfig(BaseModel):
463
491
  fluids: Fluids = Field(
464
492
  description="Settings related to fluid composition",
465
493
  )
466
- pressure: Pressure = Field(
494
+ pressure: OverburdenPressureTrend | OverburdenPressureConstant = Field(
495
+ default=OverburdenPressureTrend,
467
496
  description="Definition of overburden pressure model - constant or trend",
468
497
  )
469
498
  results: Results = Field(
@@ -476,10 +505,14 @@ class PemConfig(BaseModel):
476
505
  "difference calculation is run - normal difference, percent "
477
506
  "difference or ratio"
478
507
  )
479
- global_params: Optional[FromGlobal] = None
508
+ global_params: SkipJsonSchema[FromGlobal | None] = Field(
509
+ default=None,
510
+ )
480
511
 
481
512
  @field_validator("paths", mode="before")
482
- def check_and_create_directories(cls, v):
513
+ def check_and_create_directories(cls, v: Dict, info: ValidationInfo):
514
+ if v is None:
515
+ return PemPaths()
483
516
  for key, path in v.items():
484
517
  if key == "rel_path_intermed_output" or key == "rel_path_output":
485
518
  os.makedirs(path, exist_ok=True)
@@ -2,19 +2,40 @@
2
2
  Define RPM model types and their parameters
3
3
  """
4
4
 
5
- from enum import Enum
6
5
  from typing import List, Literal
7
6
 
8
- from pydantic import BaseModel, Field
7
+ from pydantic import BaseModel, ConfigDict, Field
8
+ from pydantic.json_schema import SkipJsonSchema
9
9
  from typing_extensions import Annotated
10
10
 
11
- from fmu.pem.pem_utilities.enum_defs import RPMType
11
+ from fmu.pem.pem_utilities.enum_defs import CoordinationNumberFunction, RPMType
12
12
 
13
13
 
14
14
  class MineralProperties(BaseModel):
15
- bulk_modulus: Annotated[float, Field(gt=1.0e9)]
16
- shear_modulus: Annotated[float, Field(gt=1.0e9)]
17
- density: Annotated[float, Field(gt=1.0e3)]
15
+ bulk_modulus: float = Field(gt=1.0e9, lt=5.0e11, description="Units: Pa")
16
+ shear_modulus: float = Field(gt=1.0e9, lt=5.0e11, description="Units: Pa")
17
+ density: float = Field(gt=1.0e3, lt=1.0e4, description="Units: kg/m^3")
18
+
19
+
20
+ class CoordinationNumberPorBased(BaseModel):
21
+ fcn: SkipJsonSchema[CoordinationNumberFunction] = Field(
22
+ default="PorBased",
23
+ description="Coordinate number is the number of grain-grain contacts. It is "
24
+ "normally assumed to be a function of porosity for friable sand",
25
+ )
26
+
27
+
28
+ class CoordinationNumberConstVal(BaseModel):
29
+ fcn: SkipJsonSchema[CoordinationNumberFunction] = Field(
30
+ default="ConstVal",
31
+ )
32
+ coordination_number: float = Field(
33
+ default=9.0,
34
+ gt=2.0,
35
+ lt=16.0,
36
+ description="In case of a constant value for the number of grain contacts, "
37
+ "a value of 8-9 is common",
38
+ )
18
39
 
19
40
 
20
41
  class PatchyCementParams(BaseModel):
@@ -47,16 +68,13 @@ class PatchyCementParams(BaseModel):
47
68
  "between grains. Shear reduction of 1 means frictionless contact, "
48
69
  "and 0 means full friction",
49
70
  )
50
- coord_num_function: Literal["ConstVal", "PorBased"] = Field(
51
- default="PorBased",
71
+ coordination_number_function: (
72
+ CoordinationNumberPorBased | CoordinationNumberConstVal
73
+ ) = Field(
74
+ default_factory=CoordinationNumberPorBased,
52
75
  description="Coordinate number is the number of grain-grain contacts. It is "
53
76
  "normally assumed to be a function of porosity for friable sand",
54
77
  )
55
- coordination_number: float = Field(
56
- default=9.0,
57
- description="In case of a constant value for the number of grain contacts, "
58
- "a value of 8-9 is common",
59
- )
60
78
 
61
79
 
62
80
  class TMatrixParams(BaseModel):
@@ -98,8 +116,10 @@ class TMatrixParams(BaseModel):
98
116
 
99
117
 
100
118
  class RhoRegressionMixin(BaseModel):
101
- rho_weights: List[float] | None = Field(
102
- default=None,
119
+ rho_weights: List[float] = Field(
120
+ default=[
121
+ 1.0,
122
+ ],
103
123
  description="List of float values for polynomial regression for density "
104
124
  "based on porosity",
105
125
  )
@@ -108,7 +128,8 @@ class RhoRegressionMixin(BaseModel):
108
128
  description="Matrix density is normally estimated from "
109
129
  "mineral composition and the density of each mineral. "
110
130
  "Setting this to True will estimate matrix "
111
- "density based on porosity alone",
131
+ "density based on porosity alone. In that case, check the "
132
+ "rho regression parameters",
112
133
  )
113
134
 
114
135
 
@@ -123,7 +144,7 @@ class VpVsRegressionParams(RhoRegressionMixin):
123
144
  description="List of float values for polynomial regression for Vs "
124
145
  "based on porosity",
125
146
  )
126
- mode: Literal["vp_vs"] = Field(
147
+ mode: SkipJsonSchema[Literal["vp_vs"]] = Field(
127
148
  default="vp_vs",
128
149
  description="Regression mode mode must be set to 'vp_vs' for "
129
150
  "estimation of Vp and Vs based on porosity",
@@ -141,7 +162,7 @@ class KMuRegressionParams(RhoRegressionMixin):
141
162
  description="List of float values for polynomial regression for shear modulus "
142
163
  "based on porosity",
143
164
  )
144
- mode: Literal["k_mu"] = Field(
165
+ mode: SkipJsonSchema[Literal["k_mu"]] = Field(
145
166
  default="k_mu",
146
167
  description="Regression mode mode must be set to 'k_mu' for "
147
168
  "estimation of bulk and shear modulus based on porosity",
@@ -158,20 +179,24 @@ class RegressionModels(BaseModel):
158
179
 
159
180
 
160
181
  class PatchyCementRPM(BaseModel):
161
- model: Literal[RPMType.PATCHY_CEMENT]
182
+ model_config = ConfigDict(title="Patchy Cement Model")
183
+ model: SkipJsonSchema[Literal[RPMType.PATCHY_CEMENT]]
162
184
  parameters: PatchyCementParams
163
185
 
164
186
 
165
187
  class FriableRPM(BaseModel):
166
- model: Literal[RPMType.FRIABLE]
188
+ model_config = ConfigDict(title="Friable Sand Model")
189
+ model: SkipJsonSchema[Literal[RPMType.FRIABLE]]
167
190
  parameters: PatchyCementParams
168
191
 
169
192
 
170
193
  class TMatrixRPM(BaseModel):
171
- model: Literal[RPMType.T_MATRIX]
194
+ model_config = ConfigDict(title="T-Matrix Inclusion Model")
195
+ model: SkipJsonSchema[Literal[RPMType.T_MATRIX]]
172
196
  parameters: TMatrixParams
173
197
 
174
198
 
175
199
  class RegressionRPM(BaseModel):
176
- model: Literal[RPMType.REGRESSION]
200
+ model_config = ConfigDict(title="Regression Model")
201
+ model: SkipJsonSchema[Literal[RPMType.REGRESSION]]
177
202
  parameters: RegressionModels
fmu/pem/version.py CHANGED
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '0.0.1'
21
- __version_tuple__ = version_tuple = (0, 0, 1)
20
+ __version__ = version = '0.0.2'
21
+ __version_tuple__ = version_tuple = (0, 0, 2)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fmu-pem
3
- Version: 0.0.1
3
+ Version: 0.0.2
4
4
  Summary: pem
5
5
  License: GNU GENERAL PUBLIC LICENSE
6
6
  Version 3, 29 June 2007
@@ -686,12 +686,8 @@ Classifier: Topic :: Scientific/Engineering :: Physics
686
686
  Classifier: Topic :: Software Development :: Libraries
687
687
  Classifier: Topic :: Utilities
688
688
  Classifier: Operating System :: POSIX :: Linux
689
- Classifier: Programming Language :: Python :: 3.8
690
- Classifier: Programming Language :: Python :: 3.9
691
- Classifier: Programming Language :: Python :: 3.10
692
- Classifier: Programming Language :: Python :: 3.11
693
689
  Classifier: Natural Language :: English
694
- Requires-Python: >=3.8
690
+ Requires-Python: >=3.11
695
691
  Description-Content-Type: text/markdown
696
692
  License-File: LICENSE
697
693
  Requires-Dist: numpy>=1.24.3
@@ -719,13 +715,19 @@ Requires-Dist: sphinx-togglebutton; extra == "docs"
719
715
  Requires-Dist: sphinx_rtd_theme; extra == "docs"
720
716
  Dynamic: license-file
721
717
 
722
- # How to use fmu-pem
718
+ > [!WARNING]
719
+ > `fmu-pem` is not yet qualified technology, and as of today only applicable for selected pilot test fields.
723
720
 
724
- Petro-elastic model (PEM) for [fmu-sim2seis](https://github.com/equinor/fmu-sim2seis)
725
- based on the [rock-physics-open](https://github.com/equinor/rock-physics-open)
726
- library.
721
+ **[📚 User documentation](https://equinor.github.io/fmu-pem/)**
727
722
 
728
- ## Installation
723
+ ## What is fmu-pem?
724
+
725
+ Petro-elastic model (PEM) for use in e.g. [fmu-sim2seis](https://github.com/equinor/fmu-sim2seis)
726
+ based on the [rock-physics-open](https://github.com/equinor/rock-physics-open) library.
727
+
728
+ ## How to use fmu-pem?
729
+
730
+ ### Installation
729
731
 
730
732
  To install `fmu-pem`, first activate a virtual environment, then type:
731
733
 
@@ -736,7 +738,7 @@ pip install fmu-pem
736
738
  The PEM is controlled by parameter settings in a *yaml-file*, given as part of the
737
739
  command line arguments, or by the workflow parameter if it is run as an ERT forward model.
738
740
 
739
- ## Calibration of rock physics models
741
+ ### Calibration of rock physics models
740
742
 
741
743
  Calibration of the rock physics models is normally carried out in
742
744
  [RokDoc](https://www.ikonscience.com/rokdoc-geoprediction-software-platform/)
@@ -752,17 +754,13 @@ from LFP logs, if they are available.
752
754
  > pip install "git+ssh://git@github.com/equinor/rock-physics"`
753
755
  > ```
754
756
 
755
- ## User interface
756
-
757
- Users can visit https://equinor.github.io/fmu-pem/ in order to get help configuring the `fmu-pem` input data.
758
-
759
- # How to develop fmu-pem
757
+ ## How to develop fmu-pem?
760
758
 
761
759
  Developing the user interface can be done by:
762
760
  ```bash
763
- cd ./user-interface-config
761
+ cd ./documentation
764
762
  npm ci # Install dependencies
765
763
  npm run create-json-schema # Extract JSON schema from Python code
766
- npm run dev # Start local development server
764
+ npm run docs:dev # Start local development server
767
765
  ```
768
766
  The JSON schema itself (type, title, description etc.) comes from the corresponding Pydantic models in the Python code.
@@ -2,36 +2,36 @@ fmu/__init__.py,sha256=YWSE22UTDSocfqQHxEeXrRkdlA63t_aayQVdJkycwYs,83
2
2
  fmu/pem/__init__.py,sha256=FhNaFibcFZEK1Rz7IBRXBgxMHGNlcgrHaD4FtU4pDjs,421
3
3
  fmu/pem/__main__.py,sha256=L8HW2P6_AQX70gcgmMdbW0BouCQdI0OVab-U4QkcPOk,1361
4
4
  fmu/pem/run_pem.py,sha256=z6UAuEAJlSVcbTeC2q5q8_ToKe0HIgQPHZfjRWSg6PI,3218
5
- fmu/pem/version.py,sha256=vgltXBYF55vNcC2regxjGN0_cbebmm8VgcDdQaDapWQ,511
5
+ fmu/pem/version.py,sha256=wO7XWlZte1hxA4mMvRc6zhNdGm74Nhhn2bfWRAxaKbI,511
6
6
  fmu/pem/forward_models/__init__.py,sha256=WuN66rmgfqrekCy3Ss9NHqsy-lZ4WGY-4VZa3jYDV2s,117
7
7
  fmu/pem/forward_models/pem_model.py,sha256=fKDD1-euwLBMr6rAjDYG0o-k7uKYRxG6De6bywF3AXI,2203
8
8
  fmu/pem/hook_implementations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  fmu/pem/hook_implementations/jobs.py,sha256=IQW5m7oeZ_MiemxXv-UGLCPeo4h3QT9oELPlWAzsN60,388
10
10
  fmu/pem/pem_functions/__init__.py,sha256=G2tu5E1PFvlw36fLdmr2A4Xr9ZqbKMf104OU5ydh_3A,539
11
- fmu/pem/pem_functions/density.py,sha256=36A8yccsnVPXCpnIfuwNUf9FVvXDkCBpcn4UFuPngFE,1777
12
- fmu/pem/pem_functions/effective_pressure.py,sha256=3p_bFwgS-PtCN0hAaJXYLwdzuv2J5PHDLWhzyBQNfgU,6118
13
- fmu/pem/pem_functions/estimate_saturated_rock.py,sha256=azJjVwuUGCyiO-FIY-TYktR3PSBRoOB2ceY33PJyMsc,2756
14
- fmu/pem/pem_functions/fluid_properties.py,sha256=HCRay1blnWiK19N0nncoV6ftB-DHPC8d029Xsg4jaFw,10458
11
+ fmu/pem/pem_functions/density.py,sha256=eiAvZC7L3LvD0VuJYKSKY_M1WpqnxUS935-kKsT8NyA,1791
12
+ fmu/pem/pem_functions/effective_pressure.py,sha256=AoiMlBkCtERIZ3R0Nct07J7Rj5FaOEeEtS4u738KU-0,6141
13
+ fmu/pem/pem_functions/estimate_saturated_rock.py,sha256=upWTEZ_FCi45FoG4aW5vRdX58VoEDRFlo1ZTyokQpw0,2762
14
+ fmu/pem/pem_functions/fluid_properties.py,sha256=fRS922lwJxca4m12V9XOV5bSa2KaQzt6OQ2WLg0o9EE,10811
15
15
  fmu/pem/pem_functions/mineral_properties.py,sha256=ilf1TwE4DDev65TdHEuudxgLj41IRBWgSjXghNrCPak,8394
16
- fmu/pem/pem_functions/regression_models.py,sha256=7YfEiAbjxnP1UP1ugW8ay202grbumG4_vFppEpBkEDE,9085
17
- fmu/pem/pem_functions/run_friable_model.py,sha256=rT-LQ17gSrJS_l524LKiLnK5Q0Y5zx8lKRuO7GFd3fk,4258
18
- fmu/pem/pem_functions/run_patchy_cement_model.py,sha256=B-j-Aza2yT6qbBXIsR3HZmtjcBkONLqnq7AYbrgp_uU,4201
19
- fmu/pem/pem_functions/run_t_matrix_and_pressure.py,sha256=RmvFRm6QNvhpFp9Ar_ifWru6Yp0h-XnE9WS4lUR37Nk,6821
16
+ fmu/pem/pem_functions/regression_models.py,sha256=fNpeKzVDhFniMTlWlypfcPsEx-ztfueR1Cuo7EspJhk,9091
17
+ fmu/pem/pem_functions/run_friable_model.py,sha256=PzDZjJ3KDGUfwN0nht90lk8yM0RMXS1ZzwEztjdULzk,4274
18
+ fmu/pem/pem_functions/run_patchy_cement_model.py,sha256=A8pIu3fHujoc5U382WK2R_q4GcG8D1F3wHKBRsV7k8Y,4217
19
+ fmu/pem/pem_functions/run_t_matrix_and_pressure.py,sha256=GmGcEq38Oii2mI5tHBaJ7LutE67wKx6MyrtCMpdGWVk,6823
20
20
  fmu/pem/pem_utilities/__init__.py,sha256=r9vSDgrY4B2NwBK5PL-4GMD5o1aT2IpR1vaeOCgJ-tI,1687
21
21
  fmu/pem/pem_utilities/cumsum_properties.py,sha256=W2FtawYPZzdydGsVoOYCWIgOItNGKCRzhHzI5sUw05M,3769
22
22
  fmu/pem/pem_utilities/delta_cumsum_time.py,sha256=J83PSpO2xjxHP5tpDpleVxynt0eytqHLgbGzj79wTQI,3267
23
- fmu/pem/pem_utilities/enum_defs.py,sha256=nJWpvXBFRIE-f7A4AjsVwldM2fxSZGRXAYC0faEOckw,1067
23
+ fmu/pem/pem_utilities/enum_defs.py,sha256=SFs_5lru3Br9xHqnUrWJyeJzLvE6JAAsI_MMaA6tjlU,1354
24
24
  fmu/pem/pem_utilities/export_routines.py,sha256=gZa3AscefV9h55JQXL7juQg5SpMvhnN5nbBHFU2VtCI,9879
25
25
  fmu/pem/pem_utilities/import_config.py,sha256=H6nH_MVnVhuS4q-4KWhoOvQbGzV5Jnw1-KlD1BRccmY,3232
26
- fmu/pem/pem_utilities/import_routines.py,sha256=PRnHn2wsHRewi2z3AlSNu9i3li9srfPNq_TS9qv89a4,5263
26
+ fmu/pem/pem_utilities/import_routines.py,sha256=nj-yJYFlGno7p0k67SdjjQzUUbA92Bgfv5g7q9Nx8pA,5321
27
27
  fmu/pem/pem_utilities/pem_class_definitions.py,sha256=IOwzHfMsoPoGWIs1-I-kI2wVbhgR5TjZHygXOMsECMk,3282
28
- fmu/pem/pem_utilities/pem_config_validation.py,sha256=nxHCCLCOV0bODH7LfFjdbQRbe0zhLulKYcMgG1YnjjQ,17878
29
- fmu/pem/pem_utilities/rpm_models.py,sha256=TxW8lmIMluU1JsgGUT6nlR899mlVk8GgQx2p5ODnr78,5726
28
+ fmu/pem/pem_utilities/pem_config_validation.py,sha256=8pUDTx0aGGpqBuTJth0adDTvbrODIvKifXqWy0J_WRU,19111
29
+ fmu/pem/pem_utilities/rpm_models.py,sha256=UjqCGy-nbo2uPp-KlRdUmFRG9up2XVTlI8DplDTjIdU,6836
30
30
  fmu/pem/pem_utilities/update_grid.py,sha256=InGaWrgIH5G9xyGqazAxQmVHL0nve4B9dAttisBsIpU,1775
31
31
  fmu/pem/pem_utilities/utils.py,sha256=Gm_onSB7KuHZ0iKzx5TjHCOBYkatewSyEXgC9J-UA70,8871
32
- fmu_pem-0.0.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
33
- fmu_pem-0.0.1.dist-info/METADATA,sha256=-3GgiilfNJq6zv7F6eD0fIZ5qYSIeFs6nlh2cL7VeBk,43944
34
- fmu_pem-0.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
35
- fmu_pem-0.0.1.dist-info/entry_points.txt,sha256=NSoFnob1PAE6FzRyNJZn5idocnCB1ptNg6R8zYf7Gnc,98
36
- fmu_pem-0.0.1.dist-info/top_level.txt,sha256=Z-FIY3pxn0UK2Wxi9IJ7fKoLSraaxuNGi1eokiE0ShM,4
37
- fmu_pem-0.0.1.dist-info/RECORD,,
32
+ fmu_pem-0.0.2.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
33
+ fmu_pem-0.0.2.dist-info/METADATA,sha256=bJh3W1AKoDPrC4-CPet8xAoVpOKRRVkebtW6Rw0wpqM,43839
34
+ fmu_pem-0.0.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
35
+ fmu_pem-0.0.2.dist-info/entry_points.txt,sha256=NSoFnob1PAE6FzRyNJZn5idocnCB1ptNg6R8zYf7Gnc,98
36
+ fmu_pem-0.0.2.dist-info/top_level.txt,sha256=Z-FIY3pxn0UK2Wxi9IJ7fKoLSraaxuNGi1eokiE0ShM,4
37
+ fmu_pem-0.0.2.dist-info/RECORD,,