ert 17.1.9__py3-none-any.whl → 18.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- _ert/events.py +19 -2
- ert/__main__.py +8 -7
- ert/analysis/_update_commons.py +12 -3
- ert/cli/main.py +6 -3
- ert/cli/monitor.py +7 -0
- ert/config/__init__.py +13 -3
- ert/config/_create_observation_dataframes.py +60 -12
- ert/config/_observations.py +14 -1
- ert/config/_read_summary.py +8 -6
- ert/config/ensemble_config.py +6 -14
- ert/config/ert_config.py +19 -13
- ert/config/{everest_objective_config.py → everest_response.py} +23 -12
- ert/config/ext_param_config.py +133 -1
- ert/config/field.py +12 -8
- ert/config/forward_model_step.py +108 -6
- ert/config/gen_data_config.py +2 -6
- ert/config/gen_kw_config.py +0 -9
- ert/config/known_response_types.py +14 -0
- ert/config/parameter_config.py +0 -17
- ert/config/parsing/config_keywords.py +1 -0
- ert/config/parsing/config_schema.py +12 -0
- ert/config/parsing/config_schema_deprecations.py +11 -0
- ert/config/parsing/config_schema_item.py +1 -1
- ert/config/queue_config.py +4 -4
- ert/config/response_config.py +0 -7
- ert/config/rft_config.py +230 -0
- ert/config/summary_config.py +2 -6
- ert/config/violations.py +0 -0
- ert/config/workflow_fixtures.py +2 -1
- ert/dark_storage/client/__init__.py +2 -2
- ert/dark_storage/client/_session.py +4 -4
- ert/dark_storage/client/client.py +2 -2
- ert/dark_storage/compute/misfits.py +7 -6
- ert/dark_storage/endpoints/compute/misfits.py +2 -2
- ert/dark_storage/endpoints/observations.py +4 -4
- ert/dark_storage/endpoints/responses.py +15 -1
- ert/ensemble_evaluator/__init__.py +8 -1
- ert/ensemble_evaluator/evaluator.py +81 -29
- ert/ensemble_evaluator/event.py +6 -0
- ert/ensemble_evaluator/snapshot.py +3 -1
- ert/ensemble_evaluator/state.py +1 -0
- ert/field_utils/__init__.py +8 -0
- ert/field_utils/field_utils.py +211 -1
- ert/gui/ertwidgets/__init__.py +23 -16
- ert/gui/ertwidgets/analysismoduleedit.py +2 -2
- ert/gui/ertwidgets/checklist.py +1 -1
- ert/gui/ertwidgets/create_experiment_dialog.py +3 -1
- ert/gui/ertwidgets/ensembleselector.py +2 -2
- ert/gui/ertwidgets/models/__init__.py +2 -0
- ert/gui/ertwidgets/models/activerealizationsmodel.py +2 -1
- ert/gui/ertwidgets/models/path_model.py +1 -1
- ert/gui/ertwidgets/models/targetensemblemodel.py +2 -1
- ert/gui/ertwidgets/models/text_model.py +1 -1
- ert/gui/ertwidgets/searchbox.py +13 -4
- ert/gui/{suggestor → ertwidgets/suggestor}/_suggestor_message.py +13 -4
- ert/gui/main.py +14 -7
- ert/gui/main_window.py +1 -2
- ert/gui/simulation/ensemble_experiment_panel.py +1 -1
- ert/gui/simulation/ensemble_information_filter_panel.py +1 -1
- ert/gui/simulation/ensemble_smoother_panel.py +1 -1
- ert/gui/simulation/evaluate_ensemble_panel.py +1 -1
- ert/gui/simulation/experiment_panel.py +1 -1
- ert/gui/simulation/manual_update_panel.py +31 -8
- ert/gui/simulation/multiple_data_assimilation_panel.py +12 -8
- ert/gui/simulation/run_dialog.py +25 -4
- ert/gui/simulation/single_test_run_panel.py +2 -2
- ert/gui/summarypanel.py +1 -1
- ert/gui/tools/load_results/load_results_panel.py +1 -1
- ert/gui/tools/manage_experiments/storage_info_widget.py +7 -7
- ert/gui/tools/manage_experiments/storage_widget.py +1 -2
- ert/gui/tools/plot/plot_api.py +13 -10
- ert/gui/tools/plot/plot_window.py +12 -0
- ert/gui/tools/plot/plottery/plot_config.py +2 -0
- ert/gui/tools/plot/plottery/plot_context.py +14 -0
- ert/gui/tools/plot/plottery/plots/ensemble.py +9 -2
- ert/gui/tools/plot/plottery/plots/statistics.py +59 -19
- ert/mode_definitions.py +2 -0
- ert/plugins/__init__.py +0 -1
- ert/plugins/hook_implementations/workflows/gen_data_rft_export.py +10 -2
- ert/plugins/hook_specifications/__init__.py +0 -2
- ert/plugins/hook_specifications/jobs.py +0 -9
- ert/plugins/plugin_manager.py +2 -33
- ert/resources/shell_scripts/delete_directory.py +2 -2
- ert/run_models/__init__.py +18 -5
- ert/run_models/_create_run_path.py +33 -21
- ert/run_models/ensemble_experiment.py +10 -4
- ert/run_models/ensemble_information_filter.py +8 -1
- ert/run_models/ensemble_smoother.py +9 -3
- ert/run_models/evaluate_ensemble.py +8 -6
- ert/run_models/event.py +7 -3
- ert/run_models/everest_run_model.py +155 -44
- ert/run_models/initial_ensemble_run_model.py +23 -22
- ert/run_models/manual_update.py +4 -2
- ert/run_models/manual_update_enif.py +37 -0
- ert/run_models/model_factory.py +81 -22
- ert/run_models/multiple_data_assimilation.py +21 -10
- ert/run_models/run_model.py +54 -34
- ert/run_models/single_test_run.py +7 -4
- ert/run_models/update_run_model.py +4 -2
- ert/runpaths.py +5 -6
- ert/sample_prior.py +9 -4
- ert/scheduler/driver.py +37 -0
- ert/scheduler/event.py +3 -1
- ert/scheduler/job.py +23 -13
- ert/scheduler/lsf_driver.py +6 -2
- ert/scheduler/openpbs_driver.py +7 -1
- ert/scheduler/scheduler.py +5 -0
- ert/scheduler/slurm_driver.py +6 -2
- ert/services/__init__.py +2 -2
- ert/services/_base_service.py +31 -15
- ert/services/ert_server.py +317 -0
- ert/shared/_doc_utils/ert_jobs.py +1 -4
- ert/shared/storage/connection.py +3 -3
- ert/shared/version.py +3 -3
- ert/storage/local_ensemble.py +25 -5
- ert/storage/local_experiment.py +6 -14
- ert/storage/local_storage.py +36 -30
- ert/storage/migration/to18.py +12 -0
- ert/storage/migration/to8.py +4 -4
- ert/substitutions.py +12 -28
- ert/validation/active_range.py +7 -7
- ert/validation/rangestring.py +16 -16
- {ert-17.1.9.dist-info → ert-18.0.1.dist-info}/METADATA +8 -7
- {ert-17.1.9.dist-info → ert-18.0.1.dist-info}/RECORD +159 -158
- everest/bin/config_branch_script.py +3 -6
- everest/bin/everconfigdump_script.py +1 -9
- everest/bin/everest_script.py +21 -11
- everest/bin/kill_script.py +2 -2
- everest/bin/monitor_script.py +2 -2
- everest/bin/utils.py +6 -3
- everest/config/__init__.py +4 -1
- everest/config/control_config.py +61 -2
- everest/config/control_variable_config.py +2 -1
- everest/config/everest_config.py +38 -16
- everest/config/forward_model_config.py +5 -3
- everest/config/install_data_config.py +7 -5
- everest/config/install_job_config.py +7 -3
- everest/config/install_template_config.py +3 -3
- everest/config/optimization_config.py +19 -6
- everest/config/output_constraint_config.py +8 -2
- everest/config/server_config.py +6 -49
- everest/config/utils.py +25 -105
- everest/config/validation_utils.py +10 -10
- everest/config_file_loader.py +13 -2
- everest/detached/everserver.py +7 -8
- everest/everest_storage.py +6 -10
- everest/gui/everest_client.py +0 -1
- everest/gui/main_window.py +2 -2
- everest/optimizer/everest2ropt.py +59 -32
- everest/optimizer/opt_model_transforms.py +12 -13
- everest/optimizer/utils.py +0 -29
- everest/strings.py +0 -5
- ert/config/everest_constraints_config.py +0 -95
- ert/services/storage_service.py +0 -127
- everest/config/sampler_config.py +0 -103
- everest/simulator/__init__.py +0 -88
- everest/simulator/everest_to_ert.py +0 -51
- /ert/gui/{suggestor → ertwidgets/suggestor}/__init__.py +0 -0
- /ert/gui/{suggestor → ertwidgets/suggestor}/_colors.py +0 -0
- /ert/gui/{suggestor → ertwidgets/suggestor}/suggestor.py +0 -0
- {ert-17.1.9.dist-info → ert-18.0.1.dist-info}/WHEEL +0 -0
- {ert-17.1.9.dist-info → ert-18.0.1.dist-info}/entry_points.txt +0 -0
- {ert-17.1.9.dist-info → ert-18.0.1.dist-info}/licenses/COPYING +0 -0
- {ert-17.1.9.dist-info → ert-18.0.1.dist-info}/top_level.txt +0 -0
ert/config/ext_param_config.py
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import importlib
|
|
3
4
|
import json
|
|
5
|
+
import logging
|
|
4
6
|
from collections.abc import Iterator, Mapping, MutableMapping
|
|
5
7
|
from dataclasses import field
|
|
6
8
|
from pathlib import Path
|
|
7
|
-
from
|
|
9
|
+
from textwrap import dedent
|
|
10
|
+
from typing import TYPE_CHECKING, Any, Literal, Self
|
|
8
11
|
|
|
9
12
|
import networkx as nx
|
|
10
13
|
import numpy as np
|
|
11
14
|
import xarray as xr
|
|
15
|
+
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
|
16
|
+
from ropt.workflow import find_sampler_plugin
|
|
12
17
|
|
|
13
18
|
from ert.substitutions import substitute_runpath_name
|
|
14
19
|
|
|
@@ -24,6 +29,119 @@ if TYPE_CHECKING:
|
|
|
24
29
|
MutableDataType = MutableMapping[str, Number | MutableMapping[str, Number]]
|
|
25
30
|
|
|
26
31
|
|
|
32
|
+
class SamplerConfig(BaseModel):
|
|
33
|
+
backend: str | None = Field(
|
|
34
|
+
default=None,
|
|
35
|
+
description=dedent(
|
|
36
|
+
"""
|
|
37
|
+
[Deprecated]
|
|
38
|
+
|
|
39
|
+
The correct backend will be inferred by the method. If several backends
|
|
40
|
+
have a method named `A`, pick a specific backend `B` by putting `B/A` in
|
|
41
|
+
the `method` field.
|
|
42
|
+
"""
|
|
43
|
+
),
|
|
44
|
+
)
|
|
45
|
+
method: str = Field(
|
|
46
|
+
default="norm",
|
|
47
|
+
description=dedent(
|
|
48
|
+
"""
|
|
49
|
+
The sampling method or distribution used by the sampler backend.
|
|
50
|
+
|
|
51
|
+
The set of available methods depends on the sampler backend used. By
|
|
52
|
+
default a plugin based on `scipy.stats` is used, implementing the
|
|
53
|
+
following methods:
|
|
54
|
+
|
|
55
|
+
- From Probability Distributions:
|
|
56
|
+
- `norm`: Samples from a standard normal distribution (mean 0,
|
|
57
|
+
standard deviation 1).
|
|
58
|
+
- `truncnorm`: Samples from a truncated normal distribution
|
|
59
|
+
(mean 0, std. dev. 1), truncated to the range `[-1, 1]`.
|
|
60
|
+
- `uniform`: Samples from a uniform distribution in the range
|
|
61
|
+
`[-1, 1]`.
|
|
62
|
+
|
|
63
|
+
- From Quasi-Monte Carlo Sequences:
|
|
64
|
+
- `sobol`: Uses Sobol' sequences.
|
|
65
|
+
- `halton`: Uses Halton sequences.
|
|
66
|
+
- `lhs`: Uses Latin Hypercube Sampling.
|
|
67
|
+
|
|
68
|
+
Note: QMC samples are generated in the unit hypercube `[0, 1]^d`
|
|
69
|
+
and then scaled to the hypercube `[-1, 1]^d`.
|
|
70
|
+
"""
|
|
71
|
+
),
|
|
72
|
+
)
|
|
73
|
+
options: dict[str, Any] | None = Field(
|
|
74
|
+
default=None,
|
|
75
|
+
description=dedent(
|
|
76
|
+
"""
|
|
77
|
+
Specifies a dict of optional parameters for the sampler backend.
|
|
78
|
+
|
|
79
|
+
This dict of values is passed unchanged to the selected method in
|
|
80
|
+
the backend.
|
|
81
|
+
"""
|
|
82
|
+
),
|
|
83
|
+
)
|
|
84
|
+
shared: bool | None = Field(
|
|
85
|
+
default=None,
|
|
86
|
+
description=dedent(
|
|
87
|
+
"""
|
|
88
|
+
Whether to share perturbations between realizations.
|
|
89
|
+
"""
|
|
90
|
+
),
|
|
91
|
+
)
|
|
92
|
+
model_config = ConfigDict(extra="forbid")
|
|
93
|
+
|
|
94
|
+
@model_validator(mode="after")
|
|
95
|
+
def validate_backend_and_method(self) -> Self:
|
|
96
|
+
if self.backend is not None:
|
|
97
|
+
message = (
|
|
98
|
+
"sampler.backend is deprecated. "
|
|
99
|
+
"The correct backend will be inferred by the method. "
|
|
100
|
+
"If several backends have a method named A, you need to pick "
|
|
101
|
+
"a specific backend B by putting B/A in sampler.method."
|
|
102
|
+
)
|
|
103
|
+
print(message)
|
|
104
|
+
# Note: Importing EVEREST.everest
|
|
105
|
+
# leads to circular import, but we still wish to log
|
|
106
|
+
# from "everest" here as per old behavior.
|
|
107
|
+
# Can consider logging this as if from ERT,
|
|
108
|
+
# which is valid if we store SamplerConfig as part of
|
|
109
|
+
# ExtParam configs.
|
|
110
|
+
logging.getLogger("everest").warning(message)
|
|
111
|
+
|
|
112
|
+
# Update the default for backends that are not scipy:
|
|
113
|
+
if (
|
|
114
|
+
self.backend not in {None, "scipy"}
|
|
115
|
+
and "method" not in self.model_fields_set
|
|
116
|
+
):
|
|
117
|
+
self.method = "default"
|
|
118
|
+
|
|
119
|
+
if self.backend is not None:
|
|
120
|
+
self.method = f"{self.backend}/{self.method}"
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
plugin = find_sampler_plugin(f"{self.method}")
|
|
124
|
+
except ValueError:
|
|
125
|
+
raise
|
|
126
|
+
except Exception as exc:
|
|
127
|
+
ert_version = importlib.metadata.version("ert")
|
|
128
|
+
ropt_version = importlib.metadata.version("ropt")
|
|
129
|
+
msg = (
|
|
130
|
+
f"Error while initializing ropt:\n\n{exc}.\n\n"
|
|
131
|
+
"There may a be version mismatch between "
|
|
132
|
+
f"ERT ({ert_version}) and ropt ({ropt_version})\n"
|
|
133
|
+
"If the installation is correct, please report this as a bug."
|
|
134
|
+
)
|
|
135
|
+
raise RuntimeError(msg) from exc
|
|
136
|
+
|
|
137
|
+
if plugin is None:
|
|
138
|
+
raise ValueError(f"Sampler method '{self.method}' not found")
|
|
139
|
+
|
|
140
|
+
self.backend = None
|
|
141
|
+
|
|
142
|
+
return self
|
|
143
|
+
|
|
144
|
+
|
|
27
145
|
class ExtParamConfig(ParameterConfig):
|
|
28
146
|
"""Create an ExtParamConfig for @key with the given @input_keys
|
|
29
147
|
|
|
@@ -46,6 +164,20 @@ class ExtParamConfig(ParameterConfig):
|
|
|
46
164
|
output_file: str = ""
|
|
47
165
|
forward_init_file: str = ""
|
|
48
166
|
update: bool = False
|
|
167
|
+
types: list[Literal["well_control", "generic_control"]]
|
|
168
|
+
initial_guesses: list[float]
|
|
169
|
+
control_types: list[Literal["real", "integer"]]
|
|
170
|
+
enabled: list[bool]
|
|
171
|
+
min: list[float]
|
|
172
|
+
max: list[float]
|
|
173
|
+
perturbation_types: list[Literal["absolute", "relative"]]
|
|
174
|
+
perturbation_magnitudes: list[float]
|
|
175
|
+
scaled_ranges: list[tuple[float, float]]
|
|
176
|
+
samplers: list[SamplerConfig | None]
|
|
177
|
+
|
|
178
|
+
# Set up for deprecation, but has to live here until support for the
|
|
179
|
+
# "dotdash" notation is removed for everest controls via everest config.
|
|
180
|
+
input_keys_dotdash: list[str] = field(default_factory=list)
|
|
49
181
|
|
|
50
182
|
def read_from_runpath(
|
|
51
183
|
self, run_path: Path, real_nr: int, iteration: int
|
ert/config/field.py
CHANGED
|
@@ -3,14 +3,14 @@ from __future__ import annotations
|
|
|
3
3
|
import itertools
|
|
4
4
|
import logging
|
|
5
5
|
import os
|
|
6
|
-
from collections.abc import Iterator
|
|
6
|
+
from collections.abc import Callable, Iterator
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import TYPE_CHECKING, Any, Literal, Self, cast, overload
|
|
8
|
+
from typing import TYPE_CHECKING, Any, Final, Literal, Self, cast, overload
|
|
9
9
|
|
|
10
10
|
import networkx as nx
|
|
11
11
|
import numpy as np
|
|
12
12
|
import xarray as xr
|
|
13
|
-
import xtgeo
|
|
13
|
+
import xtgeo
|
|
14
14
|
from pydantic import field_serializer
|
|
15
15
|
|
|
16
16
|
from ert.field_utils import (
|
|
@@ -258,10 +258,14 @@ class Field(ParameterConfig):
|
|
|
258
258
|
from_data: npt.NDArray[np.float64],
|
|
259
259
|
iens_active_index: npt.NDArray[np.int_],
|
|
260
260
|
) -> Iterator[tuple[int, xr.Dataset]]:
|
|
261
|
-
|
|
261
|
+
dim_nx, dim_ny, dim_nz = (
|
|
262
|
+
self.ertbox_params.nx,
|
|
263
|
+
self.ertbox_params.ny,
|
|
264
|
+
self.ertbox_params.nz,
|
|
265
|
+
)
|
|
262
266
|
|
|
263
267
|
for i, realization in enumerate(iens_active_index):
|
|
264
|
-
values = from_data[:, i].reshape((
|
|
268
|
+
values = from_data[:, i].reshape((dim_nx, dim_ny, dim_nz))
|
|
265
269
|
ds = xr.Dataset({"values": (["x", "y", "z"], values)})
|
|
266
270
|
yield int(realization), ds
|
|
267
271
|
|
|
@@ -299,7 +303,7 @@ class Field(ParameterConfig):
|
|
|
299
303
|
fill_value=np.nan,
|
|
300
304
|
)
|
|
301
305
|
|
|
302
|
-
def load_parameter_graph(self) -> nx.Graph:
|
|
306
|
+
def load_parameter_graph(self) -> nx.Graph[int]:
|
|
303
307
|
parameter_graph = create_flattened_cube_graph(
|
|
304
308
|
px=self.ertbox_params.nx, py=self.ertbox_params.ny, pz=self.ertbox_params.nz
|
|
305
309
|
)
|
|
@@ -322,7 +326,7 @@ class Field(ParameterConfig):
|
|
|
322
326
|
return self.ertbox_params.nz
|
|
323
327
|
|
|
324
328
|
|
|
325
|
-
TRANSFORM_FUNCTIONS = {
|
|
329
|
+
TRANSFORM_FUNCTIONS: Final[dict[str, Callable[[Any], Any]]] = {
|
|
326
330
|
"LN": np.log,
|
|
327
331
|
"LOG": np.log,
|
|
328
332
|
"LN0": lambda v: np.log(v + 0.000001),
|
|
@@ -353,7 +357,7 @@ def field_transform(
|
|
|
353
357
|
) -> npt.NDArray[np.float32] | xr.DataArray:
|
|
354
358
|
if transform_name is None:
|
|
355
359
|
return data
|
|
356
|
-
return TRANSFORM_FUNCTIONS[transform_name](data)
|
|
360
|
+
return TRANSFORM_FUNCTIONS[transform_name](data)
|
|
357
361
|
|
|
358
362
|
|
|
359
363
|
def _field_truncate(data: npt.ArrayLike, min_: float | None, max_: float | None) -> Any:
|
ert/config/forward_model_step.py
CHANGED
|
@@ -1,13 +1,33 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
-
from typing import
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
from typing import (
|
|
5
|
+
TYPE_CHECKING,
|
|
6
|
+
Annotated,
|
|
7
|
+
Any,
|
|
8
|
+
ClassVar,
|
|
9
|
+
Literal,
|
|
10
|
+
NotRequired,
|
|
11
|
+
Self,
|
|
12
|
+
cast,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
from pydantic import (
|
|
16
|
+
BaseModel,
|
|
17
|
+
Field,
|
|
18
|
+
field_validator,
|
|
19
|
+
model_serializer,
|
|
20
|
+
model_validator,
|
|
21
|
+
)
|
|
22
|
+
from pydantic_core.core_schema import ValidationInfo
|
|
7
23
|
from typing_extensions import TypedDict, Unpack
|
|
8
24
|
|
|
25
|
+
from ..base_model_context import BaseModelWithContextSupport
|
|
9
26
|
from .parsing import ConfigValidationError, ConfigWarning, SchemaItemType
|
|
10
27
|
|
|
28
|
+
if TYPE_CHECKING:
|
|
29
|
+
from ert.plugins import ErtRuntimePlugins
|
|
30
|
+
|
|
11
31
|
logger = logging.getLogger(__name__)
|
|
12
32
|
|
|
13
33
|
|
|
@@ -72,6 +92,7 @@ class ForwardModelStepOptions(TypedDict, total=False):
|
|
|
72
92
|
max_running_minutes: NotRequired[int]
|
|
73
93
|
environment: NotRequired[dict[str, str]]
|
|
74
94
|
default_mapping: NotRequired[dict[str, str]]
|
|
95
|
+
required_keywords: NotRequired[list[str]]
|
|
75
96
|
|
|
76
97
|
|
|
77
98
|
class ForwardModelStepDocumentation(BaseModel):
|
|
@@ -91,7 +112,7 @@ class ForwardModelStepDocumentation(BaseModel):
|
|
|
91
112
|
) = Field(default="Uncategorized")
|
|
92
113
|
|
|
93
114
|
|
|
94
|
-
class ForwardModelStep(
|
|
115
|
+
class ForwardModelStep(BaseModelWithContextSupport):
|
|
95
116
|
"""
|
|
96
117
|
Holds information to execute one step of a forward model
|
|
97
118
|
|
|
@@ -202,7 +223,87 @@ class ForwardModelStep(BaseModel):
|
|
|
202
223
|
return None if v == "null" else v
|
|
203
224
|
|
|
204
225
|
|
|
205
|
-
class
|
|
226
|
+
class UserInstalledForwardModelStep(ForwardModelStep):
|
|
227
|
+
"""
|
|
228
|
+
Represents a forward model step installed by a user via the ERT Config
|
|
229
|
+
forward model step format provided via the INSTALL_JOB keyword.
|
|
230
|
+
User-installed forward model steps serialize with their full configuration,
|
|
231
|
+
unlike site-installed steps which only serialize as references.
|
|
232
|
+
"""
|
|
233
|
+
|
|
234
|
+
type: Literal["user_installed"] = "user_installed"
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
class _SerializedSiteInstalledForwardModelStep(TypedDict):
|
|
238
|
+
type: Literal["site_installed"]
|
|
239
|
+
name: str
|
|
240
|
+
private_args: dict[str, str]
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
class SiteInstalledForwardModelStep(ForwardModelStep):
|
|
244
|
+
"""
|
|
245
|
+
Represents a forward model step installed via external plugins.
|
|
246
|
+
Instances of this class serialize only as references to the plugin by name, and
|
|
247
|
+
the user-provided private_args, allowing them to dynamically update when plugins
|
|
248
|
+
change, rather than being locked to a specific executable at serialization time.
|
|
249
|
+
"""
|
|
250
|
+
|
|
251
|
+
type: Literal["site_installed"] = "site_installed"
|
|
252
|
+
|
|
253
|
+
@model_serializer(mode="plain")
|
|
254
|
+
def serialize_model(self) -> _SerializedSiteInstalledForwardModelStep:
|
|
255
|
+
return {
|
|
256
|
+
"type": "site_installed",
|
|
257
|
+
"name": self.name,
|
|
258
|
+
"private_args": self.private_args,
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
@model_validator(mode="before")
|
|
262
|
+
@classmethod
|
|
263
|
+
def deserialize_model(
|
|
264
|
+
cls, values: dict[str, Any], info: ValidationInfo
|
|
265
|
+
) -> dict[str, Any]:
|
|
266
|
+
runtime_plugins = cast("ErtRuntimePlugins", info.context)
|
|
267
|
+
name = values["name"]
|
|
268
|
+
|
|
269
|
+
if runtime_plugins is None:
|
|
270
|
+
if values.get("type") == "site_installed":
|
|
271
|
+
msg = (
|
|
272
|
+
f"Trying to find site-installed forward model step {name} "
|
|
273
|
+
f"without site plugins. This forward model must be loaded "
|
|
274
|
+
f"with ERT site plugins available."
|
|
275
|
+
)
|
|
276
|
+
raise KeyError(msg)
|
|
277
|
+
return values
|
|
278
|
+
|
|
279
|
+
if name not in runtime_plugins.installed_forward_model_steps:
|
|
280
|
+
msg = (
|
|
281
|
+
f"Expected forward model step {name} to be installed "
|
|
282
|
+
f"via plugins, but it was not found. Please check that "
|
|
283
|
+
f"your python environment has it installed."
|
|
284
|
+
)
|
|
285
|
+
raise KeyError(msg)
|
|
286
|
+
site_installed_fm = runtime_plugins.installed_forward_model_steps[name]
|
|
287
|
+
|
|
288
|
+
# Intent: copy the site installed forward model to this instance.
|
|
289
|
+
# bypassing the model_serializer
|
|
290
|
+
site_fm_instance = {
|
|
291
|
+
k: getattr(site_installed_fm, k)
|
|
292
|
+
for k in SiteInstalledForwardModelStep.model_fields
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return site_fm_instance | (
|
|
296
|
+
{"private_args": values["private_args"]} if "private_args" in values else {}
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
SiteOrUserForwardModelStep = Annotated[
|
|
301
|
+
(UserInstalledForwardModelStep | SiteInstalledForwardModelStep),
|
|
302
|
+
Field(discriminator="type"),
|
|
303
|
+
]
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
class ForwardModelStepPlugin(SiteInstalledForwardModelStep):
|
|
206
307
|
def __init__(
|
|
207
308
|
self, name: str, command: list[str], **kwargs: Unpack[ForwardModelStepOptions]
|
|
208
309
|
) -> None:
|
|
@@ -221,6 +322,7 @@ class ForwardModelStepPlugin(ForwardModelStep):
|
|
|
221
322
|
max_running_minutes = kwargs.get("max_running_minutes")
|
|
222
323
|
environment = kwargs.get("environment", {}) or {}
|
|
223
324
|
default_mapping = kwargs.get("default_mapping", {}) or {}
|
|
325
|
+
required_keywords = kwargs.get("required_keywords", []) or []
|
|
224
326
|
|
|
225
327
|
super().__init__(
|
|
226
328
|
name=name,
|
|
@@ -235,7 +337,7 @@ class ForwardModelStepPlugin(ForwardModelStep):
|
|
|
235
337
|
max_running_minutes=max_running_minutes,
|
|
236
338
|
min_arg=0,
|
|
237
339
|
max_arg=0,
|
|
238
|
-
required_keywords=
|
|
340
|
+
required_keywords=required_keywords,
|
|
239
341
|
arg_types=[],
|
|
240
342
|
environment=environment,
|
|
241
343
|
default_mapping=default_mapping,
|
ert/config/gen_data_config.py
CHANGED
|
@@ -210,16 +210,12 @@ class GenDataConfig(ResponseConfig):
|
|
|
210
210
|
return combined
|
|
211
211
|
|
|
212
212
|
def get_args_for_key(self, key: str) -> tuple[str | None, list[int] | None]:
|
|
213
|
-
for i,
|
|
214
|
-
if key ==
|
|
213
|
+
for i, key_ in enumerate(self.keys):
|
|
214
|
+
if key == key_:
|
|
215
215
|
return self.input_files[i], self.report_steps_list[i]
|
|
216
216
|
|
|
217
217
|
return None, None
|
|
218
218
|
|
|
219
|
-
@property
|
|
220
|
-
def response_type(self) -> str:
|
|
221
|
-
return "gen_data"
|
|
222
|
-
|
|
223
219
|
@property
|
|
224
220
|
def primary_key(self) -> list[str]:
|
|
225
221
|
return ["report_step", "index"]
|
ert/config/gen_kw_config.py
CHANGED
|
@@ -248,15 +248,6 @@ class GenKwConfig(ParameterConfig):
|
|
|
248
248
|
def group_name(self) -> str:
|
|
249
249
|
return self.group
|
|
250
250
|
|
|
251
|
-
def copy_parameters(
|
|
252
|
-
self,
|
|
253
|
-
source_ensemble: Ensemble,
|
|
254
|
-
target_ensemble: Ensemble,
|
|
255
|
-
realizations: npt.NDArray[np.int_],
|
|
256
|
-
) -> None:
|
|
257
|
-
df = source_ensemble.load_parameters(self.name, realizations)
|
|
258
|
-
target_ensemble.save_parameters(dataset=df)
|
|
259
|
-
|
|
260
251
|
def get_priors(self) -> list[PriorDict]:
|
|
261
252
|
dist_json = self.distribution.model_dump(exclude={"name"})
|
|
262
253
|
return [
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from .everest_response import EverestConstraintsConfig, EverestObjectivesConfig
|
|
2
|
+
from .gen_data_config import GenDataConfig
|
|
3
|
+
from .rft_config import RFTConfig
|
|
4
|
+
from .summary_config import SummaryConfig
|
|
5
|
+
|
|
6
|
+
KnownErtResponseTypes = SummaryConfig | GenDataConfig | RFTConfig
|
|
7
|
+
KNOWN_ERT_RESPONSE_TYPES = (
|
|
8
|
+
SummaryConfig,
|
|
9
|
+
GenDataConfig,
|
|
10
|
+
RFTConfig,
|
|
11
|
+
)
|
|
12
|
+
KnownResponseTypes = (
|
|
13
|
+
KnownErtResponseTypes | EverestConstraintsConfig | EverestObjectivesConfig
|
|
14
|
+
)
|
ert/config/parameter_config.py
CHANGED
|
@@ -108,23 +108,6 @@ class ParameterConfig(BaseModel):
|
|
|
108
108
|
or polars DataFrame from the numpy data
|
|
109
109
|
"""
|
|
110
110
|
|
|
111
|
-
def copy_parameters(
|
|
112
|
-
self,
|
|
113
|
-
source_ensemble: Ensemble,
|
|
114
|
-
target_ensemble: Ensemble,
|
|
115
|
-
realizations: npt.NDArray[np.int_],
|
|
116
|
-
) -> None:
|
|
117
|
-
"""
|
|
118
|
-
Copy parameters from one ensemble to another.
|
|
119
|
-
If realizations is None, copy all realizations.
|
|
120
|
-
If realizations is given, copy only those realizations.
|
|
121
|
-
"""
|
|
122
|
-
for realization in realizations:
|
|
123
|
-
# Converts to standard python scalar due to mypy
|
|
124
|
-
realization_int = int(realization)
|
|
125
|
-
ds = source_ensemble.load_parameters(self.name, realization_int)
|
|
126
|
-
target_ensemble.save_parameters(ds, self.name, realization_int)
|
|
127
|
-
|
|
128
111
|
@abstractmethod
|
|
129
112
|
def load_parameters(
|
|
130
113
|
self, ensemble: Ensemble, realizations: npt.NDArray[np.int_]
|
|
@@ -63,6 +63,17 @@ def data_kw_keyword() -> SchemaItem:
|
|
|
63
63
|
)
|
|
64
64
|
|
|
65
65
|
|
|
66
|
+
def rft_keyword() -> SchemaItem:
|
|
67
|
+
return SchemaItem(
|
|
68
|
+
kw=ConfigKeys.RFT,
|
|
69
|
+
required_set=False,
|
|
70
|
+
multi_occurrence=True,
|
|
71
|
+
options_after=0,
|
|
72
|
+
argc_min=1,
|
|
73
|
+
argc_max=1,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
|
|
66
77
|
def define_keyword() -> SchemaItem:
|
|
67
78
|
return SchemaItem(
|
|
68
79
|
kw=ConfigKeys.DEFINE,
|
|
@@ -303,6 +314,7 @@ def init_user_config_schema() -> ConfigSchemaDict:
|
|
|
303
314
|
gen_kw_keyword(),
|
|
304
315
|
gen_data_keyword(),
|
|
305
316
|
summary_keyword(),
|
|
317
|
+
rft_keyword(),
|
|
306
318
|
surface_keyword(),
|
|
307
319
|
field_keyword(),
|
|
308
320
|
single_arg_keyword(ConfigKeys.ECLBASE),
|
|
@@ -217,4 +217,15 @@ deprecated_keywords_list = [
|
|
|
217
217
|
),
|
|
218
218
|
check=lambda line: line[0] == "DESIGN2PARAMS",
|
|
219
219
|
),
|
|
220
|
+
DeprecationInfo(
|
|
221
|
+
keyword="FORWARD_MODEL",
|
|
222
|
+
message=(
|
|
223
|
+
"FORWARD_MODEL DESIGN_KW will be replaced with RUN_TEMPLATE. "
|
|
224
|
+
"DESIGN2PARAMS has been replaced by DESIGN_MATRIX, so the "
|
|
225
|
+
"parameters are already available for magic string replacement "
|
|
226
|
+
"with the RUN_TEMPLATE keyword. Please use this format: "
|
|
227
|
+
"'RUN_TEMPLATE my_text_file_template.txt my_text_output_file.txt'"
|
|
228
|
+
),
|
|
229
|
+
check=lambda line: line[0] == "DESIGN_KW",
|
|
230
|
+
),
|
|
220
231
|
]
|
|
@@ -48,7 +48,7 @@ class SchemaItem:
|
|
|
48
48
|
# if positive, arguments after this count will be concatenated with a " " between
|
|
49
49
|
join_after: PositiveInt | None = None
|
|
50
50
|
# if positive, arguments after this count will be interpreted as options
|
|
51
|
-
options_after:
|
|
51
|
+
options_after: NonNegativeInt | Varies | None = None
|
|
52
52
|
# if true, will accumulate many values set for key, otherwise each entry will
|
|
53
53
|
# overwrite any previous value set
|
|
54
54
|
multi_occurrence: bool = False
|
ert/config/queue_config.py
CHANGED
|
@@ -478,11 +478,11 @@ class QueueConfig(BaseModelWithContextSupport):
|
|
|
478
478
|
|
|
479
479
|
# validate all queue options for the unselected queues
|
|
480
480
|
# and show a warning
|
|
481
|
-
for
|
|
482
|
-
if
|
|
481
|
+
for queue_system in QueueSystem:
|
|
482
|
+
if queue_system != selected_queue_system:
|
|
483
483
|
_ = QueueOptions.create_queue_options(
|
|
484
|
-
|
|
485
|
-
grouped_queue_options[
|
|
484
|
+
queue_system,
|
|
485
|
+
grouped_queue_options[queue_system],
|
|
486
486
|
False,
|
|
487
487
|
)
|
|
488
488
|
|
ert/config/response_config.py
CHANGED
|
@@ -60,13 +60,6 @@ class ResponseConfig(BaseModel):
|
|
|
60
60
|
def expected_input_files(self) -> list[str]:
|
|
61
61
|
"""Returns a list of filenames expected to be produced by the forward model"""
|
|
62
62
|
|
|
63
|
-
@property
|
|
64
|
-
@abstractmethod
|
|
65
|
-
def response_type(self) -> str:
|
|
66
|
-
"""Label to identify what kind of response it is.
|
|
67
|
-
Must not overlap with that of other response configs."""
|
|
68
|
-
...
|
|
69
|
-
|
|
70
63
|
@property
|
|
71
64
|
@abstractmethod
|
|
72
65
|
def primary_key(self) -> list[str]:
|