ert 17.1.7__py3-none-any.whl → 18.0.0__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 (165) hide show
  1. _ert/events.py +19 -2
  2. ert/__main__.py +8 -7
  3. ert/analysis/_enif_update.py +8 -4
  4. ert/analysis/_update_commons.py +16 -6
  5. ert/cli/main.py +6 -3
  6. ert/cli/monitor.py +7 -0
  7. ert/config/__init__.py +13 -3
  8. ert/config/_create_observation_dataframes.py +60 -12
  9. ert/config/_observations.py +14 -1
  10. ert/config/_read_summary.py +8 -6
  11. ert/config/ensemble_config.py +6 -14
  12. ert/config/ert_config.py +19 -13
  13. ert/config/{everest_objective_config.py → everest_response.py} +23 -12
  14. ert/config/ext_param_config.py +133 -1
  15. ert/config/field.py +12 -8
  16. ert/config/forward_model_step.py +108 -6
  17. ert/config/gen_data_config.py +2 -6
  18. ert/config/gen_kw_config.py +0 -9
  19. ert/config/known_response_types.py +14 -0
  20. ert/config/parameter_config.py +0 -17
  21. ert/config/parsing/config_keywords.py +1 -0
  22. ert/config/parsing/config_schema.py +12 -0
  23. ert/config/parsing/config_schema_deprecations.py +11 -0
  24. ert/config/parsing/config_schema_item.py +1 -1
  25. ert/config/queue_config.py +4 -4
  26. ert/config/response_config.py +0 -7
  27. ert/config/rft_config.py +230 -0
  28. ert/config/summary_config.py +2 -6
  29. ert/config/violations.py +0 -0
  30. ert/config/workflow_fixtures.py +2 -1
  31. ert/dark_storage/client/__init__.py +2 -2
  32. ert/dark_storage/client/_session.py +4 -4
  33. ert/dark_storage/client/client.py +2 -2
  34. ert/dark_storage/compute/misfits.py +7 -6
  35. ert/dark_storage/endpoints/compute/misfits.py +2 -2
  36. ert/dark_storage/endpoints/observations.py +4 -4
  37. ert/dark_storage/endpoints/responses.py +15 -1
  38. ert/ensemble_evaluator/__init__.py +8 -1
  39. ert/ensemble_evaluator/evaluator.py +81 -29
  40. ert/ensemble_evaluator/event.py +6 -0
  41. ert/ensemble_evaluator/snapshot.py +3 -1
  42. ert/ensemble_evaluator/state.py +1 -0
  43. ert/field_utils/__init__.py +8 -0
  44. ert/field_utils/field_utils.py +211 -1
  45. ert/gui/ertwidgets/__init__.py +23 -16
  46. ert/gui/ertwidgets/analysismoduleedit.py +2 -2
  47. ert/gui/ertwidgets/checklist.py +1 -1
  48. ert/gui/ertwidgets/create_experiment_dialog.py +3 -1
  49. ert/gui/ertwidgets/ensembleselector.py +2 -2
  50. ert/gui/ertwidgets/models/__init__.py +2 -0
  51. ert/gui/ertwidgets/models/activerealizationsmodel.py +2 -1
  52. ert/gui/ertwidgets/models/path_model.py +1 -1
  53. ert/gui/ertwidgets/models/targetensemblemodel.py +2 -1
  54. ert/gui/ertwidgets/models/text_model.py +1 -1
  55. ert/gui/ertwidgets/searchbox.py +13 -4
  56. ert/gui/{suggestor → ertwidgets/suggestor}/_suggestor_message.py +13 -4
  57. ert/gui/main.py +11 -6
  58. ert/gui/main_window.py +1 -2
  59. ert/gui/simulation/ensemble_experiment_panel.py +1 -1
  60. ert/gui/simulation/ensemble_information_filter_panel.py +1 -1
  61. ert/gui/simulation/ensemble_smoother_panel.py +1 -1
  62. ert/gui/simulation/evaluate_ensemble_panel.py +1 -1
  63. ert/gui/simulation/experiment_panel.py +1 -1
  64. ert/gui/simulation/manual_update_panel.py +31 -8
  65. ert/gui/simulation/multiple_data_assimilation_panel.py +12 -8
  66. ert/gui/simulation/run_dialog.py +25 -4
  67. ert/gui/simulation/single_test_run_panel.py +2 -2
  68. ert/gui/summarypanel.py +1 -1
  69. ert/gui/tools/load_results/load_results_panel.py +1 -1
  70. ert/gui/tools/manage_experiments/storage_info_widget.py +7 -7
  71. ert/gui/tools/manage_experiments/storage_widget.py +1 -2
  72. ert/gui/tools/plot/plot_api.py +13 -10
  73. ert/gui/tools/plot/plot_window.py +12 -0
  74. ert/gui/tools/plot/plottery/plot_config.py +2 -0
  75. ert/gui/tools/plot/plottery/plot_context.py +14 -0
  76. ert/gui/tools/plot/plottery/plots/ensemble.py +9 -2
  77. ert/gui/tools/plot/plottery/plots/statistics.py +59 -19
  78. ert/mode_definitions.py +2 -0
  79. ert/plugins/__init__.py +0 -1
  80. ert/plugins/hook_implementations/workflows/gen_data_rft_export.py +10 -2
  81. ert/plugins/hook_specifications/__init__.py +0 -2
  82. ert/plugins/hook_specifications/jobs.py +0 -9
  83. ert/plugins/plugin_manager.py +2 -33
  84. ert/resources/shell_scripts/delete_directory.py +2 -2
  85. ert/run_models/__init__.py +18 -5
  86. ert/run_models/_create_run_path.py +56 -23
  87. ert/run_models/ensemble_experiment.py +10 -4
  88. ert/run_models/ensemble_information_filter.py +8 -1
  89. ert/run_models/ensemble_smoother.py +9 -3
  90. ert/run_models/evaluate_ensemble.py +8 -6
  91. ert/run_models/event.py +7 -3
  92. ert/run_models/everest_run_model.py +155 -44
  93. ert/run_models/initial_ensemble_run_model.py +23 -22
  94. ert/run_models/manual_update.py +4 -2
  95. ert/run_models/manual_update_enif.py +37 -0
  96. ert/run_models/model_factory.py +81 -22
  97. ert/run_models/multiple_data_assimilation.py +21 -10
  98. ert/run_models/run_model.py +54 -34
  99. ert/run_models/single_test_run.py +7 -4
  100. ert/run_models/update_run_model.py +4 -2
  101. ert/runpaths.py +5 -6
  102. ert/sample_prior.py +9 -4
  103. ert/scheduler/driver.py +37 -0
  104. ert/scheduler/event.py +3 -1
  105. ert/scheduler/job.py +23 -13
  106. ert/scheduler/lsf_driver.py +6 -2
  107. ert/scheduler/openpbs_driver.py +7 -1
  108. ert/scheduler/scheduler.py +5 -0
  109. ert/scheduler/slurm_driver.py +6 -2
  110. ert/services/__init__.py +2 -2
  111. ert/services/_base_service.py +31 -15
  112. ert/services/ert_server.py +317 -0
  113. ert/shared/_doc_utils/ert_jobs.py +1 -4
  114. ert/shared/storage/connection.py +3 -3
  115. ert/shared/version.py +3 -3
  116. ert/storage/local_ensemble.py +25 -5
  117. ert/storage/local_experiment.py +6 -14
  118. ert/storage/local_storage.py +35 -30
  119. ert/storage/migration/to18.py +12 -0
  120. ert/storage/migration/to8.py +4 -4
  121. ert/substitutions.py +12 -28
  122. ert/validation/active_range.py +7 -7
  123. ert/validation/rangestring.py +16 -16
  124. {ert-17.1.7.dist-info → ert-18.0.0.dist-info}/METADATA +8 -7
  125. {ert-17.1.7.dist-info → ert-18.0.0.dist-info}/RECORD +160 -159
  126. everest/bin/config_branch_script.py +3 -6
  127. everest/bin/everconfigdump_script.py +1 -9
  128. everest/bin/everest_script.py +21 -11
  129. everest/bin/kill_script.py +2 -2
  130. everest/bin/monitor_script.py +2 -2
  131. everest/bin/utils.py +6 -3
  132. everest/config/__init__.py +4 -1
  133. everest/config/control_config.py +61 -2
  134. everest/config/control_variable_config.py +2 -1
  135. everest/config/everest_config.py +38 -16
  136. everest/config/forward_model_config.py +5 -3
  137. everest/config/install_data_config.py +7 -5
  138. everest/config/install_job_config.py +7 -3
  139. everest/config/install_template_config.py +3 -3
  140. everest/config/optimization_config.py +19 -6
  141. everest/config/output_constraint_config.py +8 -2
  142. everest/config/server_config.py +6 -49
  143. everest/config/utils.py +25 -105
  144. everest/config/validation_utils.py +10 -10
  145. everest/config_file_loader.py +13 -2
  146. everest/detached/everserver.py +7 -8
  147. everest/everest_storage.py +6 -10
  148. everest/gui/everest_client.py +0 -1
  149. everest/gui/main_window.py +2 -2
  150. everest/optimizer/everest2ropt.py +59 -32
  151. everest/optimizer/opt_model_transforms.py +12 -13
  152. everest/optimizer/utils.py +0 -29
  153. everest/strings.py +0 -5
  154. ert/config/everest_constraints_config.py +0 -95
  155. ert/services/storage_service.py +0 -127
  156. everest/config/sampler_config.py +0 -103
  157. everest/simulator/__init__.py +0 -88
  158. everest/simulator/everest_to_ert.py +0 -51
  159. /ert/gui/{suggestor → ertwidgets/suggestor}/__init__.py +0 -0
  160. /ert/gui/{suggestor → ertwidgets/suggestor}/_colors.py +0 -0
  161. /ert/gui/{suggestor → ertwidgets/suggestor}/suggestor.py +0 -0
  162. {ert-17.1.7.dist-info → ert-18.0.0.dist-info}/WHEEL +0 -0
  163. {ert-17.1.7.dist-info → ert-18.0.0.dist-info}/entry_points.txt +0 -0
  164. {ert-17.1.7.dist-info → ert-18.0.0.dist-info}/licenses/COPYING +0 -0
  165. {ert-17.1.7.dist-info → ert-18.0.0.dist-info}/top_level.txt +0 -0
@@ -5,8 +5,6 @@ from pathlib import Path
5
5
  from textwrap import dedent
6
6
  from typing import Any
7
7
 
8
- from ruamel.yaml import YAML
9
-
10
8
  from everest.bin.utils import setup_logging
11
9
  from everest.config import EverestConfig
12
10
  from everest.config_file_loader import load_yaml
@@ -139,10 +137,9 @@ def config_branch_entry(args: list[str] | None = None) -> None:
139
137
  conf_controls=yml_config["controls"], opt_controls=opt_controls
140
138
  )
141
139
 
142
- yaml = YAML()
143
- yaml.indent(mapping=2, sequence=4, offset=2)
144
- yaml.preserve_quotes = True
145
- yaml.dump(yml_config, Path(options.output_config))
140
+ EverestConfig.write_dict_to_file(
141
+ yml_config, Path(options.output_config), safe_and_pure=False
142
+ )
146
143
  print(f"New config file {options.output_config} created.")
147
144
 
148
145
 
@@ -3,8 +3,6 @@
3
3
  import argparse
4
4
  import sys
5
5
 
6
- from ruamel.yaml import YAML
7
-
8
6
  from everest.config import EverestConfig
9
7
 
10
8
 
@@ -26,13 +24,7 @@ def _build_args_parser() -> argparse.ArgumentParser:
26
24
  def config_dump_entry(args: list[str] | None = None) -> None:
27
25
  parser = _build_args_parser()
28
26
  options = parser.parse_args(args)
29
-
30
- config = EverestConfig.load_file(options.config_file)
31
-
32
- yaml = YAML(typ="safe", pure=True)
33
- yaml.indent = 2
34
- yaml.default_flow_style = False
35
- yaml.dump(config.to_dict(), sys.stdout)
27
+ EverestConfig.load_file(options.config_file).write_to_file(sys.stdout)
36
28
 
37
29
 
38
30
  if __name__ == "__main__":
@@ -3,7 +3,6 @@ import argparse
3
3
  import asyncio
4
4
  import json
5
5
  import logging
6
- import os
7
6
  import signal
8
7
  import socket
9
8
  import threading
@@ -11,9 +10,11 @@ from functools import partial
11
10
  from pathlib import Path
12
11
  from textwrap import dedent
13
12
 
13
+ import anyio
14
+
14
15
  from _ert.threading import ErtThread
15
16
  from ert.config import QueueSystem
16
- from ert.services import StorageService
17
+ from ert.services import ErtServer
17
18
  from ert.storage.local_experiment import ExperimentState
18
19
  from everest.config import EverestConfig, ServerConfig
19
20
  from everest.detached import (
@@ -168,7 +169,7 @@ async def run_everest(options: argparse.Namespace) -> None:
168
169
  )
169
170
 
170
171
  try:
171
- StorageService.session(
172
+ ErtServer.session(
172
173
  Path(ServerConfig.get_session_dir(options.config.output_dir)), timeout=1
173
174
  )
174
175
  server_running = True
@@ -193,18 +194,27 @@ async def run_everest(options: argparse.Namespace) -> None:
193
194
  job_name = fm_job.split()[0]
194
195
  logger.info(f"Everest forward model contains job {job_name}")
195
196
 
196
- if os.path.exists(options.config.simulation_dir) and any(
197
- os.listdir(options.config.simulation_dir)
198
- ):
197
+ async def directory_is_nonempty(path: Path) -> bool:
198
+ try:
199
+ async for _ in anyio.Path(path).iterdir():
200
+ return True
201
+ except OSError: # Raised if the directory is empty
202
+ return False
203
+ else:
204
+ return False
205
+
206
+ if await anyio.Path(
207
+ options.config.simulation_dir
208
+ ).exists() and await directory_is_nonempty(options.config.simulation_dir):
199
209
  warn_user_that_runpath_is_nonempty()
200
210
  if not options.skip_prompt:
201
211
  show_scaled_controls_warning()
202
212
 
203
213
  try:
204
- output_dir = options.config.output_dir
205
- config_file = options.config.config_file
206
- save_config_path = os.path.join(output_dir, config_file)
207
- options.config.dump(save_config_path)
214
+ output_dir = Path(options.config.output_dir)
215
+ options.config.write_to_file(
216
+ output_dir / options.config.config_file, drop_config_path=True
217
+ )
208
218
  except (OSError, LookupError) as e:
209
219
  logger.error(f"Failed to save optimization config: {e}")
210
220
 
@@ -223,7 +233,7 @@ async def run_everest(options: argparse.Namespace) -> None:
223
233
 
224
234
  print("Waiting for server ...")
225
235
  logger.debug("Waiting for response from everserver")
226
- client = StorageService.session(
236
+ client = ErtServer.session(
227
237
  Path(ServerConfig.get_session_dir(options.config.output_dir))
228
238
  )
229
239
  wait_for_server(client, timeout=600)
@@ -12,7 +12,7 @@ from functools import partial
12
12
  from pathlib import Path
13
13
  from typing import Any
14
14
 
15
- from ert.services import StorageService
15
+ from ert.services import ErtServer
16
16
  from everest.bin.utils import setup_logging
17
17
  from everest.config import EverestConfig, ServerConfig
18
18
  from everest.detached import stop_server, wait_for_server_to_stop
@@ -74,7 +74,7 @@ def _handle_keyboard_interrupt(signal: int, _: Any, after: bool = False) -> None
74
74
 
75
75
  def kill_everest(options: argparse.Namespace) -> None:
76
76
  try:
77
- client = StorageService.session(
77
+ client = ErtServer.session(
78
78
  Path(ServerConfig.get_session_dir(options.config.output_dir)), timeout=1
79
79
  )
80
80
  server_context = ServerConfig.get_server_context_from_conn_info(
@@ -7,7 +7,7 @@ from functools import partial
7
7
  from pathlib import Path
8
8
  from textwrap import dedent
9
9
 
10
- from ert.services import StorageService
10
+ from ert.services import ErtServer
11
11
  from ert.storage import ErtStorageException, ExperimentState
12
12
  from everest.config import EverestConfig, ServerConfig
13
13
  from everest.everest_storage import EverestStorage
@@ -82,7 +82,7 @@ def _build_args_parser() -> argparse.ArgumentParser:
82
82
  def monitor_everest(options: argparse.Namespace) -> None:
83
83
  config: EverestConfig = options.config
84
84
  try:
85
- with StorageService.session(
85
+ with ErtServer.session(
86
86
  Path(ServerConfig.get_session_dir(config.output_dir)), timeout=1
87
87
  ) as client:
88
88
  server_context = ServerConfig.get_server_context_from_conn_info(
everest/bin/utils.py CHANGED
@@ -26,7 +26,7 @@ from ert.ensemble_evaluator import (
26
26
  from ert.ensemble_evaluator.event import EndEvent
27
27
  from ert.logging import LOGGING_CONFIG
28
28
  from ert.plugins.plugin_manager import ErtPluginManager
29
- from ert.services import StorageService
29
+ from ert.services import ErtServer
30
30
  from ert.storage import (
31
31
  ExperimentStatus,
32
32
  open_storage,
@@ -39,10 +39,13 @@ from everest.detached import (
39
39
  stop_server,
40
40
  wait_for_server_to_stop,
41
41
  )
42
- from everest.simulator import JOB_FAILURE, JOB_RUNNING, JOB_SUCCESS
43
42
  from everest.strings import EVEREST, OPT_PROGRESS_ID, SIM_PROGRESS_ID
44
43
  from everest.util import makedirs_if_needed
45
44
 
45
+ JOB_SUCCESS = "Finished"
46
+ JOB_RUNNING = "Running"
47
+ JOB_FAILURE = "Failed"
48
+
46
49
 
47
50
  def cleanup_logging() -> None:
48
51
  os.environ.pop("ERT_LOG_DIR", None)
@@ -103,7 +106,7 @@ def handle_keyboard_interrupt(signum: int, _: Any, options: argparse.Namespace)
103
106
  "The optimization will be stopped and the program will exit..."
104
107
  )
105
108
  try:
106
- client = StorageService.session(
109
+ client = ErtServer.session(
107
110
  Path(ServerConfig.get_session_dir(options.config.output_dir))
108
111
  )
109
112
  server_context = ServerConfig.get_server_context_from_conn_info(
@@ -1,3 +1,5 @@
1
+ from ert.config import SamplerConfig
2
+
1
3
  from .control_config import ControlConfig
2
4
  from .control_variable_config import (
3
5
  ControlVariableConfig,
@@ -6,6 +8,7 @@ from .control_variable_config import (
6
8
  from .cvar_config import CVaRConfig
7
9
  from .environment_config import EnvironmentConfig
8
10
  from .everest_config import EverestConfig, EverestValidationError
11
+ from .forward_model_config import ForwardModelStepConfig
9
12
  from .input_constraint_config import InputConstraintConfig
10
13
  from .install_data_config import InstallDataConfig
11
14
  from .install_job_config import InstallJobConfig
@@ -14,7 +17,6 @@ from .model_config import ModelConfig
14
17
  from .objective_function_config import ObjectiveFunctionConfig
15
18
  from .optimization_config import OptimizationConfig
16
19
  from .output_constraint_config import OutputConstraintConfig
17
- from .sampler_config import SamplerConfig
18
20
  from .server_config import ServerConfig
19
21
  from .simulator_config import SimulatorConfig
20
22
  from .well_config import WellConfig
@@ -28,6 +30,7 @@ __all__ = [
28
30
  "EnvironmentConfig",
29
31
  "EverestConfig",
30
32
  "EverestValidationError",
33
+ "ForwardModelStepConfig",
31
34
  "InputConstraintConfig",
32
35
  "InstallDataConfig",
33
36
  "InstallJobConfig",
@@ -12,13 +12,12 @@ from typing import (
12
12
  from pydantic import AfterValidator, BaseModel, ConfigDict, Field, model_validator
13
13
  from ropt.enums import PerturbationType, VariableType
14
14
 
15
- from ert.config import ExtParamConfig
15
+ from ert.config import ExtParamConfig, SamplerConfig
16
16
 
17
17
  from .control_variable_config import (
18
18
  ControlVariableConfig,
19
19
  ControlVariableGuessListConfig,
20
20
  )
21
- from .sampler_config import SamplerConfig
22
21
  from .validation_utils import (
23
22
  control_variables_validation,
24
23
  no_dots_in_string,
@@ -314,8 +313,68 @@ class ControlConfig(BaseModel):
314
313
  )
315
314
 
316
315
  def to_ert_parameter_config(self) -> ExtParamConfig:
316
+ types = []
317
+ initial_guesses = []
318
+ control_types = []
319
+ enabled = []
320
+ mins = []
321
+ maxs = []
322
+ perturbation_types = []
323
+ perturbation_magnitudes = []
324
+ scaled_ranges = []
325
+ samplers = []
326
+
327
+ def _parse_variable(
328
+ variable: ControlVariableConfig | ControlVariableGuessListConfig,
329
+ initial_guess: float | None = None,
330
+ ) -> None:
331
+ types.append(self.type)
332
+ initial_guesses.append(
333
+ initial_guess
334
+ if initial_guess is not None
335
+ else variable.initial_guess
336
+ if variable.initial_guess is not None
337
+ else self.initial_guess
338
+ )
339
+ control_types.append(self.control_type)
340
+ enabled.append(
341
+ variable.enabled if variable.enabled is not None else self.enabled
342
+ )
343
+ mins.append(variable.min if variable.min is not None else self.min)
344
+ maxs.append(variable.max if variable.max is not None else self.max)
345
+ perturbation_types.append(variable.perturbation_type)
346
+ perturbation_magnitudes.append(
347
+ variable.perturbation_magnitude
348
+ if variable.perturbation_magnitude is not None
349
+ else self.perturbation_magnitude
350
+ )
351
+ scaled_ranges.append(
352
+ variable.scaled_range
353
+ if variable.scaled_range is not None
354
+ else self.scaled_range
355
+ )
356
+ samplers.append(variable.sampler or self.sampler)
357
+
358
+ for variable in self.variables:
359
+ if isinstance(variable, ControlVariableConfig):
360
+ _parse_variable(variable)
361
+ else:
362
+ for initial_guess in variable.initial_guess:
363
+ _parse_variable(variable, initial_guess=initial_guess)
364
+
317
365
  return ExtParamConfig(
318
366
  name=self.name,
319
367
  input_keys=self.formatted_control_names,
368
+ input_keys_dotdash=self.formatted_control_names_dotdash,
320
369
  output_file=self.name + ".json",
370
+ types=types,
371
+ initial_guesses=initial_guesses,
372
+ control_types=control_types,
373
+ enabled=enabled,
374
+ min=mins,
375
+ max=maxs,
376
+ perturbation_types=perturbation_types,
377
+ perturbation_magnitudes=perturbation_magnitudes,
378
+ scaled_ranges=scaled_ranges,
379
+ samplers=samplers,
321
380
  )
@@ -12,7 +12,8 @@ from pydantic import (
12
12
  )
13
13
  from ropt.enums import VariableType
14
14
 
15
- from .sampler_config import SamplerConfig
15
+ from ert.config import SamplerConfig
16
+
16
17
  from .validation_utils import no_dots_in_string, valid_range
17
18
 
18
19
 
@@ -2,7 +2,6 @@ import logging
2
2
  import os
3
3
  from argparse import ArgumentParser
4
4
  from copy import copy
5
- from io import StringIO
6
5
  from itertools import chain
7
6
  from pathlib import Path
8
7
  from sys import float_info
@@ -12,6 +11,7 @@ from typing import (
12
11
  Any,
13
12
  Optional,
14
13
  Self,
14
+ TextIO,
15
15
  TypeVar,
16
16
  no_type_check,
17
17
  )
@@ -30,7 +30,12 @@ from pydantic_core.core_schema import ValidationInfo
30
30
  from ruamel.yaml import YAML, YAMLError
31
31
 
32
32
  from ert.base_model_context import BaseModelWithContextSupport, use_runtime_plugins
33
- from ert.config import ConfigWarning, EverestObjectivesConfig, QueueSystem
33
+ from ert.config import (
34
+ ConfigWarning,
35
+ EverestConstraintsConfig,
36
+ EverestObjectivesConfig,
37
+ QueueSystem,
38
+ )
34
39
  from ert.plugins import get_site_plugins
35
40
  from everest.config.install_template_config import InstallTemplateConfig
36
41
  from everest.config.server_config import ServerConfig
@@ -1076,22 +1081,25 @@ to read summary data from forward model, do:
1076
1081
  except ValueError as e:
1077
1082
  parser.error(f"Loading config file <{config_path}> failed with: {e}")
1078
1083
 
1079
- def dump(self, fname: str | None = None) -> str | None:
1080
- """Write a config dict to file or return it if fname is None."""
1081
- stripped_conf = self.to_dict()
1082
-
1083
- del stripped_conf["config_path"]
1084
+ def write_to_file(
1085
+ self, output_file: str | Path | TextIO, drop_config_path: bool = False
1086
+ ) -> None:
1087
+ dictconf = self.to_dict()
1088
+ if drop_config_path:
1089
+ del dictconf["config_path"]
1090
+ if isinstance(output_file, str):
1091
+ output_file = Path(output_file)
1092
+ self.write_dict_to_file(dictconf, output_file)
1084
1093
 
1085
- yaml = YAML(typ="safe", pure=True)
1094
+ @staticmethod
1095
+ def write_dict_to_file(
1096
+ config: dict[str, Any], output_file: Path | TextIO, safe_and_pure: bool = True
1097
+ ) -> None:
1098
+ yaml = YAML(typ="safe", pure=True) if safe_and_pure else YAML()
1099
+ yaml.indent(mapping=2, sequence=4, offset=2)
1100
+ yaml.preserve_quotes = True
1086
1101
  yaml.default_flow_style = False
1087
- if fname is None:
1088
- with StringIO() as sio:
1089
- yaml.dump(stripped_conf, sio)
1090
- return sio.getvalue()
1091
-
1092
- yaml.dump(stripped_conf, Path(fname))
1093
-
1094
- return None
1102
+ yaml.dump(config, output_file)
1095
1103
 
1096
1104
  @property
1097
1105
  def server_queue_system(self) -> QueueSystem:
@@ -1108,3 +1116,17 @@ to read summary data from forward model, do:
1108
1116
  scales=[o.scale for o in self.objective_functions],
1109
1117
  objective_types=[o.type for o in self.objective_functions],
1110
1118
  )
1119
+
1120
+ def create_ert_output_constraints_config(self) -> EverestConstraintsConfig | None:
1121
+ if len(self.output_constraints) == 0:
1122
+ return None
1123
+
1124
+ constraint_names = [c.name for c in self.output_constraints]
1125
+ return EverestConstraintsConfig(
1126
+ keys=constraint_names,
1127
+ input_files=constraint_names,
1128
+ scales=[c.scale for c in self.output_constraints],
1129
+ targets=[c.target for c in self.output_constraints],
1130
+ upper_bounds=[c.upper_bound for c in self.output_constraints],
1131
+ lower_bounds=[c.lower_bound for c in self.output_constraints],
1132
+ )
@@ -9,7 +9,9 @@ from pydantic import (
9
9
  )
10
10
 
11
11
  from ert.base_model_context import BaseModelWithContextSupport
12
- from ert.config import ForwardModelStep
12
+ from ert.config import (
13
+ SiteOrUserForwardModelStep,
14
+ )
13
15
 
14
16
 
15
17
  class ForwardModelResult(BaseModelWithContextSupport):
@@ -74,8 +76,8 @@ class ForwardModelStepConfig(BaseModelWithContextSupport):
74
76
  return values
75
77
 
76
78
  def to_ert_forward_model_step(
77
- self, installed_fm_steps: dict[str, ForwardModelStep]
78
- ) -> ForwardModelStep:
79
+ self, installed_fm_steps: dict[str, SiteOrUserForwardModelStep]
80
+ ) -> SiteOrUserForwardModelStep:
79
81
  fm_name, *arglist = self.job.split()
80
82
  match fm_name:
81
83
  # All three reservoir simulator fm_steps map to
@@ -9,11 +9,13 @@ from typing import Any
9
9
 
10
10
  from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
11
11
 
12
- from ert.config import ForwardModelStep
12
+ from ert.config.forward_model_step import (
13
+ SiteOrUserForwardModelStep,
14
+ )
13
15
 
14
16
 
15
17
  def _is_dir_all_model(source: str, model_realizations: list[int]) -> bool:
16
- """Expands <GEO_ID> for all realizations and if:
18
+ """Expands <REALIZATION_ID> for all realizations and if:
17
19
  - all are directories, returns True,
18
20
  - all are files, returns False,
19
21
  - some are non-existing, raises an AssertionError
@@ -21,7 +23,7 @@ def _is_dir_all_model(source: str, model_realizations: list[int]) -> bool:
21
23
 
22
24
  is_dir = []
23
25
  for model_realization in model_realizations:
24
- model_source = source.replace("<GEO_ID>", str(model_realization))
26
+ model_source = source.replace("<REALIZATION_ID>", str(model_realization))
25
27
  if not os.path.exists(model_source):
26
28
  msg = (
27
29
  "Expected source to exist for data installation, "
@@ -126,8 +128,8 @@ class InstallDataConfig(BaseModel):
126
128
  config_directory: str,
127
129
  output_directory: str,
128
130
  model_realizations: list[int],
129
- installed_fm_steps: dict[str, ForwardModelStep],
130
- ) -> ForwardModelStep:
131
+ installed_fm_steps: dict[str, SiteOrUserForwardModelStep],
132
+ ) -> SiteOrUserForwardModelStep:
131
133
  target = self.target
132
134
 
133
135
  def _missing_fm_msg(fm_name: str) -> str:
@@ -7,7 +7,7 @@ from pydantic import BaseModel, Field, model_validator
7
7
 
8
8
  from ert.config import (
9
9
  ExecutableWorkflow,
10
- ForwardModelStep,
10
+ UserInstalledForwardModelStep,
11
11
  forward_model_step_from_config_contents,
12
12
  workflow_job_from_file,
13
13
  )
@@ -57,12 +57,16 @@ class InstallJobConfig(BaseModel, extra="forbid"):
57
57
 
58
58
 
59
59
  class InstallForwardModelStepConfig(InstallJobConfig):
60
- def to_ert_forward_model_step(self, config_directory: str) -> ForwardModelStep:
60
+ def to_ert_forward_model_step(
61
+ self, config_directory: str
62
+ ) -> UserInstalledForwardModelStep:
61
63
  if self.executable is not None:
62
64
  executable = Path(self.executable)
63
65
  if not executable.is_absolute():
64
66
  executable = Path(config_directory) / executable
65
- return ForwardModelStep(name=self.name, executable=str(executable))
67
+ return UserInstalledForwardModelStep(
68
+ name=self.name, executable=str(executable)
69
+ )
66
70
  else:
67
71
  assert (
68
72
  self.source is not None
@@ -4,7 +4,7 @@ from textwrap import dedent
4
4
 
5
5
  from pydantic import BaseModel, Field
6
6
 
7
- from ert.config import ForwardModelStep
7
+ from ert.config import SiteOrUserForwardModelStep
8
8
  from everest.strings import EVEREST
9
9
 
10
10
 
@@ -38,9 +38,9 @@ class InstallTemplateConfig(BaseModel, extra="forbid"):
38
38
  def to_ert_forward_model_step(
39
39
  self,
40
40
  control_names: list[str],
41
- installed_fm_steps: dict[str, ForwardModelStep],
41
+ installed_fm_steps: dict[str, SiteOrUserForwardModelStep],
42
42
  well_path: str,
43
- ) -> ForwardModelStep:
43
+ ) -> SiteOrUserForwardModelStep:
44
44
  fm_step_instance = copy.deepcopy(installed_fm_steps.get("template_render"))
45
45
  if fm_step_instance is None:
46
46
  raise KeyError(
@@ -1,11 +1,12 @@
1
+ import importlib
1
2
  import logging
2
3
  from textwrap import dedent
3
4
  from typing import Any, Self
4
5
 
5
6
  from pydantic import BaseModel, Field, model_validator
7
+ from ropt.workflow import find_optimizer_plugin, validate_optimizer_options
6
8
 
7
9
  from everest.config.cvar_config import CVaRConfig
8
- from everest.optimizer.utils import get_ropt_plugin_manager
9
10
  from everest.strings import EVEREST
10
11
 
11
12
 
@@ -346,15 +347,27 @@ class OptimizationConfig(BaseModel, extra="forbid"):
346
347
  else f"{self.backend}/{self.algorithm}"
347
348
  )
348
349
 
349
- plugin_manager = get_ropt_plugin_manager()
350
- plugin_name = plugin_manager.get_plugin_name("optimizer", algorithm)
350
+ try:
351
+ plugin_name = find_optimizer_plugin(algorithm)
352
+ except ValueError:
353
+ raise
354
+ except Exception as exc:
355
+ ert_version = importlib.metadata.version("ert")
356
+ ropt_version = importlib.metadata.version("ropt")
357
+ msg = (
358
+ f"Error while initializing ropt:\n\n{exc}.\n\n"
359
+ "There may a be version mismatch between "
360
+ f"ERT ({ert_version}) and ropt ({ropt_version})\n"
361
+ "If the installation is correct, please report this as a bug."
362
+ )
363
+ raise RuntimeError(msg) from exc
351
364
  if plugin_name is None:
352
365
  raise ValueError(f"Optimizer algorithm '{algorithm}' not found")
353
366
  self._optimization_plugin_name = plugin_name
354
367
 
355
- plugin_manager.get_plugin("optimizer", algorithm).validate_options(
356
- self.algorithm, self.options or self.backend_options
357
- )
368
+ options = self.options or self.backend_options
369
+ if options:
370
+ validate_optimizer_options(algorithm, options)
358
371
 
359
372
  self.backend = None
360
373
  self.algorithm = algorithm
@@ -74,10 +74,16 @@ class OutputConstraintConfig(BaseModel, extra="forbid"):
74
74
  @model_validator(mode="before")
75
75
  @classmethod
76
76
  def validate_target_or_bounds(cls, values: dict[str, Any]) -> dict[str, Any]:
77
- if "target" in values and ("lower_bound" in values or "upper_bound" in values):
77
+ if (values.get("target") is not None) and (
78
+ "lower_bound" in values or "upper_bound" in values
79
+ ):
78
80
  raise ValueError("Can not combine target and bounds")
79
81
  elif not any(
80
- ("target" in values, "lower_bound" in values, "upper_bound" in values)
82
+ (
83
+ (values.get("target") is not None),
84
+ "lower_bound" in values,
85
+ "upper_bound" in values,
86
+ )
81
87
  ):
82
88
  raise ValueError("Must provide target or lower_bound/upper_bound")
83
89
  return values
@@ -1,6 +1,4 @@
1
- import json
2
1
  import os
3
- from pathlib import Path
4
2
  from textwrap import dedent
5
3
  from typing import Any
6
4
 
@@ -12,14 +10,9 @@ from ert.config.queue_config import (
12
10
  SlurmQueueOptions,
13
11
  TorqueQueueOptions,
14
12
  )
15
- from ert.dark_storage.client import ConnInfo
13
+ from ert.dark_storage.client import ErtClientConnectionInfo
16
14
 
17
- from ..strings import (
18
- CERTIFICATE_DIR,
19
- DETACHED_NODE_DIR,
20
- HOSTFILE_NAME,
21
- SESSION_DIR,
22
- )
15
+ from ..strings import SESSION_DIR
23
16
  from .simulator_config import check_removed_config
24
17
 
25
18
 
@@ -59,21 +52,11 @@ class ServerConfig(BaseModel):
59
52
  check_removed_config(data.get("queue_system"))
60
53
  return data
61
54
 
62
- @staticmethod
63
- def get_server_url(output_dir: str) -> str:
64
- """Return the url of the server.
65
-
66
- If server_info are given, the url is generated using that info. Otherwise
67
- server information are retrieved from the hostfile
68
- """
69
- server_info = ServerConfig.get_server_info(output_dir)
70
- return f"https://{server_info['host']}:{server_info['port']}/experiment_server"
71
-
72
55
  @staticmethod
73
56
  def get_server_context_from_conn_info(
74
- conn_info: ConnInfo,
57
+ conn_info: ErtClientConnectionInfo,
75
58
  ) -> tuple[str, str, tuple[str, str]]:
76
- """Get server connection context information from a storage_service ConnInfo.
59
+ """Get server connection context information from a ErtClientConnectionInfo.
77
60
 
78
61
  Returns a tuple containing the server URL, certificate file path,
79
62
  and authentication credentials.
@@ -83,7 +66,7 @@ class ServerConfig(BaseModel):
83
66
  This should be refactored to use the ERT Storage Client class directly instead.
84
67
 
85
68
  Args:
86
- conn_info: An instance of the storage_service client ConnInfo
69
+ conn_info: An instance of the ErtClientConnectionInfo
87
70
 
88
71
  Returns:
89
72
  tuple: A tuple containing:
@@ -102,34 +85,8 @@ class ServerConfig(BaseModel):
102
85
 
103
86
  return url, cert_file, auth
104
87
 
105
- @staticmethod
106
- def get_server_info(output_dir: str) -> dict[str, Any]:
107
- """Load server information from the hostfile"""
108
- host_file_path = Path(ServerConfig.get_hostfile_path(output_dir))
109
- if not host_file_path.exists():
110
- return {"host": None, "port": None, "cert": None, "auth": None}
111
-
112
- data = json.loads(host_file_path.read_text(encoding="utf-8"))
113
-
114
- if not all(k in data for k in ("host", "port", "cert", "auth")):
115
- raise RuntimeError("Malformed hostfile")
116
- return data
117
-
118
- @staticmethod
119
- def get_detached_node_dir(output_dir: str) -> str:
120
- return os.path.join(os.path.abspath(output_dir), DETACHED_NODE_DIR)
121
-
122
- @staticmethod
123
- def get_hostfile_path(output_dir: str) -> str:
124
- return os.path.join(ServerConfig.get_session_dir(output_dir), HOSTFILE_NAME)
125
-
126
88
  @staticmethod
127
89
  def get_session_dir(output_dir: str) -> str:
128
90
  """Return path to the session directory containing information about the
129
91
  certificates and host information"""
130
- return os.path.join(ServerConfig.get_detached_node_dir(output_dir), SESSION_DIR)
131
-
132
- @staticmethod
133
- def get_certificate_dir(output_dir: str) -> str:
134
- """Return the path to certificate folder"""
135
- return os.path.join(ServerConfig.get_session_dir(output_dir), CERTIFICATE_DIR)
92
+ return os.path.join(os.path.abspath(output_dir), SESSION_DIR)