ert 18.0.9__py3-none-any.whl → 19.0.0rc0__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.
Files changed (117) hide show
  1. _ert/forward_model_runner/client.py +6 -2
  2. ert/__main__.py +20 -6
  3. ert/analysis/_es_update.py +6 -19
  4. ert/cli/main.py +7 -3
  5. ert/config/__init__.py +3 -4
  6. ert/config/_create_observation_dataframes.py +57 -8
  7. ert/config/_get_num_cpu.py +1 -1
  8. ert/config/_observations.py +77 -1
  9. ert/config/distribution.py +1 -1
  10. ert/config/ensemble_config.py +3 -3
  11. ert/config/ert_config.py +50 -8
  12. ert/config/{ext_param_config.py → everest_control.py} +8 -12
  13. ert/config/everest_response.py +3 -5
  14. ert/config/field.py +76 -14
  15. ert/config/forward_model_step.py +12 -9
  16. ert/config/gen_data_config.py +3 -4
  17. ert/config/gen_kw_config.py +2 -12
  18. ert/config/parameter_config.py +1 -16
  19. ert/config/parsing/_option_dict.py +10 -2
  20. ert/config/parsing/config_keywords.py +1 -0
  21. ert/config/parsing/config_schema.py +8 -0
  22. ert/config/parsing/config_schema_deprecations.py +14 -3
  23. ert/config/parsing/config_schema_item.py +12 -3
  24. ert/config/parsing/context_values.py +3 -3
  25. ert/config/parsing/file_context_token.py +1 -1
  26. ert/config/parsing/observations_parser.py +6 -2
  27. ert/config/parsing/queue_system.py +9 -0
  28. ert/config/queue_config.py +0 -1
  29. ert/config/response_config.py +0 -1
  30. ert/config/rft_config.py +78 -33
  31. ert/config/summary_config.py +1 -2
  32. ert/config/surface_config.py +59 -16
  33. ert/dark_storage/common.py +1 -1
  34. ert/dark_storage/compute/misfits.py +4 -1
  35. ert/dark_storage/endpoints/compute/misfits.py +4 -2
  36. ert/dark_storage/endpoints/experiment_server.py +12 -9
  37. ert/dark_storage/endpoints/experiments.py +2 -2
  38. ert/dark_storage/endpoints/observations.py +4 -2
  39. ert/dark_storage/endpoints/parameters.py +2 -18
  40. ert/dark_storage/endpoints/responses.py +10 -5
  41. ert/dark_storage/json_schema/experiment.py +1 -1
  42. ert/data/_measured_data.py +6 -5
  43. ert/ensemble_evaluator/config.py +2 -1
  44. ert/field_utils/field_utils.py +1 -1
  45. ert/field_utils/grdecl_io.py +9 -26
  46. ert/field_utils/roff_io.py +1 -1
  47. ert/gui/__init__.py +5 -2
  48. ert/gui/ertnotifier.py +1 -1
  49. ert/gui/ertwidgets/pathchooser.py +0 -3
  50. ert/gui/ertwidgets/suggestor/suggestor.py +63 -30
  51. ert/gui/main.py +27 -5
  52. ert/gui/main_window.py +0 -5
  53. ert/gui/simulation/experiment_panel.py +12 -7
  54. ert/gui/simulation/run_dialog.py +2 -16
  55. ert/gui/summarypanel.py +0 -19
  56. ert/gui/tools/manage_experiments/export_dialog.py +136 -0
  57. ert/gui/tools/manage_experiments/storage_info_widget.py +110 -9
  58. ert/gui/tools/plot/plot_api.py +24 -15
  59. ert/gui/tools/plot/plot_widget.py +10 -2
  60. ert/gui/tools/plot/plot_window.py +26 -18
  61. ert/gui/tools/plot/plottery/plots/__init__.py +2 -0
  62. ert/gui/tools/plot/plottery/plots/cesp.py +3 -1
  63. ert/gui/tools/plot/plottery/plots/distribution.py +6 -1
  64. ert/gui/tools/plot/plottery/plots/ensemble.py +3 -1
  65. ert/gui/tools/plot/plottery/plots/gaussian_kde.py +12 -2
  66. ert/gui/tools/plot/plottery/plots/histogram.py +3 -1
  67. ert/gui/tools/plot/plottery/plots/misfits.py +436 -0
  68. ert/gui/tools/plot/plottery/plots/observations.py +18 -4
  69. ert/gui/tools/plot/plottery/plots/statistics.py +3 -1
  70. ert/gui/tools/plot/plottery/plots/std_dev.py +3 -1
  71. ert/plugins/hook_implementations/workflows/csv_export.py +2 -3
  72. ert/plugins/plugin_manager.py +4 -0
  73. ert/resources/forward_models/run_reservoirsimulator.py +8 -3
  74. ert/run_models/_create_run_path.py +3 -3
  75. ert/run_models/everest_run_model.py +13 -11
  76. ert/run_models/initial_ensemble_run_model.py +2 -2
  77. ert/run_models/run_model.py +30 -1
  78. ert/services/_base_service.py +6 -5
  79. ert/services/ert_server.py +4 -4
  80. ert/shared/_doc_utils/__init__.py +4 -2
  81. ert/shared/net_utils.py +43 -18
  82. ert/shared/version.py +3 -3
  83. ert/storage/__init__.py +2 -0
  84. ert/storage/local_ensemble.py +13 -7
  85. ert/storage/local_experiment.py +2 -2
  86. ert/storage/local_storage.py +41 -25
  87. ert/storage/migration/to11.py +1 -1
  88. ert/storage/migration/to18.py +0 -1
  89. ert/storage/migration/to19.py +34 -0
  90. ert/storage/migration/to20.py +23 -0
  91. ert/storage/migration/to21.py +25 -0
  92. ert/workflow_runner.py +2 -1
  93. {ert-18.0.9.dist-info → ert-19.0.0rc0.dist-info}/METADATA +1 -1
  94. {ert-18.0.9.dist-info → ert-19.0.0rc0.dist-info}/RECORD +112 -112
  95. {ert-18.0.9.dist-info → ert-19.0.0rc0.dist-info}/WHEEL +1 -1
  96. everest/bin/everlint_script.py +0 -2
  97. everest/bin/utils.py +2 -1
  98. everest/bin/visualization_script.py +4 -11
  99. everest/config/control_config.py +4 -4
  100. everest/config/control_variable_config.py +2 -2
  101. everest/config/everest_config.py +9 -0
  102. everest/config/utils.py +2 -2
  103. everest/config/validation_utils.py +7 -1
  104. everest/config_file_loader.py +0 -2
  105. everest/detached/client.py +3 -3
  106. everest/everest_storage.py +0 -2
  107. everest/gui/everest_client.py +2 -2
  108. everest/optimizer/everest2ropt.py +4 -4
  109. everest/optimizer/opt_model_transforms.py +2 -2
  110. ert/config/violations.py +0 -0
  111. ert/gui/tools/export/__init__.py +0 -3
  112. ert/gui/tools/export/export_panel.py +0 -83
  113. ert/gui/tools/export/export_tool.py +0 -69
  114. ert/gui/tools/export/exporter.py +0 -36
  115. {ert-18.0.9.dist-info → ert-19.0.0rc0.dist-info}/entry_points.txt +0 -0
  116. {ert-18.0.9.dist-info → ert-19.0.0rc0.dist-info}/licenses/COPYING +0 -0
  117. {ert-18.0.9.dist-info → ert-19.0.0rc0.dist-info}/top_level.txt +0 -0
@@ -2,8 +2,9 @@ from __future__ import annotations
2
2
 
3
3
  import asyncio
4
4
  import logging
5
+ import types
5
6
  import uuid
6
- from typing import Any, Self
7
+ from typing import Self
7
8
 
8
9
  import zmq
9
10
  import zmq.asyncio
@@ -67,7 +68,10 @@ class Client:
67
68
  return self
68
69
 
69
70
  async def __aexit__(
70
- self, exc_type: Any, exc_value: Any, exc_traceback: Any
71
+ self,
72
+ exc_type: type[BaseException] | None,
73
+ exc_value: BaseException | None,
74
+ exc_traceback: types.TracebackType | None,
71
75
  ) -> None:
72
76
  try:
73
77
  await self.send(DISCONNECT_MSG)
ert/__main__.py CHANGED
@@ -80,18 +80,32 @@ def run_webviz_ert(args: Namespace, _: ErtRuntimePlugins | None = None) -> None:
80
80
  # only use the base name of the config file path
81
81
  kwargs["ert_config"] = os.path.basename(args.config)
82
82
  kwargs["project"] = os.path.abspath(ens_path)
83
+
84
+ yellow = "\x1b[33m"
85
+ green = "\x1b[32m"
86
+ bold = "\x1b[1m"
87
+ reset = "\x1b[0m"
88
+
83
89
  try:
84
90
  with ErtServer.init_service(project=Path(ens_path).absolute()) as storage:
85
91
  storage.wait_until_ready()
86
92
  print(
87
- """
88
- -----------------------------------------------------------
93
+ f"""
94
+ ---------------------------------------------------------------
95
+
96
+ {yellow}{bold}Webviz-ERT is deprecated and will be removed in the near future{reset}
97
+
98
+ {green}{bold}Plotting capabilities provided by Webviz-ERT are now available
99
+ using the ERT plotter{reset}
100
+
101
+ ---------------------------------------------------------------
89
102
 
90
103
  Starting up Webviz-ERT. This might take more than a minute.
91
104
 
92
- -----------------------------------------------------------
105
+ ---------------------------------------------------------------
93
106
  """
94
107
  )
108
+ logger.info("Show Webviz-ert deprecation warning")
95
109
  webviz_kwargs = {
96
110
  "experimental_mode": args.experimental_mode,
97
111
  "verbose": args.verbose,
@@ -567,15 +581,15 @@ def get_ert_parser(parser: ArgumentParser | None = None) -> ArgumentParser:
567
581
  "--color-always",
568
582
  action="store_true",
569
583
  help="Force coloring of monitor output, which is automatically"
570
- + " disabled if the output stream is not a terminal.",
584
+ " disabled if the output stream is not a terminal.",
571
585
  default=False,
572
586
  )
573
587
  cli_parser.add_argument(
574
588
  "--disable-monitoring",
575
589
  action="store_true",
576
590
  help="Monitoring will continuously print the status of the realisations"
577
- + " classified into Waiting, Pending, Running, Failed, Finished"
578
- + " and Unknown.",
591
+ " classified into Waiting, Pending, Running, Failed, Finished"
592
+ " and Unknown.",
579
593
  default=False,
580
594
  )
581
595
  cli_parser.add_argument(
@@ -2,7 +2,6 @@ from __future__ import annotations
2
2
 
3
3
  import functools
4
4
  import logging
5
- import re
6
5
  import time
7
6
  import warnings
8
7
  from collections.abc import Callable, Iterable, Sequence
@@ -442,12 +441,6 @@ def smoother_update(
442
441
  with warnings.catch_warnings():
443
442
  original_showwarning = warnings.showwarning
444
443
 
445
- ILL_CONDITIONED_RE = re.compile(
446
- r"^LinAlgWarning:.*ill[- ]?conditioned\s+matrix", re.IGNORECASE
447
- )
448
- LIMIT_ILL_CONDITIONED_WARNING = 1000
449
- illconditioned_warn_counter = 0
450
-
451
444
  def log_warning(
452
445
  message: Warning | str,
453
446
  category: type[Warning],
@@ -456,18 +449,12 @@ def smoother_update(
456
449
  file: TextIO | None = None,
457
450
  line: str | None = None,
458
451
  ) -> None:
459
- nonlocal illconditioned_warn_counter
460
-
461
- if ILL_CONDITIONED_RE.search(str(message)):
462
- illconditioned_warn_counter += 1
463
-
464
- if illconditioned_warn_counter < LIMIT_ILL_CONDITIONED_WARNING:
465
- logger.warning(
466
- f"{category.__name__}: {message} (from {filename}:{lineno})"
467
- )
468
- original_showwarning(
469
- message, category, filename, lineno, file=file, line=line
470
- )
452
+ logger.warning(
453
+ f"{category.__name__}: {message} (from {filename}:{lineno})"
454
+ )
455
+ original_showwarning(
456
+ message, category, filename, lineno, file=file, line=line
457
+ )
471
458
 
472
459
  warnings.showwarning = log_warning
473
460
  analysis_ES(
ert/cli/main.py CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env python
2
1
  from __future__ import annotations
3
2
 
4
3
  import contextlib
@@ -7,6 +6,7 @@ import os
7
6
  import queue
8
7
  import sys
9
8
  from collections import Counter
9
+ from pathlib import Path
10
10
  from typing import TextIO
11
11
 
12
12
  from _ert.threading import ErtThread
@@ -27,7 +27,7 @@ from ert.namespace import Namespace
27
27
  from ert.plugins import ErtRuntimePlugins, get_site_plugins
28
28
  from ert.run_models.event import StatusEvents
29
29
  from ert.run_models.model_factory import create_model
30
- from ert.storage import open_storage
30
+ from ert.storage import LocalStorage, open_storage
31
31
  from ert.storage.local_storage import local_storage_set_ert_config
32
32
 
33
33
 
@@ -88,7 +88,10 @@ def run_cli(args: Namespace, runtime_plugins: ErtRuntimePlugins | None = None) -
88
88
  )
89
89
 
90
90
  if args.mode == WORKFLOW_MODE:
91
- with open_storage(ert_config.ens_path, "w") as storage:
91
+ path = Path(ert_config.ens_path)
92
+ if LocalStorage.check_migration_needed(path):
93
+ LocalStorage.perform_migration(path)
94
+ with open_storage(path, "w") as storage:
92
95
  execute_workflow(ert_config, storage, args.name)
93
96
  return
94
97
 
@@ -130,6 +133,7 @@ def run_cli(args: Namespace, runtime_plugins: ErtRuntimePlugins | None = None) -
130
133
  if args.port_range is None
131
134
  else (min(args.port_range), max(args.port_range) + 1),
132
135
  use_ipc_protocol=using_local_queuesystem,
136
+ prioritize_private_ip_address=ert_config.prioritize_private_ip_address,
133
137
  )
134
138
 
135
139
  if model.check_if_runpath_exists():
ert/config/__init__.py CHANGED
@@ -11,8 +11,8 @@ from .ensemble_config import EnsembleConfig
11
11
  from .ert_config import ErtConfig, forward_model_step_from_config_contents
12
12
  from .ert_plugin import ErtPlugin
13
13
  from .ert_script import ErtScript
14
+ from .everest_control import EverestControl, SamplerConfig
14
15
  from .everest_response import EverestConstraintsConfig, EverestObjectivesConfig
15
- from .ext_param_config import ExtParamConfig, SamplerConfig
16
16
  from .external_ert_script import ExternalErtScript
17
17
  from .field import Field, field_transform
18
18
  from .forward_model_step import (
@@ -31,7 +31,7 @@ from .gen_kw_config import DataSource, GenKwConfig, PriorDict
31
31
  from .known_response_types import KnownResponseTypes
32
32
  from .lint_file import lint_file
33
33
  from .model_config import ModelConfig
34
- from .parameter_config import ParameterCardinality, ParameterConfig, ParameterMetadata
34
+ from .parameter_config import ParameterCardinality, ParameterConfig
35
35
  from .parsing import (
36
36
  ConfigValidationError,
37
37
  ConfigWarning,
@@ -90,9 +90,9 @@ __all__ = [
90
90
  "ErtScript",
91
91
  "ErtScriptWorkflow",
92
92
  "EverestConstraintsConfig",
93
+ "EverestControl",
93
94
  "EverestObjectivesConfig",
94
95
  "ExecutableWorkflow",
95
- "ExtParamConfig",
96
96
  "ExternalErtScript",
97
97
  "Field",
98
98
  "ForwardModelStep",
@@ -119,7 +119,6 @@ __all__ = [
119
119
  "OutlierSettings",
120
120
  "ParameterCardinality",
121
121
  "ParameterConfig",
122
- "ParameterMetadata",
123
122
  "PostExperimentFixtures",
124
123
  "PostSimulationFixtures",
125
124
  "PostUpdateFixtures",
@@ -18,6 +18,7 @@ from ._observations import (
18
18
  Observation,
19
19
  ObservationDate,
20
20
  ObservationError,
21
+ RFTObservation,
21
22
  SummaryObservation,
22
23
  )
23
24
  from .gen_data_config import GenDataConfig
@@ -28,6 +29,7 @@ from .parsing import (
28
29
  ObservationConfigError,
29
30
  )
30
31
  from .refcase import Refcase
32
+ from .rft_config import RFTConfig
31
33
 
32
34
  if TYPE_CHECKING:
33
35
  import numpy.typing as npt
@@ -41,6 +43,7 @@ def create_observation_dataframes(
41
43
  observations: Sequence[Observation],
42
44
  refcase: Refcase | None,
43
45
  gen_data_config: GenDataConfig | None,
46
+ rft_config: RFTConfig | None,
44
47
  time_map: list[datetime] | None,
45
48
  history: HistorySource,
46
49
  ) -> dict[str, pl.DataFrame]:
@@ -56,7 +59,6 @@ def create_observation_dataframes(
56
59
  config_errors: list[ErrorInfo] = []
57
60
  grouped: dict[str, list[pl.DataFrame]] = defaultdict(list)
58
61
  for obs in observations:
59
- obs_name = obs.name
60
62
  try:
61
63
  match obs:
62
64
  case HistoryObservation():
@@ -64,7 +66,7 @@ def create_observation_dataframes(
64
66
  _handle_history_observation(
65
67
  refcase,
66
68
  obs,
67
- obs_name,
69
+ obs.name,
68
70
  history,
69
71
  time_len,
70
72
  )
@@ -73,7 +75,7 @@ def create_observation_dataframes(
73
75
  grouped["summary"].append(
74
76
  _handle_summary_observation(
75
77
  obs,
76
- obs_name,
78
+ obs.name,
77
79
  obs_time_list,
78
80
  bool(refcase),
79
81
  )
@@ -83,11 +85,18 @@ def create_observation_dataframes(
83
85
  _handle_general_observation(
84
86
  gen_data_config,
85
87
  obs,
86
- obs_name,
88
+ obs.name,
87
89
  obs_time_list,
88
90
  bool(refcase),
89
91
  )
90
92
  )
93
+ case RFTObservation():
94
+ if rft_config is None:
95
+ raise TypeError(
96
+ "create_observation_dataframes requires "
97
+ "rft_config is not None when using RFTObservation"
98
+ )
99
+ grouped["rft"].append(_handle_rft_observation(rft_config, obs))
91
100
  case default:
92
101
  assert_never(default)
93
102
  except ObservationConfigError as err:
@@ -460,10 +469,8 @@ def _handle_general_observation(
460
469
  stds = file_values[1::2]
461
470
 
462
471
  else:
463
- assert (
464
- general_observation.value is not None
465
- and general_observation.error is not None
466
- )
472
+ assert general_observation.value is not None
473
+ assert general_observation.error is not None
467
474
  values = np.array([general_observation.value])
468
475
  stds = np.array([general_observation.error])
469
476
 
@@ -509,3 +516,45 @@ def _handle_general_observation(
509
516
  "std": pl.Series(stds, dtype=pl.Float32),
510
517
  }
511
518
  )
519
+
520
+
521
+ def _handle_rft_observation(
522
+ rft_config: RFTConfig,
523
+ rft_observation: RFTObservation,
524
+ ) -> pl.DataFrame:
525
+ location = (rft_observation.east, rft_observation.north, rft_observation.tvd)
526
+ if location not in rft_config.locations:
527
+ rft_config.locations.append(location)
528
+
529
+ data_to_read = rft_config.data_to_read
530
+ if rft_observation.well not in data_to_read:
531
+ rft_config.data_to_read[rft_observation.well] = {}
532
+
533
+ well_dict = data_to_read[rft_observation.well]
534
+ if rft_observation.date not in well_dict:
535
+ well_dict[rft_observation.date] = []
536
+
537
+ property_list = well_dict[rft_observation.date]
538
+ if rft_observation.property not in property_list:
539
+ property_list.append(rft_observation.property)
540
+
541
+ if rft_observation.error <= 0.0:
542
+ raise ObservationConfigError.with_context(
543
+ "Observation uncertainty must be strictly > 0", rft_observation.well
544
+ )
545
+
546
+ return pl.DataFrame(
547
+ {
548
+ "response_key": (
549
+ f"{rft_observation.well}:"
550
+ f"{rft_observation.date}:"
551
+ f"{rft_observation.property}"
552
+ ),
553
+ "observation_key": rft_observation.name,
554
+ "east": pl.Series([location[0]], dtype=pl.Float32),
555
+ "north": pl.Series([location[1]], dtype=pl.Float32),
556
+ "tvd": pl.Series([location[2]], dtype=pl.Float32),
557
+ "observations": pl.Series([rft_observation.value], dtype=pl.Float32),
558
+ "std": pl.Series([rft_observation.error], dtype=pl.Float32),
559
+ }
560
+ )
@@ -156,7 +156,7 @@ class _Parser:
156
156
  def next_line(self) -> Iterator[str]: ...
157
157
 
158
158
  @overload
159
- def next_line(self, __default: T) -> Iterator[str] | T: ...
159
+ def next_line(self, __default: T, /) -> Iterator[str] | T: ...
160
160
 
161
161
  def next_line(self, *args: T) -> Iterator[str] | T:
162
162
  self.line_number += 1
@@ -214,12 +214,88 @@ class GeneralObservation(ObservationDate, _GeneralObservation):
214
214
  return output
215
215
 
216
216
 
217
- Observation = HistoryObservation | SummaryObservation | GeneralObservation
217
+ @dataclass
218
+ class RFTObservation:
219
+ name: str
220
+ well: str
221
+ date: str
222
+ property: str
223
+ value: float
224
+ error: float
225
+ north: float
226
+ east: float
227
+ tvd: float
228
+
229
+ @classmethod
230
+ def from_obs_dict(cls, directory: str, observation_dict: ObservationDict) -> Self:
231
+ well = None
232
+ observed_property = None
233
+ observed_value = None
234
+ error = None
235
+ date = None
236
+ north = None
237
+ east = None
238
+ tvd = None
239
+ for key, value in observation_dict.items():
240
+ match key:
241
+ case "type" | "name":
242
+ pass
243
+ case "WELL":
244
+ well = value
245
+ case "PROPERTY":
246
+ observed_property = value
247
+ case "VALUE":
248
+ observed_value = validate_float(value, key)
249
+ case "ERROR":
250
+ error = validate_float(value, key)
251
+ case "DATE":
252
+ date = value
253
+ case "NORTH":
254
+ north = validate_float(value, key)
255
+ case "EAST":
256
+ east = validate_float(value, key)
257
+ case "TVD":
258
+ tvd = validate_float(value, key)
259
+ case _:
260
+ raise _unknown_key_error(str(key), observation_dict["name"])
261
+ if well is None:
262
+ raise _missing_value_error(observation_dict["name"], "WELL")
263
+ if observed_value is None:
264
+ raise _missing_value_error(observation_dict["name"], "VALUE")
265
+ if observed_property is None:
266
+ raise _missing_value_error(observation_dict["name"], "PROPERTY")
267
+ if error is None:
268
+ raise _missing_value_error(observation_dict["name"], "ERROR")
269
+ if date is None:
270
+ raise _missing_value_error(observation_dict["name"], "DATE")
271
+ if north is None:
272
+ raise _missing_value_error(observation_dict["name"], "NORTH")
273
+ if east is None:
274
+ raise _missing_value_error(observation_dict["name"], "EAST")
275
+ if tvd is None:
276
+ raise _missing_value_error(observation_dict["name"], "TVD")
277
+ return cls(
278
+ observation_dict["name"],
279
+ well,
280
+ date,
281
+ observed_property,
282
+ observed_value,
283
+ error,
284
+ north,
285
+ east,
286
+ tvd,
287
+ )
288
+
289
+
290
+ Observation = (
291
+ HistoryObservation | SummaryObservation | GeneralObservation | RFTObservation
292
+ )
218
293
 
219
294
  _TYPE_TO_CLASS: dict[ObservationType, type[Observation]] = {
220
295
  ObservationType.HISTORY: HistoryObservation,
221
296
  ObservationType.SUMMARY: SummaryObservation,
222
297
  ObservationType.GENERAL: GeneralObservation,
298
+ ObservationType.RFT: RFTObservation,
223
299
  }
224
300
 
225
301
 
@@ -17,7 +17,7 @@ class TransSettingsValidation(BaseModel):
17
17
  model_config = {"extra": "forbid"}
18
18
 
19
19
  @classmethod
20
- def create(cls: type[T], *args: Any, **kwargs: Any) -> T:
20
+ def create(cls, *args: Any, **kwargs: Any) -> Self:
21
21
  return cls(*args, **kwargs)
22
22
 
23
23
  @classmethod
@@ -7,7 +7,7 @@ from typing import Self
7
7
 
8
8
  from pydantic import BaseModel, Field, model_validator
9
9
 
10
- from .ext_param_config import ExtParamConfig
10
+ from .everest_control import EverestControl
11
11
  from .field import Field as FieldConfig
12
12
  from .gen_kw_config import GenKwConfig
13
13
  from .known_response_types import KNOWN_ERT_RESPONSE_TYPES, KnownErtResponseTypes
@@ -22,7 +22,7 @@ logger = logging.getLogger(__name__)
22
22
  class EnsembleConfig(BaseModel):
23
23
  response_configs: dict[str, KnownErtResponseTypes] = Field(default_factory=dict)
24
24
  parameter_configs: dict[
25
- str, GenKwConfig | FieldConfig | SurfaceConfig | ExtParamConfig
25
+ str, GenKwConfig | FieldConfig | SurfaceConfig | EverestControl
26
26
  ] = Field(default_factory=dict)
27
27
 
28
28
  @model_validator(mode="after")
@@ -132,7 +132,7 @@ class EnsembleConfig(BaseModel):
132
132
  response_configs.append(instance)
133
133
 
134
134
  return cls(
135
- response_configs={response.name: response for response in response_configs},
135
+ response_configs={response.type: response for response in response_configs},
136
136
  parameter_configs={
137
137
  parameter.name: parameter for parameter in parameter_configs
138
138
  },
ert/config/ert_config.py CHANGED
@@ -25,6 +25,7 @@ from ._design_matrix_validator import DesignMatrixValidator
25
25
  from ._observations import (
26
26
  HistoryObservation,
27
27
  Observation,
28
+ RFTObservation,
28
29
  SummaryObservation,
29
30
  make_observations,
30
31
  )
@@ -62,6 +63,7 @@ from .parsing import (
62
63
  from .parsing.observations_parser import ObservationDict
63
64
  from .queue_config import KnownQueueOptions, QueueConfig
64
65
  from .refcase import Refcase
66
+ from .rft_config import RFTConfig
65
67
  from .workflow import Workflow
66
68
  from .workflow_fixtures import fixtures_per_hook
67
69
  from .workflow_job import (
@@ -686,14 +688,6 @@ def log_observation_keys(
686
688
  if key not in {"name", "type"}
687
689
  )
688
690
 
689
- if "HISTORY_OBSERVATION" in observation_type_counts:
690
- msg = (
691
- "HISTORY_OBSERVATION is deprecated and will be removed. "
692
- "Please use SUMMARY_OBSERVATION instead."
693
- )
694
- ConfigWarning.warn(msg)
695
- logger.warning(msg)
696
-
697
691
  logger.info(
698
692
  f"Count of observation types:\n\t{dict(observation_type_counts)}\n"
699
693
  f"Count of observation keywords:\n\t{dict(observation_keyword_counts)}"
@@ -715,6 +709,7 @@ class ErtConfig(BaseModel):
715
709
  QUEUE_OPTIONS: ClassVar[KnownQueueOptions | None] = None
716
710
  RESERVED_KEYWORDS: ClassVar[list[str]] = RESERVED_KEYWORDS
717
711
  ENV_VARS: ClassVar[dict[str, str]] = {}
712
+ PRIORITIZE_PRIVATE_IP_ADDRESS: ClassVar[bool] = False
718
713
 
719
714
  substitutions: dict[str, str] = Field(default_factory=dict)
720
715
  ensemble_config: EnsembleConfig = Field(default_factory=EnsembleConfig)
@@ -729,6 +724,7 @@ class ErtConfig(BaseModel):
729
724
  default_factory=lambda: defaultdict(lambda: cast(list[Workflow], []))
730
725
  )
731
726
  runpath_file: Path = Path(DEFAULT_RUNPATH_FILE)
727
+ prioritize_private_ip_address: bool = False
732
728
 
733
729
  ert_templates: list[tuple[str, str]] = Field(default_factory=list)
734
730
 
@@ -745,6 +741,18 @@ class ErtConfig(BaseModel):
745
741
  @property
746
742
  def observations(self) -> dict[str, pl.DataFrame]:
747
743
  if self._observations is None:
744
+ has_rft_observations = any(
745
+ isinstance(o, RFTObservation) for o in self.observation_declarations
746
+ )
747
+ if (
748
+ has_rft_observations
749
+ and "rft" not in self.ensemble_config.response_configs
750
+ ):
751
+ self.ensemble_config.response_configs["rft"] = RFTConfig(
752
+ input_files=[self.runpath_config.eclbase_format_string],
753
+ data_to_read={},
754
+ locations=[],
755
+ )
748
756
  computed = create_observation_dataframes(
749
757
  self.observation_declarations,
750
758
  self.refcase,
@@ -752,6 +760,10 @@ class ErtConfig(BaseModel):
752
760
  GenDataConfig | None,
753
761
  self.ensemble_config.response_configs.get("gen_data", None),
754
762
  ),
763
+ cast(
764
+ RFTConfig | None,
765
+ self.ensemble_config.response_configs.get("rft", None),
766
+ ),
755
767
  self.time_map,
756
768
  self.history_source,
757
769
  )
@@ -848,6 +860,9 @@ class ErtConfig(BaseModel):
848
860
  )
849
861
  ENV_VARS = dict(runtime_plugins.environment_variables)
850
862
  QUEUE_OPTIONS = runtime_plugins.queue_options
863
+ PRIORITIZE_PRIVATE_IP_ADDRESS = (
864
+ runtime_plugins.prioritize_private_ip_address
865
+ )
851
866
 
852
867
  ErtConfigWithPlugins.model_rebuild()
853
868
  assert issubclass(ErtConfigWithPlugins, ErtConfig)
@@ -1100,6 +1115,19 @@ class ErtConfig(BaseModel):
1100
1115
  user_configured_.add(key)
1101
1116
  env_vars[key] = substituter.substitute(val)
1102
1117
 
1118
+ prioritize_private_ip_address: bool = cls.PRIORITIZE_PRIVATE_IP_ADDRESS
1119
+ if ConfigKeys.PRIORITIZE_PRIVATE_IP_ADDRESS in config_dict:
1120
+ user_prioritize_private_ip_address = bool(
1121
+ config_dict[ConfigKeys.PRIORITIZE_PRIVATE_IP_ADDRESS]
1122
+ )
1123
+ if prioritize_private_ip_address != user_prioritize_private_ip_address:
1124
+ logger.warning(
1125
+ "PRIORITIZE_PRIVATE_IP_ADDRESS was overwritten by user: "
1126
+ f"{prioritize_private_ip_address} -> "
1127
+ f"{user_prioritize_private_ip_address}"
1128
+ )
1129
+ prioritize_private_ip_address = user_prioritize_private_ip_address
1130
+
1103
1131
  try:
1104
1132
  refcase = Refcase.from_config_dict(config_dict)
1105
1133
  cls_config = cls(
@@ -1126,11 +1154,21 @@ class ErtConfig(BaseModel):
1126
1154
  time_map=time_map,
1127
1155
  history_source=history_source,
1128
1156
  refcase=refcase,
1157
+ prioritize_private_ip_address=prioritize_private_ip_address,
1129
1158
  )
1130
1159
 
1131
1160
  # The observations are created here because create_observation_dataframes
1132
1161
  # will perform additonal validation which needs the context in
1133
1162
  # obs_configs which is stripped by pydantic
1163
+ has_rft_observations = any(
1164
+ isinstance(o, RFTObservation) for o in obs_configs
1165
+ )
1166
+ if has_rft_observations and "rft" not in ensemble_config.response_configs:
1167
+ ensemble_config.response_configs["rft"] = RFTConfig(
1168
+ input_files=[eclbase],
1169
+ data_to_read={},
1170
+ locations=[],
1171
+ )
1134
1172
  cls_config._observations = create_observation_dataframes(
1135
1173
  obs_configs,
1136
1174
  refcase,
@@ -1138,6 +1176,10 @@ class ErtConfig(BaseModel):
1138
1176
  GenDataConfig | None,
1139
1177
  ensemble_config.response_configs.get("gen_data", None),
1140
1178
  ),
1179
+ cast(
1180
+ RFTConfig | None,
1181
+ ensemble_config.response_configs.get("rft", None),
1182
+ ),
1141
1183
  time_map,
1142
1184
  history_source,
1143
1185
  )
@@ -17,7 +17,7 @@ from ropt.workflow import find_sampler_plugin
17
17
 
18
18
  from ert.substitutions import substitute_runpath_name
19
19
 
20
- from .parameter_config import ParameterConfig, ParameterMetadata
20
+ from .parameter_config import ParameterConfig
21
21
 
22
22
  if TYPE_CHECKING:
23
23
  import numpy.typing as npt
@@ -106,7 +106,7 @@ class SamplerConfig(BaseModel):
106
106
  # from "everest" here as per old behavior.
107
107
  # Can consider logging this as if from ERT,
108
108
  # which is valid if we store SamplerConfig as part of
109
- # ExtParam configs.
109
+ # EverestControl configs.
110
110
  logging.getLogger("everest").warning(message)
111
111
 
112
112
  # Update the default for backends that are not scipy:
@@ -142,22 +142,14 @@ class SamplerConfig(BaseModel):
142
142
  return self
143
143
 
144
144
 
145
- class ExtParamConfig(ParameterConfig):
146
- """Create an ExtParamConfig for @key with the given @input_keys
145
+ class EverestControl(ParameterConfig):
146
+ """Create an EverestControl for @key with the given @input_keys
147
147
 
148
148
  @input_keys can be either a list of keys as strings or a dict with
149
149
  keys as strings and a list of suffixes for each key.
150
150
  If a list of strings is given, the order is preserved.
151
151
  """
152
152
 
153
- @property
154
- def parameter_keys(self) -> list[str]:
155
- return self.input_keys
156
-
157
- @property
158
- def metadata(self) -> list[ParameterMetadata]:
159
- return []
160
-
161
153
  type: Literal["everest_parameters"] = "everest_parameters"
162
154
  input_keys: list[str] = field(default_factory=list)
163
155
  forward_init: bool = False
@@ -179,6 +171,10 @@ class ExtParamConfig(ParameterConfig):
179
171
  # "dotdash" notation is removed for everest controls via everest config.
180
172
  input_keys_dotdash: list[str] = field(default_factory=list)
181
173
 
174
+ @property
175
+ def parameter_keys(self) -> list[str]:
176
+ return self.input_keys
177
+
182
178
  def read_from_runpath(
183
179
  self, run_path: Path, real_nr: int, iteration: int
184
180
  ) -> xr.Dataset: