ert 17.1.9__py3-none-any.whl → 18.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. _ert/events.py +19 -2
  2. ert/__main__.py +8 -7
  3. ert/analysis/_update_commons.py +12 -3
  4. ert/cli/main.py +6 -3
  5. ert/cli/monitor.py +7 -0
  6. ert/config/__init__.py +13 -3
  7. ert/config/_create_observation_dataframes.py +60 -12
  8. ert/config/_observations.py +14 -1
  9. ert/config/_read_summary.py +8 -6
  10. ert/config/ensemble_config.py +6 -14
  11. ert/config/ert_config.py +19 -13
  12. ert/config/{everest_objective_config.py → everest_response.py} +23 -12
  13. ert/config/ext_param_config.py +133 -1
  14. ert/config/field.py +12 -8
  15. ert/config/forward_model_step.py +108 -6
  16. ert/config/gen_data_config.py +2 -6
  17. ert/config/gen_kw_config.py +0 -9
  18. ert/config/known_response_types.py +14 -0
  19. ert/config/parameter_config.py +0 -17
  20. ert/config/parsing/config_keywords.py +1 -0
  21. ert/config/parsing/config_schema.py +12 -0
  22. ert/config/parsing/config_schema_deprecations.py +11 -0
  23. ert/config/parsing/config_schema_item.py +1 -1
  24. ert/config/queue_config.py +4 -4
  25. ert/config/response_config.py +0 -7
  26. ert/config/rft_config.py +230 -0
  27. ert/config/summary_config.py +2 -6
  28. ert/config/violations.py +0 -0
  29. ert/config/workflow_fixtures.py +2 -1
  30. ert/dark_storage/client/__init__.py +2 -2
  31. ert/dark_storage/client/_session.py +4 -4
  32. ert/dark_storage/client/client.py +2 -2
  33. ert/dark_storage/compute/misfits.py +7 -6
  34. ert/dark_storage/endpoints/compute/misfits.py +2 -2
  35. ert/dark_storage/endpoints/observations.py +4 -4
  36. ert/dark_storage/endpoints/responses.py +15 -1
  37. ert/ensemble_evaluator/__init__.py +8 -1
  38. ert/ensemble_evaluator/evaluator.py +81 -29
  39. ert/ensemble_evaluator/event.py +6 -0
  40. ert/ensemble_evaluator/snapshot.py +3 -1
  41. ert/ensemble_evaluator/state.py +1 -0
  42. ert/field_utils/__init__.py +8 -0
  43. ert/field_utils/field_utils.py +211 -1
  44. ert/gui/ertwidgets/__init__.py +23 -16
  45. ert/gui/ertwidgets/analysismoduleedit.py +2 -2
  46. ert/gui/ertwidgets/checklist.py +1 -1
  47. ert/gui/ertwidgets/create_experiment_dialog.py +3 -1
  48. ert/gui/ertwidgets/ensembleselector.py +2 -2
  49. ert/gui/ertwidgets/models/__init__.py +2 -0
  50. ert/gui/ertwidgets/models/activerealizationsmodel.py +2 -1
  51. ert/gui/ertwidgets/models/path_model.py +1 -1
  52. ert/gui/ertwidgets/models/targetensemblemodel.py +2 -1
  53. ert/gui/ertwidgets/models/text_model.py +1 -1
  54. ert/gui/ertwidgets/searchbox.py +13 -4
  55. ert/gui/{suggestor → ertwidgets/suggestor}/_suggestor_message.py +13 -4
  56. ert/gui/main.py +14 -7
  57. ert/gui/main_window.py +1 -2
  58. ert/gui/simulation/ensemble_experiment_panel.py +1 -1
  59. ert/gui/simulation/ensemble_information_filter_panel.py +1 -1
  60. ert/gui/simulation/ensemble_smoother_panel.py +1 -1
  61. ert/gui/simulation/evaluate_ensemble_panel.py +1 -1
  62. ert/gui/simulation/experiment_panel.py +1 -1
  63. ert/gui/simulation/manual_update_panel.py +31 -8
  64. ert/gui/simulation/multiple_data_assimilation_panel.py +12 -8
  65. ert/gui/simulation/run_dialog.py +25 -4
  66. ert/gui/simulation/single_test_run_panel.py +2 -2
  67. ert/gui/summarypanel.py +1 -1
  68. ert/gui/tools/load_results/load_results_panel.py +1 -1
  69. ert/gui/tools/manage_experiments/storage_info_widget.py +7 -7
  70. ert/gui/tools/manage_experiments/storage_widget.py +1 -2
  71. ert/gui/tools/plot/plot_api.py +13 -10
  72. ert/gui/tools/plot/plot_window.py +12 -0
  73. ert/gui/tools/plot/plottery/plot_config.py +2 -0
  74. ert/gui/tools/plot/plottery/plot_context.py +14 -0
  75. ert/gui/tools/plot/plottery/plots/ensemble.py +9 -2
  76. ert/gui/tools/plot/plottery/plots/statistics.py +59 -19
  77. ert/mode_definitions.py +2 -0
  78. ert/plugins/__init__.py +0 -1
  79. ert/plugins/hook_implementations/workflows/gen_data_rft_export.py +10 -2
  80. ert/plugins/hook_specifications/__init__.py +0 -2
  81. ert/plugins/hook_specifications/jobs.py +0 -9
  82. ert/plugins/plugin_manager.py +2 -33
  83. ert/resources/shell_scripts/delete_directory.py +2 -2
  84. ert/run_models/__init__.py +18 -5
  85. ert/run_models/_create_run_path.py +33 -21
  86. ert/run_models/ensemble_experiment.py +10 -4
  87. ert/run_models/ensemble_information_filter.py +8 -1
  88. ert/run_models/ensemble_smoother.py +9 -3
  89. ert/run_models/evaluate_ensemble.py +8 -6
  90. ert/run_models/event.py +7 -3
  91. ert/run_models/everest_run_model.py +155 -44
  92. ert/run_models/initial_ensemble_run_model.py +23 -22
  93. ert/run_models/manual_update.py +4 -2
  94. ert/run_models/manual_update_enif.py +37 -0
  95. ert/run_models/model_factory.py +81 -22
  96. ert/run_models/multiple_data_assimilation.py +21 -10
  97. ert/run_models/run_model.py +54 -34
  98. ert/run_models/single_test_run.py +7 -4
  99. ert/run_models/update_run_model.py +4 -2
  100. ert/runpaths.py +5 -6
  101. ert/sample_prior.py +9 -4
  102. ert/scheduler/driver.py +37 -0
  103. ert/scheduler/event.py +3 -1
  104. ert/scheduler/job.py +23 -13
  105. ert/scheduler/lsf_driver.py +6 -2
  106. ert/scheduler/openpbs_driver.py +7 -1
  107. ert/scheduler/scheduler.py +5 -0
  108. ert/scheduler/slurm_driver.py +6 -2
  109. ert/services/__init__.py +2 -2
  110. ert/services/_base_service.py +31 -15
  111. ert/services/ert_server.py +317 -0
  112. ert/shared/_doc_utils/ert_jobs.py +1 -4
  113. ert/shared/storage/connection.py +3 -3
  114. ert/shared/version.py +3 -3
  115. ert/storage/local_ensemble.py +25 -5
  116. ert/storage/local_experiment.py +6 -14
  117. ert/storage/local_storage.py +36 -30
  118. ert/storage/migration/to18.py +12 -0
  119. ert/storage/migration/to8.py +4 -4
  120. ert/substitutions.py +12 -28
  121. ert/validation/active_range.py +7 -7
  122. ert/validation/rangestring.py +16 -16
  123. {ert-17.1.9.dist-info → ert-18.0.1.dist-info}/METADATA +8 -7
  124. {ert-17.1.9.dist-info → ert-18.0.1.dist-info}/RECORD +159 -158
  125. everest/bin/config_branch_script.py +3 -6
  126. everest/bin/everconfigdump_script.py +1 -9
  127. everest/bin/everest_script.py +21 -11
  128. everest/bin/kill_script.py +2 -2
  129. everest/bin/monitor_script.py +2 -2
  130. everest/bin/utils.py +6 -3
  131. everest/config/__init__.py +4 -1
  132. everest/config/control_config.py +61 -2
  133. everest/config/control_variable_config.py +2 -1
  134. everest/config/everest_config.py +38 -16
  135. everest/config/forward_model_config.py +5 -3
  136. everest/config/install_data_config.py +7 -5
  137. everest/config/install_job_config.py +7 -3
  138. everest/config/install_template_config.py +3 -3
  139. everest/config/optimization_config.py +19 -6
  140. everest/config/output_constraint_config.py +8 -2
  141. everest/config/server_config.py +6 -49
  142. everest/config/utils.py +25 -105
  143. everest/config/validation_utils.py +10 -10
  144. everest/config_file_loader.py +13 -2
  145. everest/detached/everserver.py +7 -8
  146. everest/everest_storage.py +6 -10
  147. everest/gui/everest_client.py +0 -1
  148. everest/gui/main_window.py +2 -2
  149. everest/optimizer/everest2ropt.py +59 -32
  150. everest/optimizer/opt_model_transforms.py +12 -13
  151. everest/optimizer/utils.py +0 -29
  152. everest/strings.py +0 -5
  153. ert/config/everest_constraints_config.py +0 -95
  154. ert/services/storage_service.py +0 -127
  155. everest/config/sampler_config.py +0 -103
  156. everest/simulator/__init__.py +0 -88
  157. everest/simulator/everest_to_ert.py +0 -51
  158. /ert/gui/{suggestor → ertwidgets/suggestor}/__init__.py +0 -0
  159. /ert/gui/{suggestor → ertwidgets/suggestor}/_colors.py +0 -0
  160. /ert/gui/{suggestor → ertwidgets/suggestor}/suggestor.py +0 -0
  161. {ert-17.1.9.dist-info → ert-18.0.1.dist-info}/WHEEL +0 -0
  162. {ert-17.1.9.dist-info → ert-18.0.1.dist-info}/entry_points.txt +0 -0
  163. {ert-17.1.9.dist-info → ert-18.0.1.dist-info}/licenses/COPYING +0 -0
  164. {ert-17.1.9.dist-info → ert-18.0.1.dist-info}/top_level.txt +0 -0
@@ -17,21 +17,22 @@ from enum import IntEnum, auto
17
17
  from functools import cached_property
18
18
  from pathlib import Path
19
19
  from types import TracebackType
20
- from typing import TYPE_CHECKING, Any, Protocol
20
+ from typing import TYPE_CHECKING, Any, Protocol, cast
21
21
 
22
22
  import numpy as np
23
23
  from numpy.typing import NDArray
24
24
  from pydantic import PrivateAttr, ValidationError
25
25
  from ropt.enums import ExitCode as RoptExitCode
26
26
  from ropt.evaluator import EvaluatorContext, EvaluatorResult
27
- from ropt.plan import BasicOptimizer
28
27
  from ropt.results import FunctionResults, Results
29
28
  from ropt.transforms import OptModelTransforms
29
+ from ropt.workflow import BasicOptimizer
30
30
  from typing_extensions import TypedDict
31
31
 
32
32
  from ert.config import (
33
33
  EverestConstraintsConfig,
34
34
  EverestObjectivesConfig,
35
+ ExtParamConfig,
35
36
  GenDataConfig,
36
37
  HookRuntime,
37
38
  KnownQueueOptionsAdapter,
@@ -57,18 +58,14 @@ from everest.config import (
57
58
  InputConstraintConfig,
58
59
  ModelConfig,
59
60
  OptimizationConfig,
60
- OutputConstraintConfig,
61
61
  )
62
- from everest.config.forward_model_config import SummaryResults
62
+ from everest.config.forward_model_config import ForwardModelStepConfig, SummaryResults
63
63
  from everest.everest_storage import EverestStorage
64
64
  from everest.optimizer.everest2ropt import everest2ropt
65
65
  from everest.optimizer.opt_model_transforms import (
66
66
  EverestOptModelTransforms,
67
67
  get_optimization_domain_transforms,
68
68
  )
69
- from everest.simulator.everest_to_ert import (
70
- extract_summary_keys,
71
- )
72
69
  from everest.strings import EVEREST
73
70
 
74
71
  from ..run_arg import RunArg, create_run_arguments
@@ -76,7 +73,7 @@ from ..storage import ExperimentState, ExperimentStatus
76
73
  from ..storage.local_ensemble import EverestRealizationInfo
77
74
  from ..substitutions import Substitutions
78
75
  from .event import EverestBatchResultEvent, EverestStatusEvent
79
- from .run_model import RunModel, StatusEvents
76
+ from .run_model import RunModel, RunModelConfig, StatusEvents
80
77
 
81
78
  if TYPE_CHECKING:
82
79
  from ert.storage import Ensemble, Experiment
@@ -225,24 +222,22 @@ def _get_workflows(
225
222
  return res_hooks, res_workflows
226
223
 
227
224
 
228
- class EverestRunModel(RunModel):
225
+ class EverestRunModelConfig(RunModelConfig):
229
226
  optimization_output_dir: str
230
227
  simulation_dir: str
231
228
 
232
229
  parameter_configuration: list[ParameterConfig]
233
230
  response_configuration: list[ResponseConfig]
234
- controls: list[ControlConfig]
235
231
 
236
232
  input_constraints: list[InputConstraintConfig]
237
-
238
- output_constraints: list[OutputConstraintConfig]
239
-
240
233
  optimization: OptimizationConfig
241
234
  model: ModelConfig
242
235
  keep_run_path: bool
243
236
  experiment_name: str
244
237
  target_ensemble: str
245
238
 
239
+
240
+ class EverestRunModel(RunModel, EverestRunModelConfig):
246
241
  _exit_code: EverestExitCode | None = PrivateAttr(default=None)
247
242
  _experiment: Experiment | None = PrivateAttr(default=None)
248
243
  _eval_server_cfg: EvaluatorServerConfig | None = PrivateAttr(default=None)
@@ -297,15 +292,9 @@ class EverestRunModel(RunModel):
297
292
 
298
293
  response_configs.append(everest_config.create_ert_objectives_config())
299
294
 
300
- constraint_names = [c.name for c in everest_config.output_constraints]
301
-
302
- if constraint_names:
303
- response_configs.append(
304
- EverestConstraintsConfig(
305
- keys=constraint_names,
306
- input_files=constraint_names,
307
- )
308
- )
295
+ constraints_config = everest_config.create_ert_output_constraints_config()
296
+ if constraints_config is not None:
297
+ response_configs.append(constraints_config)
309
298
 
310
299
  gen_data_keys = [
311
300
  fm.results.file_name
@@ -327,7 +316,7 @@ class EverestRunModel(RunModel):
327
316
  eclbase = summary_fm.results.file_name
328
317
  response_configs.append(
329
318
  SummaryConfig(
330
- keys=extract_summary_keys(everest_config), input_files=[eclbase]
319
+ keys=_extract_summary_keys(everest_config), input_files=[eclbase]
331
320
  )
332
321
  )
333
322
  else:
@@ -340,7 +329,7 @@ class EverestRunModel(RunModel):
340
329
  runpath_format_string=str(
341
330
  Path(everest_config.simulation_dir)
342
331
  / "batch_<ITER>"
343
- / "realization_<GEO_ID>"
332
+ / "realization_<REALIZATION_ID>"
344
333
  / "<SIM_DIR>"
345
334
  ),
346
335
  eclbase_format_string=eclbase
@@ -382,7 +371,7 @@ class EverestRunModel(RunModel):
382
371
  # Only take into account site queue options
383
372
  # if and only if they exist and are of same type as user
384
373
  # specified queue system
385
- applied_site_queue_options = (
374
+ site_queue_options_to_apply = (
386
375
  runtime_plugins.queue_options.model_dump(exclude_unset=True)
387
376
  if (
388
377
  runtime_plugins is not None
@@ -393,7 +382,7 @@ class EverestRunModel(RunModel):
393
382
  else {}
394
383
  )
395
384
 
396
- queue_options_dict = applied_site_queue_options | queue_options_from_everconfig
385
+ queue_options_dict = site_queue_options_to_apply | queue_options_from_everconfig
397
386
 
398
387
  queue_options = KnownQueueOptionsAdapter.validate_python(queue_options_dict)
399
388
 
@@ -521,7 +510,6 @@ class EverestRunModel(RunModel):
521
510
  objective_names=everest_config.objective_names,
522
511
  objective_functions=everest_config.objective_functions,
523
512
  input_constraints=everest_config.input_constraints,
524
- output_constraints=everest_config.output_constraints,
525
513
  optimization=everest_config.optimization,
526
514
  model=everest_config.model,
527
515
  optimization_output_dir=everest_config.optimization_output_dir,
@@ -546,13 +534,23 @@ class EverestRunModel(RunModel):
546
534
  optimization_callback=optimization_callback,
547
535
  )
548
536
 
537
+ @property
538
+ def ext_param_configs(self) -> list[ExtParamConfig]:
539
+ ext_params = [
540
+ c for c in self.parameter_configuration if c.type == "everest_parameters"
541
+ ]
542
+
543
+ # There will and must always be one extparam config for an
544
+ # Everest optimization.
545
+ return cast(list[ExtParamConfig], ext_params)
546
+
549
547
  @cached_property
550
548
  def _transforms(self) -> EverestOptModelTransforms:
551
549
  return get_optimization_domain_transforms(
552
- self.controls,
550
+ self.ext_param_configs,
553
551
  self.objectives_config,
554
552
  self.input_constraints,
555
- self.output_constraints,
553
+ self.output_constraints_config,
556
554
  self.model,
557
555
  self.optimization.auto_scale,
558
556
  )
@@ -646,6 +644,19 @@ class EverestRunModel(RunModel):
646
644
  )
647
645
  )
648
646
 
647
+ @property
648
+ def output_constraints_config(self) -> EverestConstraintsConfig | None:
649
+ constraints_config = next(
650
+ (c for c in self.response_configuration if c.type == "everest_constraints"),
651
+ None,
652
+ )
653
+
654
+ if constraints_config is None:
655
+ return None
656
+
657
+ assert isinstance(constraints_config, EverestConstraintsConfig)
658
+ return constraints_config
659
+
649
660
  @property
650
661
  def objectives_config(self) -> EverestObjectivesConfig:
651
662
  obj_config = next(
@@ -682,18 +693,18 @@ class EverestRunModel(RunModel):
682
693
  )
683
694
 
684
695
  formatted_control_names = [
685
- name for config in self.controls for name in config.formatted_control_names
696
+ name for config in self.ext_param_configs for name in config.input_keys
686
697
  ]
687
698
  self._ever_storage.init(
688
699
  formatted_control_names=formatted_control_names,
689
700
  objective_functions=self.objectives_config,
690
- output_constraints=self.output_constraints,
701
+ output_constraints=self.output_constraints_config,
691
702
  realizations=self.model.realizations,
692
703
  )
693
704
  optimizer.set_results_callback(self._handle_optimizer_results)
694
705
 
695
706
  # Run the optimization:
696
- optimizer_exit_code = optimizer.run(initial_guesses).exit_code
707
+ optimizer_exit_code = optimizer.run(initial_guesses)
697
708
 
698
709
  # Store some final results.
699
710
  self._ever_storage.on_optimization_finished()
@@ -751,10 +762,10 @@ class EverestRunModel(RunModel):
751
762
 
752
763
  def _create_optimizer(self) -> tuple[BasicOptimizer, list[float]]:
753
764
  enopt_config, initial_guesses = everest2ropt(
754
- self.controls,
765
+ cast(list[ExtParamConfig], self.parameter_configuration),
755
766
  self.objectives_config,
756
767
  self.input_constraints,
757
- self.output_constraints,
768
+ self.output_constraints_config,
758
769
  self.optimization,
759
770
  self.model,
760
771
  self.random_seed,
@@ -821,12 +832,7 @@ class EverestRunModel(RunModel):
821
832
  for sim_id in range(sim_to_control_vector.shape[0]):
822
833
  sim_controls = sim_to_control_vector[sim_id]
823
834
  offset = 0
824
- for control_config in self.controls:
825
- ext_param_config = next(
826
- c
827
- for c in self.parameter_configuration
828
- if c.name == control_config.name
829
- )
835
+ for ext_param_config in self.ext_param_configs:
830
836
  n_param_keys = len(ext_param_config.parameter_keys)
831
837
 
832
838
  # Save controls to ensemble
@@ -1004,10 +1010,10 @@ class EverestRunModel(RunModel):
1004
1010
  )
1005
1011
  constraints = (
1006
1012
  np.zeros(
1007
- (num_all_simulations, len(self.output_constraints)),
1013
+ (num_all_simulations, len(self.output_constraints_config.keys)),
1008
1014
  dtype=np.float64,
1009
1015
  )
1010
- if self.output_constraints
1016
+ if self.output_constraints_config
1011
1017
  else None
1012
1018
  )
1013
1019
  sim_ids = np.array([-1] * num_all_simulations, dtype=np.int32)
@@ -1070,7 +1076,7 @@ class EverestRunModel(RunModel):
1070
1076
  for sim_id, (model_realization, perturbation) in enumerate(
1071
1077
  zip(sim_to_model_realization, sim_to_perturbation, strict=True)
1072
1078
  ):
1073
- substitutions[f"<GEO_ID_{sim_id}_{ensemble.iteration}>"] = str(
1079
+ substitutions[f"<REALIZATION_ID_{sim_id}_{ensemble.iteration}>"] = str(
1074
1080
  int(model_realization)
1075
1081
  )
1076
1082
  if perturbation >= 0:
@@ -1120,7 +1126,11 @@ class EverestRunModel(RunModel):
1120
1126
  objective_names = self.objectives_config.keys
1121
1127
  objectives = np.zeros((ensemble.ensemble_size, len(objective_names)))
1122
1128
 
1123
- constraint_names = [c.name for c in self.output_constraints]
1129
+ constraint_names = (
1130
+ self.output_constraints_config.keys
1131
+ if self.output_constraints_config is not None
1132
+ else []
1133
+ )
1124
1134
  constraints = np.zeros((ensemble.ensemble_size, len(constraint_names)))
1125
1135
 
1126
1136
  if not any(self.active_realizations):
@@ -1157,3 +1167,104 @@ class EverestRunModel(RunModel):
1157
1167
  return os.path.exists(self.simulation_dir) and any(
1158
1168
  os.listdir(self.simulation_dir)
1159
1169
  )
1170
+
1171
+
1172
+ def _extract_summary_keys(ever_config: EverestConfig) -> list[str]:
1173
+ DEFAULT_DATA_SUMMARY_KEYS = ["YEAR", "YEARS", "TCPU", "TCPUDAY", "MONTH", "DAY"]
1174
+
1175
+ DEFAULT_FIELD_SUMMARY_KEYS = [
1176
+ "FOPR",
1177
+ "FOPT",
1178
+ "FOIR",
1179
+ "FOIT",
1180
+ "FWPR",
1181
+ "FWPT",
1182
+ "FWIR",
1183
+ "FWIT",
1184
+ "FGPR",
1185
+ "FGPT",
1186
+ "FGIR",
1187
+ "FGIT",
1188
+ "FVPR",
1189
+ "FVPT",
1190
+ "FVIR",
1191
+ "FVIT",
1192
+ "FWCT",
1193
+ "FGOR",
1194
+ "FOIP",
1195
+ "FOIPL",
1196
+ "FOIPG",
1197
+ "FWIP",
1198
+ "FGIP",
1199
+ "FGIPL",
1200
+ "FGIPG",
1201
+ "FPR",
1202
+ "FAQR",
1203
+ "FAQRG",
1204
+ "FAQT",
1205
+ "FAQTG",
1206
+ "FWGR",
1207
+ ]
1208
+
1209
+ DEFAULT_WELL_SUMMARY_KEYS = [
1210
+ "WOPR",
1211
+ "WOPT",
1212
+ "WOIR",
1213
+ "WOIT",
1214
+ "WWPR",
1215
+ "WWPT",
1216
+ "WWIR",
1217
+ "WWIT",
1218
+ "WGPR",
1219
+ "WGPT",
1220
+ "WGIR",
1221
+ "WGIT",
1222
+ "WVPR",
1223
+ "WVPT",
1224
+ "WVIR",
1225
+ "WVIT",
1226
+ "WWCT",
1227
+ "WGOR",
1228
+ "WWGR",
1229
+ "WBHP",
1230
+ "WTHP",
1231
+ "WPI",
1232
+ ]
1233
+
1234
+ DEFAULT_WELL_TARGET_SUMMARY_KEYS = [
1235
+ well_key + "T"
1236
+ for well_key in DEFAULT_WELL_SUMMARY_KEYS
1237
+ if well_key.endswith("R") and well_key != "WGOR"
1238
+ ]
1239
+
1240
+ summary_fms: list[ForwardModelStepConfig] = [
1241
+ fm
1242
+ for fm in ever_config.forward_model
1243
+ if fm.results is not None and fm.results.type == "summary"
1244
+ ]
1245
+
1246
+ if not summary_fms:
1247
+ return []
1248
+
1249
+ smry_results = summary_fms[0].results
1250
+ assert isinstance(smry_results, SummaryResults)
1251
+
1252
+ requested_keys: list[str] = ["*"] if smry_results.keys == "*" else smry_results.keys
1253
+
1254
+ well_keys = [
1255
+ f"{sum_key}:*"
1256
+ for sum_key in DEFAULT_WELL_SUMMARY_KEYS + DEFAULT_WELL_TARGET_SUMMARY_KEYS
1257
+ ]
1258
+ deprecated_user_specified_keys = (
1259
+ [] if ever_config.export is None else ever_config.export.keywords
1260
+ )
1261
+
1262
+ return list(
1263
+ set(
1264
+ requested_keys
1265
+ + DEFAULT_DATA_SUMMARY_KEYS
1266
+ + DEFAULT_FIELD_SUMMARY_KEYS
1267
+ + well_keys
1268
+ + deprecated_user_specified_keys
1269
+ )
1270
+ )
@@ -1,4 +1,3 @@
1
- from abc import ABC
2
1
  from typing import Annotated, Any, Literal, Self
3
2
 
4
3
  import numpy as np
@@ -7,26 +6,24 @@ from polars.datatypes import DataTypeClass
7
6
  from pydantic import BaseModel, Field, field_validator
8
7
 
9
8
  from ert.config import (
10
- EverestConstraintsConfig,
11
- EverestObjectivesConfig,
12
9
  ExtParamConfig,
13
- GenDataConfig,
14
10
  GenKwConfig,
15
- SummaryConfig,
11
+ KnownResponseTypes,
16
12
  SurfaceConfig,
17
13
  )
18
14
  from ert.config import Field as FieldConfig
19
15
  from ert.ensemble_evaluator.config import EvaluatorServerConfig
20
16
  from ert.run_arg import create_run_arguments
21
- from ert.run_models.run_model import RunModel
17
+ from ert.run_models.run_model import RunModel, RunModelConfig
22
18
  from ert.sample_prior import sample_prior
23
19
  from ert.storage.local_ensemble import LocalEnsemble
24
20
 
25
-
26
21
  # https://github.com/pola-rs/polars/issues/13152#issuecomment-1864600078
27
22
  # PS: Serializing/deserializing schema is scheduled to be added to polars core,
28
23
  # ref https://github.com/pola-rs/polars/issues/20426
29
24
  # then this workaround can be omitted.
25
+
26
+
30
27
  def str_to_dtype(dtype_str: str) -> pl.DataType:
31
28
  dtype = eval(f"pl.{dtype_str}")
32
29
  if isinstance(dtype, DataTypeClass):
@@ -54,7 +51,7 @@ class DictEncodedDataFrame(BaseModel):
54
51
  )
55
52
 
56
53
 
57
- class InitialEnsembleRunModel(RunModel, ABC):
54
+ class InitialEnsembleRunModelConfig(RunModelConfig):
58
55
  experiment_name: str
59
56
  design_matrix: DictEncodedDataFrame | None
60
57
  parameter_configuration: list[
@@ -65,31 +62,35 @@ class InitialEnsembleRunModel(RunModel, ABC):
65
62
  ]
66
63
  response_configuration: list[
67
64
  Annotated[
68
- (
69
- GenDataConfig
70
- | SummaryConfig
71
- | EverestConstraintsConfig
72
- | EverestObjectivesConfig
73
- ),
65
+ (KnownResponseTypes),
74
66
  Field(discriminator="type"),
75
67
  ]
76
68
  ]
77
69
  ert_templates: list[tuple[str, str]]
78
- observations: dict[str, DictEncodedDataFrame] | None
70
+ observations: dict[str, DictEncodedDataFrame] | None = None
79
71
 
80
72
  @field_validator("observations", mode="before")
73
+ @classmethod
81
74
  def make_dict_encoded_observations(
82
- cls, v: dict[str, pl.DataFrame | DictEncodedDataFrame] | None
75
+ cls, v: dict[str, pl.DataFrame | DictEncodedDataFrame | dict[str, Any]] | None
83
76
  ) -> dict[str, DictEncodedDataFrame] | None:
84
77
  if v is None:
85
78
  return None
86
- return {
87
- k: df
88
- if isinstance(df, DictEncodedDataFrame)
89
- else DictEncodedDataFrame.from_polars(df)
90
- for k, df in v.items()
91
- }
92
79
 
80
+ encoded = {}
81
+ for k, df in v.items():
82
+ match df:
83
+ case DictEncodedDataFrame():
84
+ encoded[k] = df
85
+ case pl.DataFrame():
86
+ encoded[k] = DictEncodedDataFrame.from_polars(df)
87
+ case dict():
88
+ encoded[k] = DictEncodedDataFrame.model_validate(df)
89
+
90
+ return encoded
91
+
92
+
93
+ class InitialEnsembleRunModel(RunModel, InitialEnsembleRunModelConfig):
93
94
  def _sample_and_evaluate_ensemble(
94
95
  self,
95
96
  evaluator_server_config: EvaluatorServerConfig,
@@ -8,7 +8,7 @@ from uuid import UUID
8
8
  from pydantic import PrivateAttr
9
9
 
10
10
  from ert.ensemble_evaluator import EvaluatorServerConfig
11
- from ert.run_models.update_run_model import UpdateRunModel
11
+ from ert.run_models.update_run_model import UpdateRunModel, UpdateRunModelConfig
12
12
  from ert.storage import Ensemble
13
13
 
14
14
  from ..analysis import smoother_update
@@ -17,10 +17,12 @@ from .run_model import ErtRunError
17
17
  logger = logging.getLogger(__name__)
18
18
 
19
19
 
20
- class ManualUpdate(UpdateRunModel):
20
+ class ManualUpdateConfig(UpdateRunModelConfig):
21
21
  ensemble_id: str
22
22
  ert_templates: list[tuple[str, str]]
23
23
 
24
+
25
+ class ManualUpdate(UpdateRunModel, ManualUpdateConfig):
24
26
  _prior: Ensemble = PrivateAttr()
25
27
 
26
28
  def model_post_init(self, ctx: Any) -> None:
@@ -0,0 +1,37 @@
1
+ from __future__ import annotations
2
+
3
+ import functools
4
+ import logging
5
+
6
+ from ert.storage import Ensemble
7
+
8
+ from ..analysis import enif_update
9
+ from .manual_update import ManualUpdate
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ class ManualUpdateEnIF(ManualUpdate):
15
+ @classmethod
16
+ def name(cls) -> str:
17
+ return "Manual EnIF update (Experimental)"
18
+
19
+ @classmethod
20
+ def description(cls) -> str:
21
+ return "Load parameters and responses from existing → EnIF update"
22
+
23
+ def update_ensemble_parameters(
24
+ self, prior: Ensemble, posterior: Ensemble, weight: float
25
+ ) -> None:
26
+ enif_update(
27
+ prior,
28
+ posterior,
29
+ parameters=prior.experiment.update_parameters,
30
+ observations=prior.experiment.observation_keys,
31
+ random_seed=self.random_seed,
32
+ progress_callback=functools.partial(
33
+ self.send_smoother_event,
34
+ prior.iteration,
35
+ prior.id,
36
+ ),
37
+ )