ert 19.0.0rc0__py3-none-any.whl → 19.0.0rc1__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/__main__.py +94 -63
- ert/analysis/_es_update.py +30 -20
- ert/config/_create_observation_dataframes.py +23 -262
- ert/config/_observations.py +181 -170
- ert/config/_read_summary.py +4 -5
- ert/config/ert_config.py +1 -48
- ert/config/observation_config_migrations.py +793 -0
- ert/config/parsing/config_schema_deprecations.py +0 -11
- ert/config/parsing/observations_parser.py +6 -0
- ert/config/rft_config.py +1 -1
- ert/dark_storage/compute/misfits.py +0 -42
- ert/dark_storage/endpoints/__init__.py +0 -2
- ert/dark_storage/endpoints/experiments.py +0 -3
- ert/dark_storage/endpoints/observations.py +10 -2
- ert/dark_storage/json_schema/experiment.py +0 -1
- ert/gui/main.py +4 -4
- ert/gui/main_window.py +2 -0
- ert/gui/simulation/experiment_panel.py +4 -0
- ert/gui/summarypanel.py +19 -0
- ert/gui/tools/manage_experiments/export_dialog.py +4 -0
- ert/gui/tools/manage_experiments/storage_info_widget.py +20 -20
- ert/gui/tools/plot/plot_api.py +10 -10
- ert/gui/tools/plot/plot_widget.py +5 -0
- ert/gui/tools/plot/plot_window.py +1 -1
- ert/run_models/run_model.py +1 -21
- ert/services/__init__.py +7 -3
- ert/services/_storage_main.py +59 -22
- ert/services/ert_server.py +186 -24
- ert/shared/version.py +3 -3
- ert/storage/local_ensemble.py +2 -95
- ert/storage/local_experiment.py +0 -16
- ert/storage/local_storage.py +3 -1
- ert/storage/migration/to22.py +18 -0
- ert/utils/__init__.py +20 -0
- {ert-19.0.0rc0.dist-info → ert-19.0.0rc1.dist-info}/METADATA +2 -2
- {ert-19.0.0rc0.dist-info → ert-19.0.0rc1.dist-info}/RECORD +47 -52
- everest/bin/everest_script.py +5 -5
- everest/bin/kill_script.py +2 -2
- everest/bin/monitor_script.py +2 -2
- everest/bin/utils.py +4 -4
- everest/detached/everserver.py +6 -6
- everest/gui/main_window.py +2 -2
- everest/util/__init__.py +1 -19
- ert/dark_storage/compute/__init__.py +0 -0
- ert/dark_storage/endpoints/compute/__init__.py +0 -0
- ert/dark_storage/endpoints/compute/misfits.py +0 -95
- ert/services/_base_service.py +0 -387
- ert/services/webviz_ert_service.py +0 -20
- ert/shared/storage/command.py +0 -38
- ert/shared/storage/extraction.py +0 -42
- {ert-19.0.0rc0.dist-info → ert-19.0.0rc1.dist-info}/WHEEL +0 -0
- {ert-19.0.0rc0.dist-info → ert-19.0.0rc1.dist-info}/entry_points.txt +0 -0
- {ert-19.0.0rc0.dist-info → ert-19.0.0rc1.dist-info}/licenses/COPYING +0 -0
- {ert-19.0.0rc0.dist-info → ert-19.0.0rc1.dist-info}/top_level.txt +0 -0
ert/config/_observations.py
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
1
4
|
import os
|
|
2
|
-
from collections import Counter
|
|
3
5
|
from collections.abc import Sequence
|
|
4
6
|
from dataclasses import dataclass
|
|
5
7
|
from enum import StrEnum
|
|
6
|
-
from itertools import starmap
|
|
7
8
|
from typing import Any, Self
|
|
8
9
|
|
|
10
|
+
import pandas as pd
|
|
11
|
+
|
|
9
12
|
from .parsing import (
|
|
10
13
|
ErrorInfo,
|
|
11
14
|
ObservationConfigError,
|
|
@@ -13,6 +16,8 @@ from .parsing import (
|
|
|
13
16
|
ObservationType,
|
|
14
17
|
)
|
|
15
18
|
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
16
21
|
|
|
17
22
|
class ErrorModes(StrEnum):
|
|
18
23
|
REL = "REL"
|
|
@@ -20,102 +25,52 @@ class ErrorModes(StrEnum):
|
|
|
20
25
|
RELMIN = "RELMIN"
|
|
21
26
|
|
|
22
27
|
|
|
23
|
-
@dataclass
|
|
24
|
-
class ObservationError:
|
|
25
|
-
error_mode: ErrorModes
|
|
26
|
-
error: float
|
|
27
|
-
error_min: float
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
@dataclass
|
|
31
|
-
class Segment(ObservationError):
|
|
32
|
-
name: str
|
|
33
|
-
start: int
|
|
34
|
-
stop: int
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
@dataclass
|
|
38
|
-
class HistoryObservation(ObservationError):
|
|
39
|
-
name: str
|
|
40
|
-
segments: list[Segment]
|
|
41
|
-
|
|
42
|
-
@property
|
|
43
|
-
def key(self) -> str:
|
|
44
|
-
"""The :term:`summary key` to be fetched from :ref:`refcase`."""
|
|
45
|
-
# For history observations the key is also the name, ie.
|
|
46
|
-
# "HISTORY_OBSERVATION FOPR" means to add the values from
|
|
47
|
-
# the summary vector FOPRH in refcase as observations.
|
|
48
|
-
return self.name
|
|
49
|
-
|
|
50
|
-
@classmethod
|
|
51
|
-
def from_obs_dict(cls, directory: str, observation_dict: ObservationDict) -> Self:
|
|
52
|
-
error_mode = ErrorModes.RELMIN
|
|
53
|
-
error = 0.1
|
|
54
|
-
error_min = 0.1
|
|
55
|
-
segments = []
|
|
56
|
-
for key, value in observation_dict.items():
|
|
57
|
-
match key:
|
|
58
|
-
case "type" | "name":
|
|
59
|
-
pass
|
|
60
|
-
case "ERROR":
|
|
61
|
-
error = validate_positive_float(value, key)
|
|
62
|
-
case "ERROR_MIN":
|
|
63
|
-
error_min = validate_positive_float(value, key)
|
|
64
|
-
case "ERROR_MODE":
|
|
65
|
-
error_mode = validate_error_mode(value)
|
|
66
|
-
case "segments":
|
|
67
|
-
segments = list(starmap(_validate_segment_dict, value))
|
|
68
|
-
case _:
|
|
69
|
-
raise _unknown_key_error(str(key), observation_dict["name"])
|
|
70
|
-
|
|
71
|
-
return cls(
|
|
72
|
-
name=observation_dict["name"],
|
|
73
|
-
error_mode=error_mode,
|
|
74
|
-
error=error,
|
|
75
|
-
error_min=error_min,
|
|
76
|
-
segments=segments,
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
@dataclass
|
|
81
|
-
class ObservationDate:
|
|
82
|
-
days: float | None = None
|
|
83
|
-
hours: float | None = None
|
|
84
|
-
date: str | None = None
|
|
85
|
-
restart: int | None = None
|
|
86
|
-
|
|
87
|
-
|
|
88
28
|
@dataclass
|
|
89
29
|
class _SummaryValues:
|
|
90
30
|
name: str
|
|
91
31
|
value: float
|
|
92
32
|
key: str #: The :term:`summary key` in the summary response
|
|
33
|
+
date: str
|
|
93
34
|
location_x: float | None = None
|
|
94
35
|
location_y: float | None = None
|
|
95
36
|
location_range: float | None = None
|
|
96
37
|
|
|
97
38
|
|
|
98
39
|
@dataclass
|
|
99
|
-
class
|
|
40
|
+
class ObservationError:
|
|
41
|
+
error_mode: ErrorModes
|
|
42
|
+
error: float
|
|
43
|
+
error_min: float
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass
|
|
47
|
+
class SummaryObservation(_SummaryValues, ObservationError):
|
|
100
48
|
@classmethod
|
|
101
|
-
def from_obs_dict(
|
|
49
|
+
def from_obs_dict(
|
|
50
|
+
cls, directory: str, observation_dict: ObservationDict
|
|
51
|
+
) -> list[Self]:
|
|
102
52
|
error_mode = ErrorModes.ABS
|
|
103
53
|
summary_key = None
|
|
104
54
|
|
|
105
|
-
|
|
55
|
+
date: str | None = None
|
|
106
56
|
float_values: dict[str, float] = {"ERROR_MIN": 0.1}
|
|
107
|
-
localization_values: dict[str, float] = {}
|
|
57
|
+
localization_values: dict[str, float | None] = {}
|
|
108
58
|
for key, value in observation_dict.items():
|
|
109
59
|
match key:
|
|
110
60
|
case "type" | "name":
|
|
111
61
|
pass
|
|
112
|
-
case "RESTART":
|
|
113
|
-
date_dict.restart = validate_positive_int(value, key)
|
|
114
62
|
case "ERROR" | "ERROR_MIN":
|
|
115
63
|
float_values[str(key)] = validate_positive_float(value, key)
|
|
116
|
-
case "DAYS" | "HOURS":
|
|
117
|
-
|
|
118
|
-
|
|
64
|
+
case "DAYS" | "HOURS" | "RESTART":
|
|
65
|
+
raise ObservationConfigError.with_context(
|
|
66
|
+
(
|
|
67
|
+
"SUMMARY_OBSERVATION must use DATE to specify "
|
|
68
|
+
"date, DAYS | HOURS is no longer allowed. "
|
|
69
|
+
"Please run:\n ert convert_observations "
|
|
70
|
+
"<your_ert_config.ert>\nto migrate the observation config "
|
|
71
|
+
"to use the correct format."
|
|
72
|
+
),
|
|
73
|
+
key,
|
|
119
74
|
)
|
|
120
75
|
case "VALUE":
|
|
121
76
|
float_values[str(key)] = validate_float(value, key)
|
|
@@ -124,13 +79,16 @@ class SummaryObservation(ObservationDate, _SummaryValues, ObservationError):
|
|
|
124
79
|
case "KEY":
|
|
125
80
|
summary_key = value
|
|
126
81
|
case "DATE":
|
|
127
|
-
|
|
128
|
-
case "
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
localization_values["y"] = validate_float(value, key)
|
|
132
|
-
|
|
133
|
-
|
|
82
|
+
date = value
|
|
83
|
+
case "LOCALIZATION":
|
|
84
|
+
validate_localization(value, observation_dict["name"])
|
|
85
|
+
localization_values["x"] = validate_float(value["EAST"], key)
|
|
86
|
+
localization_values["y"] = validate_float(value["NORTH"], key)
|
|
87
|
+
localization_values["range"] = (
|
|
88
|
+
validate_float(value["RADIUS"], key)
|
|
89
|
+
if "RADIUS" in value
|
|
90
|
+
else None
|
|
91
|
+
)
|
|
134
92
|
case _:
|
|
135
93
|
raise _unknown_key_error(str(key), observation_dict["name"])
|
|
136
94
|
if "VALUE" not in float_values:
|
|
@@ -140,18 +98,21 @@ class SummaryObservation(ObservationDate, _SummaryValues, ObservationError):
|
|
|
140
98
|
if "ERROR" not in float_values:
|
|
141
99
|
raise _missing_value_error(observation_dict["name"], "ERROR")
|
|
142
100
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
101
|
+
assert date is not None
|
|
102
|
+
return [
|
|
103
|
+
cls(
|
|
104
|
+
name=observation_dict["name"],
|
|
105
|
+
error_mode=error_mode,
|
|
106
|
+
error=float_values["ERROR"],
|
|
107
|
+
error_min=float_values["ERROR_MIN"],
|
|
108
|
+
key=summary_key,
|
|
109
|
+
value=float_values["VALUE"],
|
|
110
|
+
location_x=localization_values.get("x"),
|
|
111
|
+
location_y=localization_values.get("y"),
|
|
112
|
+
location_range=localization_values.get("range"),
|
|
113
|
+
date=date,
|
|
114
|
+
)
|
|
115
|
+
]
|
|
155
116
|
|
|
156
117
|
|
|
157
118
|
@dataclass
|
|
@@ -163,12 +124,15 @@ class _GeneralObservation:
|
|
|
163
124
|
index_list: str | None = None
|
|
164
125
|
index_file: str | None = None
|
|
165
126
|
obs_file: str | None = None
|
|
127
|
+
restart: int | None = None
|
|
166
128
|
|
|
167
129
|
|
|
168
130
|
@dataclass
|
|
169
|
-
class GeneralObservation(
|
|
131
|
+
class GeneralObservation(_GeneralObservation):
|
|
170
132
|
@classmethod
|
|
171
|
-
def from_obs_dict(
|
|
133
|
+
def from_obs_dict(
|
|
134
|
+
cls, directory: str, observation_dict: ObservationDict
|
|
135
|
+
) -> list[Self]:
|
|
172
136
|
try:
|
|
173
137
|
data = observation_dict["DATA"]
|
|
174
138
|
except KeyError as err:
|
|
@@ -183,12 +147,22 @@ class GeneralObservation(ObservationDate, _GeneralObservation):
|
|
|
183
147
|
output.restart = validate_positive_int(value, key)
|
|
184
148
|
case "VALUE":
|
|
185
149
|
output.value = validate_float(value, key)
|
|
186
|
-
case "ERROR"
|
|
150
|
+
case "ERROR":
|
|
187
151
|
setattr(
|
|
188
152
|
output, str(key).lower(), validate_positive_float(value, key)
|
|
189
153
|
)
|
|
190
|
-
case "DATE" | "
|
|
191
|
-
|
|
154
|
+
case "DATE" | "DAYS" | "HOURS":
|
|
155
|
+
raise ObservationConfigError.with_context(
|
|
156
|
+
(
|
|
157
|
+
"GENERAL_OBSERVATION must use RESTART to specify "
|
|
158
|
+
"report step. Please run:\n ert convert_observations "
|
|
159
|
+
"<your_ert_config.ert>\nto migrate the observation config "
|
|
160
|
+
"to use the correct format."
|
|
161
|
+
),
|
|
162
|
+
key,
|
|
163
|
+
)
|
|
164
|
+
case "INDEX_LIST":
|
|
165
|
+
output.index_list = value
|
|
192
166
|
case "OBS_FILE" | "INDEX_FILE":
|
|
193
167
|
assert not isinstance(key, tuple)
|
|
194
168
|
filename = value
|
|
@@ -211,7 +185,8 @@ class GeneralObservation(ObservationDate, _GeneralObservation):
|
|
|
211
185
|
f" VALUE = {output.value}, ERROR must also be given.",
|
|
212
186
|
observation_dict["name"],
|
|
213
187
|
)
|
|
214
|
-
|
|
188
|
+
|
|
189
|
+
return [output]
|
|
215
190
|
|
|
216
191
|
|
|
217
192
|
@dataclass
|
|
@@ -227,7 +202,63 @@ class RFTObservation:
|
|
|
227
202
|
tvd: float
|
|
228
203
|
|
|
229
204
|
@classmethod
|
|
230
|
-
def
|
|
205
|
+
def from_csv(
|
|
206
|
+
cls,
|
|
207
|
+
directory: str,
|
|
208
|
+
observation_dict: ObservationDict,
|
|
209
|
+
filename: str,
|
|
210
|
+
observed_property: str = "PRESSURE",
|
|
211
|
+
) -> list[Self]:
|
|
212
|
+
if not os.path.isabs(filename):
|
|
213
|
+
filename = os.path.join(directory, filename)
|
|
214
|
+
if not os.path.exists(filename):
|
|
215
|
+
raise ObservationConfigError.with_context(
|
|
216
|
+
f"The CSV file ({filename}) does not exist or is not accessible.",
|
|
217
|
+
filename,
|
|
218
|
+
)
|
|
219
|
+
csv_file = pd.read_csv(
|
|
220
|
+
filename,
|
|
221
|
+
encoding="utf-8",
|
|
222
|
+
on_bad_lines="error",
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
required_columns = {
|
|
226
|
+
"WELL_NAME",
|
|
227
|
+
"DATE",
|
|
228
|
+
observed_property,
|
|
229
|
+
"ERROR",
|
|
230
|
+
"NORTH",
|
|
231
|
+
"EAST",
|
|
232
|
+
"TVD",
|
|
233
|
+
}
|
|
234
|
+
missing_required_columns = required_columns - set(csv_file.keys())
|
|
235
|
+
if missing_required_columns:
|
|
236
|
+
raise ObservationConfigError.with_context(
|
|
237
|
+
f"The rft observations file {filename} is missing required column(s) "
|
|
238
|
+
f"{', '.join(sorted(missing_required_columns))}.",
|
|
239
|
+
filename,
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
return [
|
|
243
|
+
cls(
|
|
244
|
+
f"{observation_dict['name']}[{row.Index}]",
|
|
245
|
+
str(row.WELL_NAME),
|
|
246
|
+
str(row.DATE),
|
|
247
|
+
observed_property,
|
|
248
|
+
validate_float(str(getattr(row, observed_property)), observed_property),
|
|
249
|
+
validate_float(str(row.ERROR), "ERROR"),
|
|
250
|
+
validate_float(str(row.NORTH), "NORTH"),
|
|
251
|
+
validate_float(str(row.EAST), "EAST"),
|
|
252
|
+
validate_float(str(row.TVD), "TVD"),
|
|
253
|
+
)
|
|
254
|
+
for row in csv_file.itertuples(index=True)
|
|
255
|
+
]
|
|
256
|
+
|
|
257
|
+
@classmethod
|
|
258
|
+
def from_obs_dict(
|
|
259
|
+
cls, directory: str, observation_dict: ObservationDict
|
|
260
|
+
) -> list[Self]:
|
|
261
|
+
csv_filename = None
|
|
231
262
|
well = None
|
|
232
263
|
observed_property = None
|
|
233
264
|
observed_value = None
|
|
@@ -256,8 +287,17 @@ class RFTObservation:
|
|
|
256
287
|
east = validate_float(value, key)
|
|
257
288
|
case "TVD":
|
|
258
289
|
tvd = validate_float(value, key)
|
|
290
|
+
case "CSV":
|
|
291
|
+
csv_filename = value
|
|
259
292
|
case _:
|
|
260
293
|
raise _unknown_key_error(str(key), observation_dict["name"])
|
|
294
|
+
if csv_filename is not None:
|
|
295
|
+
return cls.from_csv(
|
|
296
|
+
directory,
|
|
297
|
+
observation_dict,
|
|
298
|
+
csv_filename,
|
|
299
|
+
observed_property or "PRESSURE",
|
|
300
|
+
)
|
|
261
301
|
if well is None:
|
|
262
302
|
raise _missing_value_error(observation_dict["name"], "WELL")
|
|
263
303
|
if observed_value is None:
|
|
@@ -274,25 +314,24 @@ class RFTObservation:
|
|
|
274
314
|
raise _missing_value_error(observation_dict["name"], "EAST")
|
|
275
315
|
if tvd is None:
|
|
276
316
|
raise _missing_value_error(observation_dict["name"], "TVD")
|
|
277
|
-
return
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
317
|
+
return [
|
|
318
|
+
cls(
|
|
319
|
+
observation_dict["name"],
|
|
320
|
+
well,
|
|
321
|
+
date,
|
|
322
|
+
observed_property,
|
|
323
|
+
observed_value,
|
|
324
|
+
error,
|
|
325
|
+
north,
|
|
326
|
+
east,
|
|
327
|
+
tvd,
|
|
328
|
+
)
|
|
329
|
+
]
|
|
288
330
|
|
|
289
331
|
|
|
290
|
-
Observation =
|
|
291
|
-
HistoryObservation | SummaryObservation | GeneralObservation | RFTObservation
|
|
292
|
-
)
|
|
332
|
+
Observation = SummaryObservation | GeneralObservation | RFTObservation
|
|
293
333
|
|
|
294
334
|
_TYPE_TO_CLASS: dict[ObservationType, type[Observation]] = {
|
|
295
|
-
ObservationType.HISTORY: HistoryObservation,
|
|
296
335
|
ObservationType.SUMMARY: SummaryObservation,
|
|
297
336
|
ObservationType.GENERAL: GeneralObservation,
|
|
298
337
|
ObservationType.RFT: RFTObservation,
|
|
@@ -310,10 +349,20 @@ def make_observations(
|
|
|
310
349
|
inp: The collection of statements to validate.
|
|
311
350
|
"""
|
|
312
351
|
result: list[Observation] = []
|
|
313
|
-
error_list: list[ErrorInfo] = []
|
|
352
|
+
error_list: list[ErrorInfo | ObservationConfigError] = []
|
|
314
353
|
for obs_dict in observation_dicts:
|
|
354
|
+
if obs_dict["type"] == ObservationType.HISTORY:
|
|
355
|
+
msg = (
|
|
356
|
+
"HISTORY_OBSERVATION is deprecated, and must be specified "
|
|
357
|
+
"as SUMMARY_OBSERVATION. Run"
|
|
358
|
+
" ert convert_observations <ert_config.ert> to convert your "
|
|
359
|
+
"observations automatically"
|
|
360
|
+
)
|
|
361
|
+
logger.error(msg)
|
|
362
|
+
error_list.append(ObservationConfigError(msg))
|
|
363
|
+
continue
|
|
315
364
|
try:
|
|
316
|
-
result.
|
|
365
|
+
result.extend(
|
|
317
366
|
_TYPE_TO_CLASS[obs_dict["type"]].from_obs_dict(directory, obs_dict)
|
|
318
367
|
)
|
|
319
368
|
except KeyError as err:
|
|
@@ -324,60 +373,9 @@ def make_observations(
|
|
|
324
373
|
if error_list:
|
|
325
374
|
raise ObservationConfigError.from_collected(error_list)
|
|
326
375
|
|
|
327
|
-
_validate_unique_names(result)
|
|
328
376
|
return result
|
|
329
377
|
|
|
330
378
|
|
|
331
|
-
def _validate_unique_names(
|
|
332
|
-
observations: Sequence[Observation],
|
|
333
|
-
) -> None:
|
|
334
|
-
names_counter = Counter(d.name for d in observations)
|
|
335
|
-
duplicate_names = [n for n, c in names_counter.items() if c > 1]
|
|
336
|
-
errors = [
|
|
337
|
-
ErrorInfo(
|
|
338
|
-
f"Duplicate observation name {n}",
|
|
339
|
-
).set_context(n)
|
|
340
|
-
for n in duplicate_names
|
|
341
|
-
]
|
|
342
|
-
if errors:
|
|
343
|
-
raise ObservationConfigError.from_collected(errors)
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
def _validate_segment_dict(name_token: str, inp: dict[str, Any]) -> Segment:
|
|
347
|
-
start = None
|
|
348
|
-
stop = None
|
|
349
|
-
error_mode = ErrorModes.RELMIN
|
|
350
|
-
error = 0.1
|
|
351
|
-
error_min = 0.1
|
|
352
|
-
for key, value in inp.items():
|
|
353
|
-
match key:
|
|
354
|
-
case "START":
|
|
355
|
-
start = validate_int(value, key)
|
|
356
|
-
case "STOP":
|
|
357
|
-
stop = validate_int(value, key)
|
|
358
|
-
case "ERROR":
|
|
359
|
-
error = validate_positive_float(value, key)
|
|
360
|
-
case "ERROR_MIN":
|
|
361
|
-
error_min = validate_positive_float(value, key)
|
|
362
|
-
case "ERROR_MODE":
|
|
363
|
-
error_mode = validate_error_mode(value)
|
|
364
|
-
case _:
|
|
365
|
-
raise _unknown_key_error(key, name_token)
|
|
366
|
-
|
|
367
|
-
if start is None:
|
|
368
|
-
raise _missing_value_error(name_token, "START")
|
|
369
|
-
if stop is None:
|
|
370
|
-
raise _missing_value_error(name_token, "STOP")
|
|
371
|
-
return Segment(
|
|
372
|
-
name=name_token,
|
|
373
|
-
start=start,
|
|
374
|
-
stop=stop,
|
|
375
|
-
error_mode=error_mode,
|
|
376
|
-
error=error,
|
|
377
|
-
error_min=error_min,
|
|
378
|
-
)
|
|
379
|
-
|
|
380
|
-
|
|
381
379
|
def validate_error_mode(inp: str) -> ErrorModes:
|
|
382
380
|
if inp == "REL":
|
|
383
381
|
return ErrorModes.REL
|
|
@@ -415,6 +413,19 @@ def validate_positive_float(val: str, key: str) -> float:
|
|
|
415
413
|
return v
|
|
416
414
|
|
|
417
415
|
|
|
416
|
+
def validate_localization(val: dict[str, Any], obs_name: str) -> None:
|
|
417
|
+
errors = []
|
|
418
|
+
if "EAST" not in val:
|
|
419
|
+
errors.append(_missing_value_error(f"LOCALIZATION for {obs_name}", "EAST"))
|
|
420
|
+
if "NORTH" not in val:
|
|
421
|
+
errors.append(_missing_value_error(f"LOCALIZATION for {obs_name}", "NORTH"))
|
|
422
|
+
for key in val:
|
|
423
|
+
if key not in {"EAST", "NORTH", "RADIUS"}:
|
|
424
|
+
errors.append(_unknown_key_error(key, f"LOCALIZATION for {obs_name}"))
|
|
425
|
+
if errors:
|
|
426
|
+
raise ObservationConfigError.from_collected(errors)
|
|
427
|
+
|
|
428
|
+
|
|
418
429
|
def validate_positive_int(val: str, key: str) -> int:
|
|
419
430
|
try:
|
|
420
431
|
v = int(val)
|
ert/config/_read_summary.py
CHANGED
|
@@ -8,7 +8,6 @@ from __future__ import annotations
|
|
|
8
8
|
|
|
9
9
|
import fnmatch
|
|
10
10
|
import re
|
|
11
|
-
import warnings
|
|
12
11
|
from collections.abc import Callable, Sequence
|
|
13
12
|
from datetime import datetime, timedelta
|
|
14
13
|
from enum import Enum, auto
|
|
@@ -158,10 +157,10 @@ def _read_spec(
|
|
|
158
157
|
if kw.summary_variable == "TIME":
|
|
159
158
|
date_index = i
|
|
160
159
|
date_unit_str = kw.unit
|
|
161
|
-
except InvalidSummaryKeyError
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
160
|
+
except InvalidSummaryKeyError:
|
|
161
|
+
# InvalidSummaryKeyError will happen under normal conditions when
|
|
162
|
+
# the the number of wells set for WELLDIMS in the .DATA file is
|
|
163
|
+
# larger than the number of declared wells/groups/etc. These are skipped.
|
|
165
164
|
continue
|
|
166
165
|
|
|
167
166
|
if should_load_key(key):
|
ert/config/ert_config.py
CHANGED
|
@@ -7,7 +7,6 @@ import pprint
|
|
|
7
7
|
import re
|
|
8
8
|
from collections import Counter, defaultdict
|
|
9
9
|
from collections.abc import Mapping
|
|
10
|
-
from datetime import datetime
|
|
11
10
|
from functools import cached_property
|
|
12
11
|
from os import path
|
|
13
12
|
from pathlib import Path
|
|
@@ -23,7 +22,6 @@ from ert.substitutions import Substitutions
|
|
|
23
22
|
from ._create_observation_dataframes import create_observation_dataframes
|
|
24
23
|
from ._design_matrix_validator import DesignMatrixValidator
|
|
25
24
|
from ._observations import (
|
|
26
|
-
HistoryObservation,
|
|
27
25
|
Observation,
|
|
28
26
|
RFTObservation,
|
|
29
27
|
SummaryObservation,
|
|
@@ -52,7 +50,6 @@ from .parsing import (
|
|
|
52
50
|
ConfigWarning,
|
|
53
51
|
ErrorInfo,
|
|
54
52
|
ForwardModelStepKeys,
|
|
55
|
-
HistorySource,
|
|
56
53
|
HookRuntime,
|
|
57
54
|
ObservationConfigError,
|
|
58
55
|
init_forward_model_schema,
|
|
@@ -62,7 +59,6 @@ from .parsing import (
|
|
|
62
59
|
)
|
|
63
60
|
from .parsing.observations_parser import ObservationDict
|
|
64
61
|
from .queue_config import KnownQueueOptions, QueueConfig
|
|
65
|
-
from .refcase import Refcase
|
|
66
62
|
from .rft_config import RFTConfig
|
|
67
63
|
from .workflow import Workflow
|
|
68
64
|
from .workflow_fixtures import fixtures_per_hook
|
|
@@ -104,23 +100,6 @@ def _seed_sequence(seed: int | None) -> int:
|
|
|
104
100
|
return int_seed
|
|
105
101
|
|
|
106
102
|
|
|
107
|
-
def _read_time_map(file_contents: str) -> list[datetime]:
|
|
108
|
-
def str_to_datetime(date_str: str) -> datetime:
|
|
109
|
-
try:
|
|
110
|
-
return datetime.fromisoformat(date_str)
|
|
111
|
-
except ValueError:
|
|
112
|
-
logger.warning(
|
|
113
|
-
"DD/MM/YYYY date format is deprecated"
|
|
114
|
-
", please use ISO date format YYYY-MM-DD."
|
|
115
|
-
)
|
|
116
|
-
return datetime.strptime(date_str, "%d/%m/%Y")
|
|
117
|
-
|
|
118
|
-
dates = []
|
|
119
|
-
for line in file_contents.splitlines():
|
|
120
|
-
dates.append(str_to_datetime(line.strip()))
|
|
121
|
-
return dates
|
|
122
|
-
|
|
123
|
-
|
|
124
103
|
def create_forward_model_json(
|
|
125
104
|
context: dict[str, str],
|
|
126
105
|
forward_model_steps: list[ForwardModelStep],
|
|
@@ -733,9 +712,6 @@ class ErtConfig(BaseModel):
|
|
|
733
712
|
user_config_file: str = "no_config"
|
|
734
713
|
config_path: str = Field(init=False, default="")
|
|
735
714
|
observation_declarations: list[Observation] = Field(default_factory=list)
|
|
736
|
-
time_map: list[datetime] | None = None
|
|
737
|
-
history_source: HistorySource = HistorySource.REFCASE_HISTORY
|
|
738
|
-
refcase: Refcase | None = None
|
|
739
715
|
_observations: dict[str, pl.DataFrame] | None = PrivateAttr(None)
|
|
740
716
|
|
|
741
717
|
@property
|
|
@@ -755,7 +731,6 @@ class ErtConfig(BaseModel):
|
|
|
755
731
|
)
|
|
756
732
|
computed = create_observation_dataframes(
|
|
757
733
|
self.observation_declarations,
|
|
758
|
-
self.refcase,
|
|
759
734
|
cast(
|
|
760
735
|
GenDataConfig | None,
|
|
761
736
|
self.ensemble_config.response_configs.get("gen_data", None),
|
|
@@ -764,8 +739,6 @@ class ErtConfig(BaseModel):
|
|
|
764
739
|
RFTConfig | None,
|
|
765
740
|
self.ensemble_config.response_configs.get("rft", None),
|
|
766
741
|
),
|
|
767
|
-
self.time_map,
|
|
768
|
-
self.history_source,
|
|
769
742
|
)
|
|
770
743
|
self._observations = computed
|
|
771
744
|
return computed
|
|
@@ -1021,7 +994,7 @@ class ErtConfig(BaseModel):
|
|
|
1021
994
|
summary_obs = {
|
|
1022
995
|
obs.key
|
|
1023
996
|
for obs in obs_configs
|
|
1024
|
-
if isinstance(obs,
|
|
997
|
+
if isinstance(obs, SummaryObservation)
|
|
1025
998
|
}
|
|
1026
999
|
if summary_obs:
|
|
1027
1000
|
summary_keys = ErtConfig._read_summary_keys(config_dict)
|
|
@@ -1029,16 +1002,6 @@ class ErtConfig(BaseModel):
|
|
|
1029
1002
|
[key] for key in summary_obs if key not in summary_keys
|
|
1030
1003
|
]
|
|
1031
1004
|
ensemble_config = EnsembleConfig.from_dict(config_dict=config_dict)
|
|
1032
|
-
time_map = None
|
|
1033
|
-
if time_map_args := config_dict.get(ConfigKeys.TIME_MAP):
|
|
1034
|
-
time_map_file, time_map_contents = time_map_args
|
|
1035
|
-
try:
|
|
1036
|
-
time_map = _read_time_map(time_map_contents)
|
|
1037
|
-
except ValueError as err:
|
|
1038
|
-
raise ConfigValidationError.with_context(
|
|
1039
|
-
f"Could not read timemap file {time_map_file}: {err}",
|
|
1040
|
-
time_map_file,
|
|
1041
|
-
) from err
|
|
1042
1005
|
except ConfigValidationError as err:
|
|
1043
1006
|
errors.append(err)
|
|
1044
1007
|
except PydanticValidationError as err:
|
|
@@ -1091,9 +1054,6 @@ class ErtConfig(BaseModel):
|
|
|
1091
1054
|
|
|
1092
1055
|
env_vars = {}
|
|
1093
1056
|
substituter = Substitutions(substitutions)
|
|
1094
|
-
history_source = config_dict.get(
|
|
1095
|
-
ConfigKeys.HISTORY_SOURCE, HistorySource.REFCASE_HISTORY
|
|
1096
|
-
)
|
|
1097
1057
|
|
|
1098
1058
|
# Insert env vars from plugins/site config
|
|
1099
1059
|
for key, val in cls.ENV_VARS.items():
|
|
@@ -1129,7 +1089,6 @@ class ErtConfig(BaseModel):
|
|
|
1129
1089
|
prioritize_private_ip_address = user_prioritize_private_ip_address
|
|
1130
1090
|
|
|
1131
1091
|
try:
|
|
1132
|
-
refcase = Refcase.from_config_dict(config_dict)
|
|
1133
1092
|
cls_config = cls(
|
|
1134
1093
|
substitutions=substitutions,
|
|
1135
1094
|
ensemble_config=ensemble_config,
|
|
@@ -1151,9 +1110,6 @@ class ErtConfig(BaseModel):
|
|
|
1151
1110
|
runpath_config=model_config,
|
|
1152
1111
|
user_config_file=config_file_path,
|
|
1153
1112
|
observation_declarations=list(obs_configs),
|
|
1154
|
-
time_map=time_map,
|
|
1155
|
-
history_source=history_source,
|
|
1156
|
-
refcase=refcase,
|
|
1157
1113
|
prioritize_private_ip_address=prioritize_private_ip_address,
|
|
1158
1114
|
)
|
|
1159
1115
|
|
|
@@ -1171,7 +1127,6 @@ class ErtConfig(BaseModel):
|
|
|
1171
1127
|
)
|
|
1172
1128
|
cls_config._observations = create_observation_dataframes(
|
|
1173
1129
|
obs_configs,
|
|
1174
|
-
refcase,
|
|
1175
1130
|
cast(
|
|
1176
1131
|
GenDataConfig | None,
|
|
1177
1132
|
ensemble_config.response_configs.get("gen_data", None),
|
|
@@ -1180,8 +1135,6 @@ class ErtConfig(BaseModel):
|
|
|
1180
1135
|
RFTConfig | None,
|
|
1181
1136
|
ensemble_config.response_configs.get("rft", None),
|
|
1182
1137
|
),
|
|
1183
|
-
time_map,
|
|
1184
|
-
history_source,
|
|
1185
1138
|
)
|
|
1186
1139
|
except PydanticValidationError as err:
|
|
1187
1140
|
raise ConfigValidationError.from_pydantic(err) from err
|