ert 16.0.9__py3-none-any.whl → 19.0.0rc2__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 (286) hide show
  1. _ert/events.py +19 -2
  2. _ert/forward_model_runner/client.py +6 -2
  3. _ert/forward_model_runner/fm_dispatch.py +9 -6
  4. _ert/forward_model_runner/reporting/event.py +1 -0
  5. _ert/forward_model_runner/runner.py +1 -2
  6. _ert/utils.py +12 -0
  7. ert/__main__.py +58 -38
  8. ert/analysis/_enif_update.py +8 -4
  9. ert/analysis/_es_update.py +19 -6
  10. ert/analysis/_update_commons.py +16 -6
  11. ert/base_model_context.py +1 -1
  12. ert/cli/main.py +17 -12
  13. ert/cli/monitor.py +7 -0
  14. ert/config/__init__.py +17 -6
  15. ert/config/_create_observation_dataframes.py +118 -21
  16. ert/config/_get_num_cpu.py +1 -1
  17. ert/config/_observations.py +91 -2
  18. ert/config/_read_summary.py +74 -328
  19. ert/config/design_matrix.py +62 -23
  20. ert/config/distribution.py +1 -1
  21. ert/config/ensemble_config.py +9 -17
  22. ert/config/ert_config.py +155 -58
  23. ert/config/everest_control.py +234 -0
  24. ert/config/{everest_constraints_config.py → everest_response.py} +27 -15
  25. ert/config/field.py +99 -90
  26. ert/config/forward_model_step.py +122 -17
  27. ert/config/gen_data_config.py +5 -10
  28. ert/config/gen_kw_config.py +11 -41
  29. ert/config/known_response_types.py +14 -0
  30. ert/config/parameter_config.py +1 -33
  31. ert/config/parsing/_option_dict.py +10 -2
  32. ert/config/parsing/config_errors.py +1 -1
  33. ert/config/parsing/config_keywords.py +2 -1
  34. ert/config/parsing/config_schema.py +23 -11
  35. ert/config/parsing/config_schema_deprecations.py +3 -3
  36. ert/config/parsing/config_schema_item.py +26 -11
  37. ert/config/parsing/context_values.py +3 -3
  38. ert/config/parsing/file_context_token.py +1 -1
  39. ert/config/parsing/observations_parser.py +6 -2
  40. ert/config/parsing/queue_system.py +9 -0
  41. ert/config/parsing/schema_item_type.py +1 -0
  42. ert/config/queue_config.py +42 -50
  43. ert/config/response_config.py +0 -8
  44. ert/config/rft_config.py +275 -0
  45. ert/config/summary_config.py +3 -8
  46. ert/config/surface_config.py +73 -26
  47. ert/config/workflow_fixtures.py +2 -1
  48. ert/config/workflow_job.py +135 -54
  49. ert/dark_storage/client/__init__.py +2 -2
  50. ert/dark_storage/client/_session.py +4 -4
  51. ert/dark_storage/client/client.py +2 -2
  52. ert/dark_storage/common.py +12 -3
  53. ert/dark_storage/compute/misfits.py +11 -7
  54. ert/dark_storage/endpoints/compute/misfits.py +6 -4
  55. ert/dark_storage/endpoints/ensembles.py +4 -0
  56. ert/dark_storage/endpoints/experiment_server.py +30 -24
  57. ert/dark_storage/endpoints/experiments.py +2 -2
  58. ert/dark_storage/endpoints/observations.py +8 -6
  59. ert/dark_storage/endpoints/parameters.py +4 -12
  60. ert/dark_storage/endpoints/responses.py +24 -5
  61. ert/dark_storage/json_schema/ensemble.py +3 -0
  62. ert/dark_storage/json_schema/experiment.py +1 -1
  63. ert/data/_measured_data.py +6 -5
  64. ert/ensemble_evaluator/__init__.py +8 -1
  65. ert/ensemble_evaluator/config.py +2 -1
  66. ert/ensemble_evaluator/evaluator.py +81 -29
  67. ert/ensemble_evaluator/event.py +6 -0
  68. ert/ensemble_evaluator/snapshot.py +3 -1
  69. ert/ensemble_evaluator/state.py +1 -0
  70. ert/field_utils/__init__.py +8 -0
  71. ert/field_utils/field_utils.py +228 -15
  72. ert/field_utils/grdecl_io.py +1 -1
  73. ert/field_utils/roff_io.py +1 -1
  74. ert/gui/__init__.py +5 -2
  75. ert/gui/ertnotifier.py +1 -1
  76. ert/gui/ertwidgets/__init__.py +23 -16
  77. ert/gui/ertwidgets/analysismoduleedit.py +2 -2
  78. ert/gui/ertwidgets/checklist.py +1 -1
  79. ert/gui/ertwidgets/closabledialog.py +2 -0
  80. ert/gui/ertwidgets/copyablelabel.py +2 -0
  81. ert/gui/ertwidgets/create_experiment_dialog.py +3 -1
  82. ert/gui/ertwidgets/ensembleselector.py +2 -2
  83. ert/gui/ertwidgets/listeditbox.py +2 -0
  84. ert/gui/ertwidgets/models/__init__.py +2 -0
  85. ert/gui/ertwidgets/models/activerealizationsmodel.py +5 -1
  86. ert/gui/ertwidgets/models/path_model.py +1 -1
  87. ert/gui/ertwidgets/models/targetensemblemodel.py +5 -1
  88. ert/gui/ertwidgets/models/text_model.py +4 -1
  89. ert/gui/ertwidgets/pathchooser.py +0 -3
  90. ert/gui/ertwidgets/searchbox.py +17 -4
  91. ert/gui/ertwidgets/stringbox.py +2 -0
  92. ert/gui/{suggestor → ertwidgets/suggestor}/_suggestor_message.py +13 -4
  93. ert/gui/{suggestor → ertwidgets/suggestor}/suggestor.py +63 -30
  94. ert/gui/main.py +41 -13
  95. ert/gui/main_window.py +3 -7
  96. ert/gui/model/fm_step_list.py +3 -0
  97. ert/gui/model/real_list.py +1 -0
  98. ert/gui/model/snapshot.py +1 -0
  99. ert/gui/simulation/combobox_with_description.py +3 -0
  100. ert/gui/simulation/ensemble_experiment_panel.py +8 -2
  101. ert/gui/simulation/ensemble_information_filter_panel.py +7 -2
  102. ert/gui/simulation/ensemble_smoother_panel.py +8 -2
  103. ert/gui/simulation/evaluate_ensemble_panel.py +17 -7
  104. ert/gui/simulation/experiment_panel.py +18 -6
  105. ert/gui/simulation/manual_update_panel.py +35 -10
  106. ert/gui/simulation/multiple_data_assimilation_panel.py +13 -9
  107. ert/gui/simulation/run_dialog.py +47 -20
  108. ert/gui/simulation/single_test_run_panel.py +6 -3
  109. ert/gui/simulation/view/progress_widget.py +2 -0
  110. ert/gui/simulation/view/realization.py +5 -1
  111. ert/gui/simulation/view/update.py +2 -0
  112. ert/gui/summarypanel.py +20 -1
  113. ert/gui/tools/event_viewer/panel.py +3 -4
  114. ert/gui/tools/event_viewer/tool.py +2 -0
  115. ert/gui/tools/load_results/load_results_panel.py +1 -1
  116. ert/gui/tools/load_results/load_results_tool.py +2 -0
  117. ert/gui/tools/manage_experiments/export_dialog.py +136 -0
  118. ert/gui/tools/manage_experiments/manage_experiments_panel.py +2 -0
  119. ert/gui/tools/manage_experiments/storage_info_widget.py +121 -16
  120. ert/gui/tools/manage_experiments/storage_widget.py +4 -3
  121. ert/gui/tools/plot/customize/color_chooser.py +5 -2
  122. ert/gui/tools/plot/customize/customize_plot_dialog.py +2 -0
  123. ert/gui/tools/plot/customize/default_customization_view.py +4 -0
  124. ert/gui/tools/plot/customize/limits_customization_view.py +3 -0
  125. ert/gui/tools/plot/customize/statistics_customization_view.py +3 -0
  126. ert/gui/tools/plot/customize/style_chooser.py +2 -0
  127. ert/gui/tools/plot/customize/style_customization_view.py +3 -0
  128. ert/gui/tools/plot/data_type_keys_widget.py +2 -0
  129. ert/gui/tools/plot/data_type_proxy_model.py +3 -0
  130. ert/gui/tools/plot/plot_api.py +50 -28
  131. ert/gui/tools/plot/plot_ensemble_selection_widget.py +17 -10
  132. ert/gui/tools/plot/plot_widget.py +15 -2
  133. ert/gui/tools/plot/plot_window.py +41 -19
  134. ert/gui/tools/plot/plottery/plot_config.py +2 -0
  135. ert/gui/tools/plot/plottery/plot_context.py +14 -0
  136. ert/gui/tools/plot/plottery/plots/__init__.py +2 -0
  137. ert/gui/tools/plot/plottery/plots/cesp.py +3 -1
  138. ert/gui/tools/plot/plottery/plots/distribution.py +6 -1
  139. ert/gui/tools/plot/plottery/plots/ensemble.py +13 -5
  140. ert/gui/tools/plot/plottery/plots/gaussian_kde.py +12 -2
  141. ert/gui/tools/plot/plottery/plots/histogram.py +3 -1
  142. ert/gui/tools/plot/plottery/plots/misfits.py +436 -0
  143. ert/gui/tools/plot/plottery/plots/observations.py +18 -4
  144. ert/gui/tools/plot/plottery/plots/statistics.py +62 -20
  145. ert/gui/tools/plot/plottery/plots/std_dev.py +3 -1
  146. ert/gui/tools/plot/widgets/clearable_line_edit.py +9 -0
  147. ert/gui/tools/plot/widgets/filter_popup.py +2 -0
  148. ert/gui/tools/plot/widgets/filterable_kw_list_model.py +3 -0
  149. ert/gui/tools/plugins/plugin.py +1 -1
  150. ert/gui/tools/plugins/plugins_tool.py +2 -0
  151. ert/gui/tools/plugins/process_job_dialog.py +3 -0
  152. ert/gui/tools/workflows/workflow_dialog.py +2 -0
  153. ert/gui/tools/workflows/workflows_tool.py +2 -0
  154. ert/libres_facade.py +5 -7
  155. ert/logging/__init__.py +4 -1
  156. ert/mode_definitions.py +2 -0
  157. ert/plugins/__init__.py +4 -6
  158. ert/plugins/hook_implementations/workflows/csv_export.py +2 -3
  159. ert/plugins/hook_implementations/workflows/gen_data_rft_export.py +10 -2
  160. ert/plugins/hook_specifications/__init__.py +0 -10
  161. ert/plugins/hook_specifications/jobs.py +0 -9
  162. ert/plugins/plugin_manager.py +53 -124
  163. ert/resources/forward_models/run_reservoirsimulator.py +8 -4
  164. ert/resources/forward_models/template_render.py +10 -10
  165. ert/resources/shell_scripts/delete_directory.py +2 -2
  166. ert/run_models/__init__.py +24 -6
  167. ert/run_models/_create_run_path.py +133 -38
  168. ert/run_models/ensemble_experiment.py +10 -4
  169. ert/run_models/ensemble_information_filter.py +8 -1
  170. ert/run_models/ensemble_smoother.py +9 -3
  171. ert/run_models/evaluate_ensemble.py +8 -6
  172. ert/run_models/event.py +7 -3
  173. ert/run_models/everest_run_model.py +337 -113
  174. ert/run_models/initial_ensemble_run_model.py +25 -24
  175. ert/run_models/manual_update.py +6 -3
  176. ert/run_models/manual_update_enif.py +37 -0
  177. ert/run_models/model_factory.py +78 -18
  178. ert/run_models/multiple_data_assimilation.py +22 -11
  179. ert/run_models/run_model.py +72 -73
  180. ert/run_models/single_test_run.py +7 -4
  181. ert/run_models/update_run_model.py +4 -2
  182. ert/runpaths.py +5 -6
  183. ert/sample_prior.py +9 -4
  184. ert/scheduler/__init__.py +10 -5
  185. ert/scheduler/driver.py +40 -0
  186. ert/scheduler/event.py +3 -1
  187. ert/scheduler/job.py +23 -13
  188. ert/scheduler/lsf_driver.py +15 -5
  189. ert/scheduler/openpbs_driver.py +10 -4
  190. ert/scheduler/scheduler.py +5 -0
  191. ert/scheduler/slurm_driver.py +20 -5
  192. ert/services/__init__.py +2 -2
  193. ert/services/_base_service.py +37 -20
  194. ert/services/_storage_main.py +20 -18
  195. ert/services/ert_server.py +317 -0
  196. ert/shared/_doc_utils/__init__.py +4 -2
  197. ert/shared/_doc_utils/ert_jobs.py +1 -4
  198. ert/shared/net_utils.py +43 -18
  199. ert/shared/storage/connection.py +3 -3
  200. ert/shared/version.py +3 -3
  201. ert/storage/__init__.py +14 -1
  202. ert/storage/local_ensemble.py +44 -13
  203. ert/storage/local_experiment.py +54 -34
  204. ert/storage/local_storage.py +90 -58
  205. ert/storage/migration/to10.py +3 -2
  206. ert/storage/migration/to11.py +9 -10
  207. ert/storage/migration/to12.py +19 -20
  208. ert/storage/migration/to13.py +28 -27
  209. ert/storage/migration/to14.py +3 -3
  210. ert/storage/migration/to15.py +25 -0
  211. ert/storage/migration/to16.py +38 -0
  212. ert/storage/migration/to17.py +42 -0
  213. ert/storage/migration/to18.py +11 -0
  214. ert/storage/migration/to19.py +34 -0
  215. ert/storage/migration/to20.py +23 -0
  216. ert/storage/migration/to21.py +25 -0
  217. ert/storage/migration/to6.py +3 -2
  218. ert/storage/migration/to7.py +12 -13
  219. ert/storage/migration/to8.py +9 -11
  220. ert/storage/migration/to9.py +5 -4
  221. ert/storage/realization_storage_state.py +7 -7
  222. ert/substitutions.py +12 -28
  223. ert/validation/active_range.py +7 -7
  224. ert/validation/ensemble_realizations_argument.py +4 -2
  225. ert/validation/rangestring.py +16 -16
  226. ert/workflow_runner.py +6 -3
  227. {ert-16.0.9.dist-info → ert-19.0.0rc2.dist-info}/METADATA +21 -15
  228. ert-19.0.0rc2.dist-info/RECORD +524 -0
  229. {ert-16.0.9.dist-info → ert-19.0.0rc2.dist-info}/WHEEL +1 -1
  230. everest/api/everest_data_api.py +14 -1
  231. everest/assets/everest_logo.svg +406 -0
  232. everest/bin/config_branch_script.py +30 -14
  233. everest/bin/everconfigdump_script.py +2 -10
  234. everest/bin/everest_script.py +53 -33
  235. everest/bin/everlint_script.py +3 -5
  236. everest/bin/kill_script.py +7 -5
  237. everest/bin/main.py +11 -24
  238. everest/bin/monitor_script.py +64 -35
  239. everest/bin/utils.py +58 -43
  240. everest/bin/visualization_script.py +23 -13
  241. everest/config/__init__.py +4 -1
  242. everest/config/control_config.py +81 -6
  243. everest/config/control_variable_config.py +4 -3
  244. everest/config/everest_config.py +102 -79
  245. everest/config/forward_model_config.py +5 -3
  246. everest/config/install_data_config.py +7 -5
  247. everest/config/install_job_config.py +45 -3
  248. everest/config/install_template_config.py +3 -3
  249. everest/config/optimization_config.py +19 -6
  250. everest/config/output_constraint_config.py +8 -2
  251. everest/config/server_config.py +6 -55
  252. everest/config/simulator_config.py +62 -17
  253. everest/config/utils.py +25 -105
  254. everest/config/validation_utils.py +34 -15
  255. everest/config_file_loader.py +30 -21
  256. everest/detached/__init__.py +0 -6
  257. everest/detached/client.py +7 -52
  258. everest/detached/everserver.py +19 -45
  259. everest/everest_storage.py +24 -40
  260. everest/gui/everest_client.py +2 -3
  261. everest/gui/main_window.py +2 -2
  262. everest/optimizer/everest2ropt.py +68 -42
  263. everest/optimizer/opt_model_transforms.py +15 -20
  264. everest/optimizer/utils.py +0 -29
  265. everest/plugins/hook_specs.py +0 -24
  266. everest/strings.py +1 -6
  267. everest/util/__init__.py +3 -1
  268. ert/config/everest_objective_config.py +0 -95
  269. ert/config/ext_param_config.py +0 -107
  270. ert/gui/tools/export/__init__.py +0 -3
  271. ert/gui/tools/export/export_panel.py +0 -83
  272. ert/gui/tools/export/export_tool.py +0 -67
  273. ert/gui/tools/export/exporter.py +0 -36
  274. ert/plugins/hook_specifications/ecl_config.py +0 -29
  275. ert/services/storage_service.py +0 -127
  276. ert/summary_key_type.py +0 -234
  277. ert-16.0.9.dist-info/RECORD +0 -521
  278. everest/bin/everexport_script.py +0 -53
  279. everest/config/sampler_config.py +0 -103
  280. everest/simulator/__init__.py +0 -88
  281. everest/simulator/everest_to_ert.py +0 -252
  282. /ert/gui/{suggestor → ertwidgets/suggestor}/__init__.py +0 -0
  283. /ert/gui/{suggestor → ertwidgets/suggestor}/_colors.py +0 -0
  284. {ert-16.0.9.dist-info → ert-19.0.0rc2.dist-info}/entry_points.txt +0 -0
  285. {ert-16.0.9.dist-info → ert-19.0.0rc2.dist-info}/licenses/COPYING +0 -0
  286. {ert-16.0.9.dist-info → ert-19.0.0rc2.dist-info}/top_level.txt +0 -0
_ert/events.py CHANGED
@@ -41,10 +41,12 @@ class Id:
41
41
  ENSEMBLE_SUCCEEDED_TYPE = Literal["ensemble.succeeded"]
42
42
  ENSEMBLE_CANCELLED_TYPE = Literal["ensemble.cancelled"]
43
43
  ENSEMBLE_FAILED_TYPE = Literal["ensemble.failed"]
44
+ ENSEMBLE_WARNING_TYPE = Literal["ensemble.warning"]
44
45
  ENSEMBLE_STARTED: Final = "ensemble.started"
45
46
  ENSEMBLE_SUCCEEDED: Final = "ensemble.succeeded"
46
47
  ENSEMBLE_CANCELLED: Final = "ensemble.cancelled"
47
48
  ENSEMBLE_FAILED: Final = "ensemble.failed"
49
+ ENSEMBLE_WARNING: Final = "ensemble.warning"
48
50
  ENSEMBLE_TYPES = (
49
51
  ENSEMBLE_STARTED_TYPE
50
52
  | ENSEMBLE_FAILED_TYPE
@@ -170,6 +172,15 @@ class EnsembleCancelled(EnsembleBaseEvent):
170
172
  event_type: Id.ENSEMBLE_CANCELLED_TYPE = Id.ENSEMBLE_CANCELLED
171
173
 
172
174
 
175
+ class EnsembleEvaluationWarning(EnsembleBaseEvent):
176
+ """This event is to indicate that something unexpected happened while
177
+ running the ensemble, and that it might be stuck in an unresponsive state.
178
+ """
179
+
180
+ event_type: Id.ENSEMBLE_WARNING_TYPE = Id.ENSEMBLE_WARNING
181
+ warning_message: str
182
+
183
+
173
184
  class EESnapshot(EnsembleBaseEvent):
174
185
  event_type: Id.EE_SNAPSHOT_TYPE = Id.EE_SNAPSHOT
175
186
  snapshot: Any
@@ -200,9 +211,15 @@ RealizationEvent = (
200
211
  | RealizationResubmit
201
212
  )
202
213
 
203
- EnsembleEvent = EnsembleStarted | EnsembleSucceeded | EnsembleFailed | EnsembleCancelled
214
+ EnsembleEvent = (
215
+ EnsembleStarted
216
+ | EnsembleSucceeded
217
+ | EnsembleFailed
218
+ | EnsembleCancelled
219
+ | EnsembleEvaluationWarning
220
+ )
204
221
 
205
- EEEvent = EESnapshot | EESnapshotUpdate
222
+ EEEvent = EESnapshot | EESnapshotUpdate | EnsembleEvaluationWarning
206
223
 
207
224
  SnapshotInputEvent = RealizationEvent | EnsembleEvent | FMEvent
208
225
 
@@ -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)
@@ -8,6 +8,7 @@ import sys
8
8
  import time
9
9
  from collections.abc import Generator, Iterable
10
10
  from datetime import datetime
11
+ from pathlib import Path
11
12
  from typing import TYPE_CHECKING, Any
12
13
 
13
14
  from _ert.forward_model_runner import reporting
@@ -19,6 +20,7 @@ from _ert.forward_model_runner.reporting.message import (
19
20
  ProcessTreeStatus,
20
21
  )
21
22
  from _ert.forward_model_runner.runner import ForwardModelRunner
23
+ from _ert.utils import file_safe_timestamp
22
24
 
23
25
  if TYPE_CHECKING:
24
26
  from ert.config.forward_model_step import ForwardModelJSON
@@ -81,10 +83,10 @@ def _setup_logging(directory: str = "logs") -> None:
81
83
  "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
82
84
  )
83
85
 
84
- filename = (
85
- f"forward-model-runner-log-{datetime.now().isoformat(timespec='minutes')}.txt"
86
- )
87
- csv_filename = f"memory-profile-{datetime.now().isoformat(timespec='minutes')}.csv"
86
+ timestamp = file_safe_timestamp(datetime.now().isoformat(timespec="minutes"))
87
+
88
+ filename = f"forward-model-runner-log-{timestamp}.txt"
89
+ csv_filename = f"memory-profile-{timestamp}.csv"
88
90
 
89
91
  handler = logging.FileHandler(filename=directory + "/" + filename)
90
92
  handler.setFormatter(formatter)
@@ -107,8 +109,9 @@ def _wait_for_retry() -> None:
107
109
 
108
110
  def _read_fm_description_file(retry: bool = True) -> "ForwardModelDescriptionJSON":
109
111
  try:
110
- with open(FORWARD_MODEL_DESCRIPTION_FILE, encoding="utf-8") as json_file:
111
- return json.load(json_file)
112
+ return json.loads(
113
+ Path(FORWARD_MODEL_DESCRIPTION_FILE).read_text(encoding="utf-8")
114
+ )
112
115
  except json.JSONDecodeError as e:
113
116
  raise OSError(
114
117
  "fm_dispatch failed to load JSON-file describing the forward model."
@@ -137,6 +137,7 @@ class Event(Reporter):
137
137
  return
138
138
  except ClientConnectionError as exc:
139
139
  logger.error(f"Failed to send event: {exc}")
140
+ self._reporter_exception = exc
140
141
  return
141
142
  except queue.Empty:
142
143
  await asyncio.sleep(0)
@@ -40,8 +40,7 @@ class ForwardModelRunner:
40
40
  def _read_manifest(self) -> dict[str, Manifest] | None:
41
41
  if not Path("manifest.json").exists():
42
42
  return None
43
- with open("manifest.json", encoding="utf-8") as f:
44
- data = json.load(f)
43
+ data = json.loads(Path("manifest.json").read_text(encoding="utf-8"))
45
44
  return {
46
45
  name: {"type": "file", "path": str(Path(file).absolute())}
47
46
  for name, file in data.items()
_ert/utils.py ADDED
@@ -0,0 +1,12 @@
1
+ def file_safe_timestamp(timestamp: str) -> str:
2
+ """
3
+ Convert an ISO timestamp string to a file-safe version
4
+
5
+ Keeps the date in the extended format (YYYY-MM-DD) and converts the time
6
+ to the basic format (HHMMSS) by removing colons. This mix is not strictly
7
+ ISO 8601 compliant, but it can still be parsed.
8
+
9
+ Example:
10
+ 2025-10-10T14:30:00 -> 2025-10-10T143000
11
+ """
12
+ return str(timestamp).replace(":", "")
ert/__main__.py CHANGED
@@ -12,6 +12,7 @@ import sys
12
12
  import warnings
13
13
  from argparse import ArgumentParser, ArgumentTypeError
14
14
  from collections.abc import Sequence
15
+ from pathlib import Path
15
16
  from typing import Any
16
17
  from uuid import UUID
17
18
 
@@ -20,6 +21,7 @@ from opentelemetry.trace import Status, StatusCode
20
21
 
21
22
  import ert.shared
22
23
  from _ert.threading import set_signal_handler
24
+ from ert.base_model_context import use_runtime_plugins
23
25
  from ert.cli.main import ErtCliError, run_cli
24
26
  from ert.config import ConfigValidationError, ErtConfig, lint_file
25
27
  from ert.logging import LOGGING_CONFIG
@@ -32,11 +34,12 @@ from ert.mode_definitions import (
32
34
  WORKFLOW_MODE,
33
35
  )
34
36
  from ert.namespace import Namespace
35
- from ert.plugins import ErtPluginContext, ErtRuntimePlugins
36
- from ert.run_models.multiple_data_assimilation import MultipleDataAssimilation
37
- from ert.services import StorageService, WebvizErt
37
+ from ert.plugins import ErtRuntimePlugins, get_site_plugins, setup_site_logging
38
+ from ert.run_models.multiple_data_assimilation import MultipleDataAssimilationConfig
39
+ from ert.services import ErtServer, WebvizErt
40
+ from ert.shared.status.utils import get_ert_memory_usage
38
41
  from ert.shared.storage.command import add_parser_options as ert_api_add_parser_options
39
- from ert.storage import ErtStorageException
42
+ from ert.storage import ErtStorageException, ErtStoragePermissionError
40
43
  from ert.trace import trace, tracer
41
44
  from ert.validation import (
42
45
  IntegerArgument,
@@ -51,9 +54,9 @@ logger = logging.getLogger(__name__)
51
54
 
52
55
 
53
56
  def run_ert_storage(args: Namespace, _: ErtRuntimePlugins | None = None) -> None:
54
- with StorageService.start_server(
57
+ with ErtServer.start_server(
55
58
  verbose=True,
56
- project=ErtConfig.from_file(args.config).ens_path,
59
+ project=Path(ErtConfig.from_file(args.config).ens_path),
57
60
  parent_pid=os.getpid(),
58
61
  ) as server:
59
62
  server.wait()
@@ -68,8 +71,7 @@ def run_webviz_ert(args: Namespace, _: ErtRuntimePlugins | None = None) -> None:
68
71
  ) from err
69
72
 
70
73
  kwargs: dict[str, Any] = {"verbose": args.verbose}
71
- with ErtPluginContext() as runtime_plugins:
72
- ert_config = ErtConfig.with_plugins(runtime_plugins).from_file(args.config)
74
+ ert_config = ErtConfig.with_plugins(get_site_plugins()).from_file(args.config)
73
75
 
74
76
  os.chdir(ert_config.config_path)
75
77
  ens_path = ert_config.ens_path
@@ -78,18 +80,32 @@ def run_webviz_ert(args: Namespace, _: ErtRuntimePlugins | None = None) -> None:
78
80
  # only use the base name of the config file path
79
81
  kwargs["ert_config"] = os.path.basename(args.config)
80
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
+
81
89
  try:
82
- with StorageService.init_service(project=os.path.abspath(ens_path)) as storage:
90
+ with ErtServer.init_service(project=Path(ens_path).absolute()) as storage:
83
91
  storage.wait_until_ready()
84
92
  print(
85
- """
86
- -----------------------------------------------------------
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
+ ---------------------------------------------------------------
87
102
 
88
103
  Starting up Webviz-ERT. This might take more than a minute.
89
104
 
90
- -----------------------------------------------------------
105
+ ---------------------------------------------------------------
91
106
  """
92
107
  )
108
+ logger.info("Show Webviz-ert deprecation warning")
93
109
  webviz_kwargs = {
94
110
  "experimental_mode": args.experimental_mode,
95
111
  "verbose": args.verbose,
@@ -500,7 +516,7 @@ def get_ert_parser(parser: ArgumentParser | None = None) -> ArgumentParser:
500
516
  es_mda_parser.add_argument(
501
517
  "--weights",
502
518
  type=valid_weights,
503
- default=MultipleDataAssimilation.default_weights,
519
+ default=MultipleDataAssimilationConfig.default_weights,
504
520
  help="Example custom relative weights: '8,4,2,1'. This means multiple data "
505
521
  "assimilation ensemble smoother will half the weight applied to the "
506
522
  "observation errors from one iteration to the next across 4 iterations.",
@@ -565,15 +581,15 @@ def get_ert_parser(parser: ArgumentParser | None = None) -> ArgumentParser:
565
581
  "--color-always",
566
582
  action="store_true",
567
583
  help="Force coloring of monitor output, which is automatically"
568
- + " disabled if the output stream is not a terminal.",
584
+ " disabled if the output stream is not a terminal.",
569
585
  default=False,
570
586
  )
571
587
  cli_parser.add_argument(
572
588
  "--disable-monitoring",
573
589
  action="store_true",
574
590
  help="Monitoring will continuously print the status of the realisations"
575
- + " classified into Waiting, Pending, Running, Failed, Finished"
576
- + " and Unknown.",
591
+ " classified into Waiting, Pending, Running, Failed, Finished"
592
+ " and Unknown.",
577
593
  default=False,
578
594
  )
579
595
  cli_parser.add_argument(
@@ -597,7 +613,7 @@ def ert_parser(parser: ArgumentParser | None, args: Sequence[str]) -> Namespace:
597
613
  def log_process_usage() -> None:
598
614
  try:
599
615
  usage = resource.getrusage(resource.RUSAGE_SELF)
600
- max_rss = ert.shared.status.utils.get_ert_memory_usage()
616
+ max_rss = get_ert_memory_usage()
601
617
 
602
618
  usage_dict: dict[str, int | float] = {
603
619
  "User time": usage.ru_utime,
@@ -636,25 +652,24 @@ def main() -> None:
636
652
 
637
653
  os.environ["ERT_LOG_DIR"] = log_dir
638
654
 
639
- with open(LOGGING_CONFIG, encoding="utf-8") as conf_file:
640
- config_dict = yaml.safe_load(conf_file)
641
- for handler_name, handler_config in config_dict["handlers"].items():
642
- if handler_name == "file":
643
- handler_config["filename"] = "ert-log.txt"
644
- if "ert.logging.TimestampedFileHandler" in handler_config.values():
645
- handler_config["config_filename"] = args.config
646
- try:
647
- logging.config.dictConfig(config_dict)
648
- except ValueError as err:
649
- if "handler 'file'" in str(err):
650
- exit_msg = (
651
- f"Could not configure log handler for files. "
652
- f"Check if you have write-access to the logs-directory ({log_dir})."
653
- )
654
- else:
655
- exit_msg = str(err)
656
- os.environ.pop("ERT_LOG_DIR")
657
- sys.exit(exit_msg)
655
+ config_dict = yaml.safe_load(Path(LOGGING_CONFIG).read_text(encoding="utf-8"))
656
+ for handler_name, handler_config in config_dict["handlers"].items():
657
+ if handler_name == "file":
658
+ handler_config["filename"] = "ert-log.txt"
659
+ if "ert.logging.TimestampedFileHandler" in handler_config.values():
660
+ handler_config["config_filename"] = args.config
661
+ try:
662
+ logging.config.dictConfig(config_dict)
663
+ except ValueError as err:
664
+ if "handler 'file'" in str(err):
665
+ exit_msg = (
666
+ f"Could not configure log handler for files. "
667
+ f"Check if you have write-access to the logs-directory ({log_dir})."
668
+ )
669
+ else:
670
+ exit_msg = str(err)
671
+ os.environ.pop("ERT_LOG_DIR")
672
+ sys.exit(exit_msg)
658
673
 
659
674
  logger = logging.getLogger(__name__)
660
675
  if args.verbose:
@@ -663,9 +678,14 @@ def main() -> None:
663
678
  handler.setLevel(logging.INFO)
664
679
  root_logger.addHandler(handler)
665
680
  try:
666
- with ErtPluginContext(logger=logging.getLogger()) as runtime_plugins:
681
+ site_plugins = get_site_plugins()
682
+ setup_site_logging(logging.getLogger())
683
+ with use_runtime_plugins(site_plugins):
667
684
  logger.info(f"Running ert with {args} in {os.getcwd()}")
668
- args.func(args, runtime_plugins)
685
+ args.func(args, site_plugins)
686
+ except ErtStoragePermissionError as err:
687
+ logger.error(str(err))
688
+ sys.exit(str(err))
669
689
  except (ErtCliError, ErtStorageException) as err:
670
690
  span.set_status(Status(StatusCode.ERROR))
671
691
  span.record_exception(err)
@@ -160,10 +160,14 @@ def analysis_EnIF(
160
160
  Y=S.T,
161
161
  verbose_level=5,
162
162
  )
163
-
163
+ updated_parameters = [
164
+ p
165
+ for p, config in source_ensemble.experiment.parameter_configuration.items()
166
+ if config.update
167
+ ]
164
168
  # Learn the precision matrix block-sparse over parameter groups
165
169
  Prec_u = sp.sparse.csc_matrix((0, 0), dtype=float)
166
- for param_group in parameters:
170
+ for param_group in updated_parameters:
167
171
  config_node = source_ensemble.experiment.parameter_configuration[param_group]
168
172
  X_local = source_ensemble.load_parameters_numpy(param_group, iens_active_index)
169
173
  X_local_scaler = StandardScaler()
@@ -215,7 +219,7 @@ def analysis_EnIF(
215
219
 
216
220
  # Iterate over parameters to store the updated ensemble
217
221
  parameters_updated = 0
218
- for param_group in parameters:
222
+ for param_group in updated_parameters:
219
223
  log_msg = f"Storing data for {param_group}.."
220
224
  logger.info(log_msg)
221
225
  progress_callback(AnalysisStatusEvent(msg=log_msg))
@@ -241,7 +245,7 @@ def analysis_EnIF(
241
245
  )
242
246
  _copy_unupdated_parameters(
243
247
  list(source_ensemble.experiment.parameter_configuration.keys()),
244
- parameters,
248
+ updated_parameters,
245
249
  iens_active_index,
246
250
  source_ensemble,
247
251
  target_ensemble,
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import functools
4
4
  import logging
5
+ import re
5
6
  import time
6
7
  import warnings
7
8
  from collections.abc import Callable, Iterable, Sequence
@@ -441,6 +442,12 @@ def smoother_update(
441
442
  with warnings.catch_warnings():
442
443
  original_showwarning = warnings.showwarning
443
444
 
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
+
444
451
  def log_warning(
445
452
  message: Warning | str,
446
453
  category: type[Warning],
@@ -449,12 +456,18 @@ def smoother_update(
449
456
  file: TextIO | None = None,
450
457
  line: str | None = None,
451
458
  ) -> None:
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
- )
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
+ )
458
471
 
459
472
  warnings.showwarning = log_warning
460
473
  analysis_ES(
@@ -61,10 +61,19 @@ def _copy_unupdated_parameters(
61
61
 
62
62
  # Copy the non-updated parameter groups from source to target
63
63
  # for each active realization
64
+ complete_df: pl.DataFrame | None = None
64
65
  for parameter_group in not_updated_parameter_groups:
65
- source_ensemble.experiment.parameter_configuration[
66
- parameter_group
67
- ].copy_parameters(source_ensemble, target_ensemble, iens_active_index)
66
+ data = source_ensemble.load_parameters(parameter_group, iens_active_index)
67
+ if isinstance(data, pl.DataFrame):
68
+ if complete_df is None:
69
+ complete_df = data
70
+ else:
71
+ complete_df = complete_df.join(data, on="realization")
72
+ else:
73
+ target_ensemble.save_parameters(dataset=data)
74
+
75
+ if complete_df is not None:
76
+ target_ensemble.save_parameters(complete_df)
68
77
 
69
78
 
70
79
  def _expand_wildcards(
@@ -331,11 +340,12 @@ def _all_parameters(
331
340
  ) -> npt.NDArray[np.float64]:
332
341
  """Return all parameters in assimilation problem"""
333
342
 
334
- param_groups = list(ensemble.experiment.parameter_configuration.keys())
335
-
343
+ groups_to_update = [
344
+ k for k, v in ensemble.experiment.parameter_configuration.items() if v.update
345
+ ]
336
346
  param_arrays = [
337
347
  ensemble.load_parameters_numpy(param_group, iens_active_index)
338
- for param_group in param_groups
348
+ for param_group in groups_to_update
339
349
  ]
340
350
 
341
351
  return np.vstack(param_arrays)
ert/base_model_context.py CHANGED
@@ -14,7 +14,7 @@ if TYPE_CHECKING:
14
14
 
15
15
 
16
16
  @contextmanager
17
- def init_context(value: ErtRuntimePlugins) -> Iterator[None]:
17
+ def use_runtime_plugins(value: ErtRuntimePlugins) -> Iterator[None]:
18
18
  token = init_context_var.set(value) # type: ignore
19
19
  try:
20
20
  yield
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,9 +6,11 @@ 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
13
+ from ert.base_model_context import use_runtime_plugins
13
14
  from ert.cli.monitor import Monitor
14
15
  from ert.cli.workflow import execute_workflow
15
16
  from ert.config import ErtConfig, QueueSystem
@@ -23,10 +24,10 @@ from ert.mode_definitions import (
23
24
  WORKFLOW_MODE,
24
25
  )
25
26
  from ert.namespace import Namespace
26
- from ert.plugins import ErtPluginContext, ErtRuntimePlugins
27
+ from ert.plugins import ErtRuntimePlugins, get_site_plugins
27
28
  from ert.run_models.event import StatusEvents
28
29
  from ert.run_models.model_factory import create_model
29
- from ert.storage import open_storage
30
+ from ert.storage import LocalStorage, open_storage
30
31
  from ert.storage.local_storage import local_storage_set_ert_config
31
32
 
32
33
 
@@ -45,10 +46,7 @@ def run_cli(args: Namespace, runtime_plugins: ErtRuntimePlugins | None = None) -
45
46
  if runtime_plugins is not None:
46
47
  ert_config = ErtConfig.with_plugins(runtime_plugins).from_file(args.config)
47
48
  else:
48
- with ErtPluginContext() as default_runtime_plugins:
49
- ert_config = ErtConfig.with_plugins(default_runtime_plugins).from_file(
50
- args.config
51
- )
49
+ ert_config = ErtConfig.with_plugins(get_site_plugins()).from_file(args.config)
52
50
 
53
51
  local_storage_set_ert_config(ert_config)
54
52
  counter_fm_steps = Counter(fms.name for fms in ert_config.forward_model_steps)
@@ -90,18 +88,25 @@ def run_cli(args: Namespace, runtime_plugins: ErtRuntimePlugins | None = None) -
90
88
  )
91
89
 
92
90
  if args.mode == WORKFLOW_MODE:
93
- 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:
94
95
  execute_workflow(ert_config, storage, args.name)
95
96
  return
96
97
 
97
98
  status_queue: queue.SimpleQueue[StatusEvents] = queue.SimpleQueue()
99
+ using_local_queuesystem: bool = True
98
100
  try:
99
- with ErtPluginContext():
101
+ with use_runtime_plugins(get_site_plugins()):
100
102
  model = create_model(
101
103
  ert_config,
102
104
  args,
103
105
  status_queue,
104
106
  )
107
+ using_local_queuesystem = (
108
+ ert_config.queue_config.queue_system == QueueSystem.LOCAL
109
+ )
105
110
  except ValueError as e:
106
111
  raise ErtCliError(f"{args.mode} was not valid, failed with: {e}") from e
107
112
 
@@ -118,17 +123,17 @@ def run_cli(args: Namespace, runtime_plugins: ErtRuntimePlugins | None = None) -
118
123
  f"and DESIGN_MATRIX ({model.active_realizations.count(True)})"
119
124
  )
120
125
 
121
- if args.port_range is None and model.queue_system == QueueSystem.LOCAL:
126
+ if args.port_range is None and using_local_queuesystem:
122
127
  # This is within the range for ephemeral ports as defined by
123
128
  # most unix flavors https://en.wikipedia.org/wiki/Ephemeral_port
124
129
  args.port_range = range(49152, 51819)
125
130
 
126
- use_ipc_protocol = model.queue_system == QueueSystem.LOCAL
127
131
  evaluator_server_config = EvaluatorServerConfig(
128
132
  port_range=None
129
133
  if args.port_range is None
130
134
  else (min(args.port_range), max(args.port_range) + 1),
131
- use_ipc_protocol=use_ipc_protocol,
135
+ use_ipc_protocol=using_local_queuesystem,
136
+ prioritize_private_ip_address=ert_config.prioritize_private_ip_address,
132
137
  )
133
138
 
134
139
  if model.check_if_runpath_exists():
ert/cli/monitor.py CHANGED
@@ -9,6 +9,7 @@ from typing import TextIO
9
9
  import humanize
10
10
  from tqdm import tqdm
11
11
 
12
+ from _ert.events import EnsembleEvaluationWarning
12
13
  from ert.ensemble_evaluator import (
13
14
  EndEvent,
14
15
  EnsembleSnapshot,
@@ -19,6 +20,7 @@ from ert.ensemble_evaluator import identifiers as ids
19
20
  from ert.ensemble_evaluator.state import (
20
21
  COLOR_FAILED,
21
22
  COLOR_FINISHED,
23
+ COLOR_WARNING,
22
24
  FORWARD_MODEL_STATE_FAILURE,
23
25
  REAL_STATE_TO_COLOR,
24
26
  )
@@ -96,6 +98,11 @@ class Monitor:
96
98
  | RunModelErrorEvent() as event
97
99
  ):
98
100
  event.write_as_csv(output_path)
101
+ case EnsembleEvaluationWarning(warning_message=msg):
102
+ print(
103
+ self._colorize(msg, color=COLOR_WARNING),
104
+ file=self._out,
105
+ )
99
106
 
100
107
  def _print_step_errors(self) -> None:
101
108
  failed_steps: dict[str | None, int] = {}