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
@@ -16,37 +16,39 @@ info = (
16
16
  def point_experiments_to_ensembles(path: Path) -> None:
17
17
  experiment_to_ensemble: dict[str, list[str]] = {}
18
18
  for ensemble in path.glob("ensembles/*"):
19
- with open(ensemble / "index.json", encoding="utf-8") as fin:
20
- index_ = json.load(fin)
21
- ensemble_id = index_["id"]
22
- experiment_id = index_["experiment_id"]
19
+ index_ = json.loads((ensemble / "index.json").read_text(encoding="utf-8"))
20
+ ensemble_id = index_["id"]
21
+ experiment_id = index_["experiment_id"]
23
22
 
24
- if experiment_id not in experiment_to_ensemble:
25
- experiment_to_ensemble[experiment_id] = []
23
+ if experiment_id not in experiment_to_ensemble:
24
+ experiment_to_ensemble[experiment_id] = []
26
25
 
27
- experiment_to_ensemble[experiment_id].append(ensemble_id)
26
+ experiment_to_ensemble[experiment_id].append(ensemble_id)
28
27
 
29
28
  for experiment_path in path.glob("experiments/*"):
30
- with open(experiment_path / "index.json", encoding="utf-8") as fin:
31
- old_json = json.load(fin)
32
- exp_id = old_json["id"]
29
+ old_json = json.loads(
30
+ (experiment_path / "index.json").read_text(encoding="utf-8")
31
+ )
32
+ exp_id = old_json["id"]
33
33
 
34
34
  if exp_id not in experiment_to_ensemble:
35
- with open(experiment_path / "index.json", "w", encoding="utf-8") as fout:
36
- json.dump(
35
+ (experiment_path / "index.json").write_text(
36
+ json.dumps(
37
37
  old_json | {"ensembles": []},
38
- fout,
39
38
  indent=2,
40
- )
39
+ ),
40
+ encoding="utf-8",
41
+ )
41
42
  continue
42
43
 
43
- with open(experiment_path / "index.json", "w", encoding="utf-8") as fout:
44
- json.dump(
44
+ (experiment_path / "index.json").write_text(
45
+ json.dumps(
45
46
  old_json
46
47
  | {"ensembles": sorted(experiment_to_ensemble.get(exp_id, []))},
47
- fout,
48
48
  indent=2,
49
- )
49
+ ),
50
+ encoding="utf-8",
51
+ )
50
52
 
51
53
 
52
54
  tfd_to_distributions = {
@@ -101,12 +103,12 @@ def migrate_genkw(path: Path) -> None:
101
103
  ensembles = path.glob("ensembles/*")
102
104
 
103
105
  experiment_id = None
104
- with open(experiment / "index.json", encoding="utf-8") as f:
105
- exp_index = json.load(f)
106
- experiment_id = exp_index["id"]
106
+ exp_index = json.loads((experiment / "index.json").read_text(encoding="utf-8"))
107
+ experiment_id = exp_index["id"]
107
108
 
108
- with open(experiment / "parameter.json", encoding="utf-8") as fin:
109
- parameters_json = json.load(fin)
109
+ parameters_json = json.loads(
110
+ (experiment / "parameter.json").read_text(encoding="utf-8")
111
+ )
110
112
 
111
113
  new_parameter_configs = migrate_gen_kw_param(parameters_json)
112
114
  Path(experiment / "parameter.json").write_text(
@@ -115,10 +117,9 @@ def migrate_genkw(path: Path) -> None:
115
117
 
116
118
  # migrate parquet files
117
119
  for ens in ensembles:
118
- with open(ens / "index.json", encoding="utf-8") as f:
119
- ens_file = json.load(f)
120
- if ens_file["experiment_id"] != experiment_id:
121
- continue
120
+ ens_file = json.loads((ens / "index.json").read_text(encoding="utf-8"))
121
+ if ens_file["experiment_id"] != experiment_id:
122
+ continue
122
123
 
123
124
  group_dfs = []
124
125
  for param_config in parameters_json.values():
@@ -30,9 +30,9 @@ def migrate_field_param(parameters_json: dict[str, Any]) -> dict[str, Any]:
30
30
 
31
31
  def migrate_fields(path: Path) -> None:
32
32
  for experiment in path.glob("experiments/*"):
33
- with open(experiment / "parameter.json", encoding="utf-8") as fin:
34
- parameters_json = json.load(fin)
35
-
33
+ parameters_json = json.loads(
34
+ (experiment / "parameter.json").read_text(encoding="utf-8")
35
+ )
36
36
  new_parameter_configs = migrate_field_param(parameters_json)
37
37
  Path(experiment / "parameter.json").write_text(
38
38
  json.dumps(new_parameter_configs, indent=2), encoding="utf-8"
@@ -0,0 +1,25 @@
1
+ import json
2
+ import pathlib
3
+ from pathlib import Path
4
+ from typing import Any
5
+
6
+ info = "Add status field to experiment index.json files"
7
+
8
+
9
+ def add_experiment_status_to_index_json(index_json: dict[str, Any]) -> dict[str, Any]:
10
+ index_json["status"] = {"message": "", "status": "completed"}
11
+ return index_json
12
+
13
+
14
+ def migrate_index_json(path: Path) -> None:
15
+ for experiment in path.glob("experiments/*"):
16
+ index_path = experiment / "index.json"
17
+ index_data = json.loads(pathlib.Path(index_path).read_text(encoding="utf-8"))
18
+ pathlib.Path(index_path).write_text(
19
+ json.dumps(add_experiment_status_to_index_json(index_data), indent=2),
20
+ encoding="utf-8",
21
+ )
22
+
23
+
24
+ def migrate(path: Path) -> None:
25
+ migrate_index_json(path)
@@ -0,0 +1,38 @@
1
+ import json
2
+ from pathlib import Path
3
+ from typing import Any
4
+
5
+ info = "Remove mask file from field config"
6
+
7
+
8
+ def migrate_field_param(parameters_json: dict[str, Any]) -> dict[str, Any]:
9
+ new_configs = {}
10
+ for param_config in parameters_json.values():
11
+ if param_config["type"] == "field":
12
+ del param_config["mask_file"]
13
+
14
+ new_configs[param_config["name"]] = param_config
15
+ return new_configs
16
+
17
+
18
+ def delete_mask_file(experiment: Path) -> None:
19
+ # delete grid mask file if it exists
20
+ grid_mask_file = experiment / "grid_mask.npy"
21
+ if grid_mask_file.exists():
22
+ grid_mask_file.unlink()
23
+
24
+
25
+ def migrate_fields(experiment: Path) -> None:
26
+ with open(experiment / "parameter.json", encoding="utf-8") as fin:
27
+ parameters_json = json.load(fin)
28
+
29
+ new_parameter_configs = migrate_field_param(parameters_json)
30
+ Path(experiment / "parameter.json").write_text(
31
+ json.dumps(new_parameter_configs, indent=2), encoding="utf-8"
32
+ )
33
+
34
+
35
+ def migrate(path: Path) -> None:
36
+ for experiment in path.glob("experiments/*"):
37
+ migrate_fields(experiment)
38
+ delete_mask_file(experiment)
@@ -0,0 +1,42 @@
1
+ import json
2
+ from pathlib import Path
3
+ from typing import Any
4
+
5
+ info = "Migrate realization error type from IntEnum to StrEnum"
6
+
7
+
8
+ def migrate_realization_errors_json_content(
9
+ error_json: dict[str, Any],
10
+ ) -> dict[str, Any]:
11
+ int_to_str = {
12
+ 1: "undefined",
13
+ 2: "parameters_loaded",
14
+ 4: "responses_loaded",
15
+ 8: "failure_in_current",
16
+ 16: "failure_in_parent",
17
+ # To cover cases who ran with storage version 16
18
+ # and StrEnum _RealizationStorageState
19
+ "undefined": "undefined",
20
+ "parameters_loaded": "parameters_loaded",
21
+ "responses_loaded": "responses_loaded",
22
+ "failure_in_current": "failure_in_current",
23
+ "failure_in_parent": "failure_in_parent",
24
+ }
25
+ return error_json | {"type": int_to_str[error_json["type"]]}
26
+
27
+
28
+ def migrate_realization_errors(path: Path) -> None:
29
+ for realization_error in path.glob("ensembles/*/realization-*/error.json"):
30
+ old_error_json_content = json.loads(
31
+ realization_error.read_text(encoding="utf-8")
32
+ )
33
+ realization_error.write_text(
34
+ json.dumps(
35
+ migrate_realization_errors_json_content(old_error_json_content),
36
+ indent=2,
37
+ )
38
+ )
39
+
40
+
41
+ def migrate(path: Path) -> None:
42
+ migrate_realization_errors(path)
@@ -0,0 +1,11 @@
1
+ from pathlib import Path
2
+
3
+ info = (
4
+ "Added localization attributes to summary observations."
5
+ "Added RFT observations."
6
+ "No change to current storage, only additions. "
7
+ )
8
+
9
+
10
+ def migrate(path: Path) -> None:
11
+ pass
@@ -0,0 +1,34 @@
1
+ import json
2
+ from pathlib import Path
3
+ from typing import Any
4
+
5
+ info = "Add dimensionality attribute to parameters"
6
+
7
+
8
+ def migrate_param(parameters_json: dict[str, Any]) -> dict[str, Any]:
9
+ new_configs = {}
10
+ for param_config in parameters_json.values():
11
+ if param_config["type"] == "surface":
12
+ param_config["dimensionality"] = 2
13
+ elif param_config["type"] == "field":
14
+ param_config["dimensionality"] = 3
15
+ else:
16
+ param_config["dimensionality"] = 1
17
+
18
+ new_configs[param_config["name"]] = param_config
19
+ return new_configs
20
+
21
+
22
+ def migrate_parameters_for_experiment(experiment: Path) -> None:
23
+ with open(experiment / "parameter.json", encoding="utf-8") as fin:
24
+ parameters_json = json.load(fin)
25
+
26
+ new_parameter_configs = migrate_param(parameters_json)
27
+ Path(experiment / "parameter.json").write_text(
28
+ json.dumps(new_parameter_configs, indent=2), encoding="utf-8"
29
+ )
30
+
31
+
32
+ def migrate(path: Path) -> None:
33
+ for experiment in path.glob("experiments/*"):
34
+ migrate_parameters_for_experiment(experiment)
@@ -0,0 +1,23 @@
1
+ import json
2
+ from pathlib import Path
3
+ from typing import Any
4
+
5
+ info = "Remove redundant .name attribute from responses."
6
+
7
+
8
+ def config_without_name_attr(config: dict[str, Any]) -> dict[str, Any]:
9
+ new_json = {**config}
10
+ new_json.pop("name", None)
11
+
12
+ return new_json
13
+
14
+
15
+ def migrate(path: Path) -> None:
16
+ for response_json_path in path.glob("experiments/*/responses.json"):
17
+ old_json = json.loads((response_json_path).read_text(encoding="utf-8"))
18
+ new_json = {
19
+ response_type: config_without_name_attr(config)
20
+ for response_type, config in old_json.items()
21
+ }
22
+
23
+ response_json_path.write_text(json.dumps(new_json, indent=2), encoding="utf-8")
@@ -0,0 +1,25 @@
1
+ import json
2
+ from pathlib import Path
3
+ from typing import Any
4
+
5
+ info = "Remove refcase from summary response configs"
6
+
7
+
8
+ def config_without_refcase(summary_config: dict[str, Any]) -> dict[str, Any]:
9
+ new_json = {**summary_config}
10
+ new_json.pop("refcase", None)
11
+
12
+ return new_json
13
+
14
+
15
+ def migrate(path: Path) -> None:
16
+ for response_json_path in path.glob("experiments/*/responses.json"):
17
+ old_json = json.loads((response_json_path).read_text(encoding="utf-8"))
18
+ new_json = {
19
+ response_type: config_without_refcase(response_config)
20
+ if response_config["type"] == "summary"
21
+ else response_config
22
+ for response_type, response_config in old_json.items()
23
+ }
24
+
25
+ response_json_path.write_text(json.dumps(new_json, indent=2), encoding="utf-8")
@@ -6,8 +6,9 @@ info = "Rename and change transfer_function_definitions"
6
6
 
7
7
  def migrate(path: Path) -> None:
8
8
  for experiment in path.glob("experiments/*"):
9
- with open(experiment / "parameter.json", encoding="utf-8") as fin:
10
- parameters_json = json.load(fin)
9
+ parameters_json = json.loads(
10
+ (experiment / "parameter.json").read_text(encoding="utf-8")
11
+ )
11
12
 
12
13
  for param in parameters_json.values():
13
14
  if "transfer_function_definitions" in param:
@@ -9,8 +9,9 @@ info = "Standardize response configs"
9
9
 
10
10
  def _migrate_response_configs(path: Path) -> None:
11
11
  for experiment in path.glob("experiments/*"):
12
- with open(experiment / "responses.json", encoding="utf-8") as fin:
13
- responses = json.load(fin)
12
+ responses = json.loads(
13
+ (experiment / "responses.json").read_text(encoding="utf-8")
14
+ )
14
15
 
15
16
  # If we for example do a .to2() migration
16
17
  # this will implicitly upgrade it to v7 since
@@ -58,8 +59,9 @@ def _migrate_response_configs(path: Path) -> None:
58
59
  }
59
60
  )
60
61
 
61
- with open(experiment / "responses.json", "w", encoding="utf-8") as fout:
62
- json.dump(migrated, fout)
62
+ (experiment / "responses.json").write_text(
63
+ json.dumps(migrated), encoding="utf-8"
64
+ )
63
65
 
64
66
 
65
67
  def _ensure_coord_order(
@@ -83,13 +85,11 @@ def _migrate_response_datasets(path: Path) -> None:
83
85
  ensembles = path.glob("ensembles/*")
84
86
 
85
87
  experiment_id = None
86
- with open(experiment / "index.json", encoding="utf-8") as f:
87
- exp_index = json.load(f)
88
- experiment_id = exp_index["id"]
88
+ exp_index = json.loads((experiment / "index.json").read_text(encoding="utf-8"))
89
+ experiment_id = exp_index["id"]
89
90
 
90
91
  responses_file = experiment / "responses.json"
91
- with open(responses_file, encoding="utf-8") as f:
92
- responses_obj = json.load(f)
92
+ responses_obj = json.loads(responses_file.read_text(encoding="utf-8"))
93
93
 
94
94
  assert responses_obj is not None, (
95
95
  f"Failed to load responses.json @ {responses_file}"
@@ -98,10 +98,9 @@ def _migrate_response_datasets(path: Path) -> None:
98
98
  gendata_keys = responses_obj.get("gen_data", {}).get("keys", [])
99
99
 
100
100
  for ens in ensembles:
101
- with open(ens / "index.json", encoding="utf-8") as f:
102
- ens_file = json.load(f)
103
- if ens_file["experiment_id"] != experiment_id:
104
- continue
101
+ ens_file = json.loads((ens / "index.json").read_text(encoding="utf-8"))
102
+ if ens_file["experiment_id"] != experiment_id:
103
+ continue
105
104
 
106
105
  real_dirs = [*ens.glob("realization-*")]
107
106
 
@@ -63,15 +63,13 @@ def _migrate_responses_from_netcdf_to_parquet(path: Path) -> None:
63
63
  ensembles = path.glob("ensembles/*")
64
64
 
65
65
  experiment_id = None
66
- with open(experiment / "index.json", encoding="utf-8") as f:
67
- exp_index = json.load(f)
68
- experiment_id = exp_index["id"]
66
+ exp_index = json.loads((experiment / "index.json").read_text(encoding="utf-8"))
67
+ experiment_id = exp_index["id"]
69
68
 
70
69
  for ens in ensembles:
71
- with open(ens / "index.json", encoding="utf-8") as f:
72
- ens_file = json.load(f)
73
- if ens_file["experiment_id"] != experiment_id:
74
- continue
70
+ ens_file = json.loads((ens / "index.json").read_text(encoding="utf-8"))
71
+ if ens_file["experiment_id"] != experiment_id:
72
+ continue
75
73
 
76
74
  real_dirs = [*ens.glob("realization-*")]
77
75
 
@@ -140,14 +138,14 @@ def _migrate_observations_to_grouped_parquet(path: Path) -> None:
140
138
 
141
139
  for response_type in ["gen_data", "summary"]:
142
140
  infos = [
143
- _info for _info in obs_ds_infos if _info.response_type == response_type
141
+ info_ for info_ in obs_ds_infos if info_.response_type == response_type
144
142
  ]
145
143
  if len(infos) > 0:
146
- concatd_df = pl.concat([_info.polars_df for _info in infos])
144
+ concatd_df = pl.concat([info_.polars_df for info_ in infos])
147
145
  concatd_df.write_parquet(experiment / "observations" / response_type)
148
146
 
149
- for _info in infos:
150
- os.remove(_info.original_ds_path)
147
+ for info_ in infos:
148
+ os.remove(info_.original_ds_path)
151
149
 
152
150
 
153
151
  def migrate(path: Path) -> None:
@@ -39,10 +39,11 @@ def migrate(path: Path) -> None:
39
39
  if not config.get("has_finalized_keys"):
40
40
  # Read a sample response and write the keys
41
41
  for ens in ensembles:
42
- with open(ens / "index.json", encoding="utf-8") as f_ensemble:
43
- ens_file = json.load(f_ensemble)
44
- if ens_file["experiment_id"] != experiment_id:
45
- continue
42
+ ens_file = json.loads(
43
+ (ens / "index.json").read_text(encoding="utf-8")
44
+ )
45
+ if ens_file["experiment_id"] != experiment_id:
46
+ continue
46
47
 
47
48
  real_dirs = [*ens.glob("realization-*")]
48
49
 
@@ -1,9 +1,9 @@
1
- from enum import Enum
1
+ from enum import StrEnum, auto
2
2
 
3
3
 
4
- class RealizationStorageState(Enum):
5
- UNDEFINED = 1
6
- PARAMETERS_LOADED = 2
7
- RESPONSES_LOADED = 4
8
- FAILURE_IN_CURRENT = 8
9
- FAILURE_IN_PARENT = 16
4
+ class RealizationStorageState(StrEnum):
5
+ UNDEFINED = auto()
6
+ PARAMETERS_LOADED = auto()
7
+ RESPONSES_LOADED = auto()
8
+ FAILURE_IN_CURRENT = auto()
9
+ FAILURE_IN_PARENT = auto()
ert/substitutions.py CHANGED
@@ -4,6 +4,7 @@ import logging
4
4
  import re
5
5
  from collections import UserDict
6
6
  from collections.abc import Mapping
7
+ from typing import Self
7
8
 
8
9
  logger = logging.getLogger(__name__)
9
10
  _PATTERN = re.compile(r"<[^<>]+>")
@@ -25,44 +26,27 @@ class Substitutions(UserDict[str, str]):
25
26
  """
26
27
  return _substitute(self, to_substitute, context, max_iterations, warn_max_iter)
27
28
 
28
- @staticmethod
29
- def substitute_parameters(
30
- to_substitute: str, parameter_values: Mapping[str, Mapping[str, str | float]]
31
- ) -> str:
32
- """Applies the substitution '<param_name>' to parameter value
33
- Args:
34
- parameter_values: Mapping from parameter name to parameter value
35
- to_substitute: string to substitute magic strings in
36
- Returns:
37
- substituted string
38
- """
39
- for values in parameter_values.values():
40
- for param_name, value in values.items():
41
- if isinstance(value, (int, float)):
42
- formatted_value = f"{value:.6g}"
43
- else:
44
- formatted_value = str(value)
45
- to_substitute = to_substitute.replace(
46
- f"<{param_name}>", formatted_value
47
- )
48
- return to_substitute
49
-
50
- def substitute_real_iter(
51
- self, to_substitute: str, realization: int, iteration: int
52
- ) -> str:
29
+ def real_iter_substituter(self, realization: int, iteration: int) -> Self:
53
30
  extra_data = {
54
31
  "<IENS>": str(realization),
55
32
  "<ITER>": str(iteration),
56
33
  }
57
34
 
58
- model_id_key = f"<GEO_ID_{realization}_{iteration}>"
35
+ model_id_key = f"<REALIZATION_ID_{realization}_{iteration}>"
59
36
  if model_id_key in self:
60
- extra_data["<GEO_ID>"] = self[model_id_key]
37
+ extra_data["<REALIZATION_ID>"] = self[model_id_key]
61
38
  sim_id_key = f"<SIM_DIR_{realization}_{iteration}>"
62
39
  if sim_id_key in self:
63
40
  extra_data["<SIM_DIR>"] = self[sim_id_key]
64
41
 
65
- return Substitutions({**self, **extra_data}).substitute(to_substitute)
42
+ return type(self)({**self, **extra_data})
43
+
44
+ def substitute_real_iter(
45
+ self, to_substitute: str, realization: int, iteration: int
46
+ ) -> str:
47
+ return self.real_iter_substituter(realization, iteration).substitute(
48
+ to_substitute
49
+ )
66
50
 
67
51
  def _concise_representation(self) -> str:
68
52
  return (
@@ -47,19 +47,19 @@ class ActiveRange:
47
47
  raise ValueError(
48
48
  f"Only digits, commas, dashes and spaces are allowed, got {rangestring}"
49
49
  )
50
- for _range in rangestring.split(","):
51
- if "-" in _range:
52
- if len(_range.split("-")) != 2:
53
- raise ValueError(f"Invalid range specified, got {_range}")
54
- realization_bounds = _range.split("-")
50
+ for range_ in rangestring.split(","):
51
+ if "-" in range_:
52
+ if len(range_.split("-")) != 2:
53
+ raise ValueError(f"Invalid range specified, got {range_}")
54
+ realization_bounds = range_.split("-")
55
55
  start = int(realization_bounds[0])
56
56
  end = int(realization_bounds[1])
57
57
  if end < start:
58
58
  raise ValueError(
59
- f"Invalid direction in range specified, got {_range}"
59
+ f"Invalid direction in range specified, got {range_}"
60
60
  )
61
61
  else:
62
- int(_range)
62
+ int(range_)
63
63
  return rangestring
64
64
 
65
65
  @classmethod
@@ -17,11 +17,13 @@ class EnsembleRealizationsArgument(RangeStringArgument):
17
17
  def __init__(
18
18
  self,
19
19
  ensemble: Callable[[], Union["Ensemble", None]],
20
- max_value: int | None,
21
20
  required_realization_storage_states: Iterable["RealizationStorageState"],
22
21
  **kwargs: bool,
23
22
  ) -> None:
24
- super().__init__(max_value, **kwargs)
23
+ ens = ensemble()
24
+ size = ens.ensemble_size if ens is not None else None
25
+ super().__init__(size, **kwargs)
26
+
25
27
  self.__ensemble_getter = ensemble
26
28
  self._required_realization_storage_states: Iterable[RealizationStorageState] = (
27
29
  required_realization_storage_states
@@ -66,11 +66,11 @@ def rangestring_to_mask(rangestring: str, length: int) -> list[bool]:
66
66
  # An empty string means no active indecies. Note that an
67
67
  # IndexRange-typed instance being None means the opposite
68
68
  return mask
69
- for _range in rangestring.split(","):
70
- if "-" in _range:
71
- if len(_range.strip().split("-")) != 2:
72
- raise ValueError(f"Wrong range syntax {_range}")
73
- start, end = map(int, _range.strip().split("-"))
69
+ for range_ in rangestring.split(","):
70
+ if "-" in range_:
71
+ if len(range_.strip().split("-")) != 2:
72
+ raise ValueError(f"Wrong range syntax {range_}")
73
+ start, end = map(int, range_.strip().split("-"))
74
74
  if end < start:
75
75
  raise ValueError(f"Range {start}-{end} has invalid direction")
76
76
  if end + 1 > length:
@@ -78,12 +78,12 @@ def rangestring_to_mask(rangestring: str, length: int) -> list[bool]:
78
78
  f"Range endpoint {end} is beyond the mask length {length}"
79
79
  )
80
80
  mask[start : end + 1] = [True] * (end + 1 - start)
81
- elif _range:
82
- if int(_range) + 1 > length:
81
+ elif range_:
82
+ if int(range_) + 1 > length:
83
83
  raise ValueError(
84
- f"Realization index {_range} is beyond the mask length {length}"
84
+ f"Realization index {range_} is beyond the mask length {length}"
85
85
  )
86
- mask[int(_range)] = True
86
+ mask[int(range_)] = True
87
87
  return mask
88
88
 
89
89
 
@@ -102,14 +102,14 @@ def rangestring_to_list(rangestring: str) -> list[int]:
102
102
  result: set[int] = set()
103
103
  if not rangestring:
104
104
  return []
105
- for _range in rangestring.split(","):
106
- if "-" in _range:
107
- if len(_range.strip().split("-")) != 2:
108
- raise ValueError(f"Wrong range syntax {_range}")
109
- start, end = map(int, _range.strip().split("-"))
105
+ for range_ in rangestring.split(","):
106
+ if "-" in range_:
107
+ if len(range_.strip().split("-")) != 2:
108
+ raise ValueError(f"Wrong range syntax {range_}")
109
+ start, end = map(int, range_.strip().split("-"))
110
110
  if end < start:
111
111
  raise ValueError(f"Range {start}-{end} has invalid direction")
112
112
  result.update(range(start, end + 1))
113
- elif _range:
114
- result.add(int(_range))
113
+ elif range_:
114
+ result.add(int(range_))
115
115
  return list(result)
ert/workflow_runner.py CHANGED
@@ -1,12 +1,14 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import logging
4
+ import types
4
5
  from concurrent import futures
5
6
  from concurrent.futures import Future
6
7
  from typing import Any, Self
7
8
 
8
9
  from ert import ErtScript
9
10
  from ert.config import (
11
+ BaseErtScriptWorkflow,
10
12
  ErtScriptWorkflow,
11
13
  ExternalErtScript,
12
14
  Workflow,
@@ -43,8 +45,9 @@ class WorkflowJobRunner:
43
45
  f"{self.job.max_args} arguments, {len(arguments)} given."
44
46
  )
45
47
 
46
- if isinstance(self.job, ErtScriptWorkflow):
47
- self.__script = self.job.ert_script()
48
+ if isinstance(self.job, BaseErtScriptWorkflow):
49
+ ert_script_class = self.job.load_ert_script_class()
50
+ self.__script = ert_script_class()
48
51
  # We let stop on fail either from class or config take precedence
49
52
  self.stop_on_fail = self.job.stop_on_fail or self.__script.stop_on_fail
50
53
 
@@ -125,7 +128,7 @@ class WorkflowRunner:
125
128
  self,
126
129
  exc_type: type[BaseException] | None,
127
130
  exc_value: BaseException | None,
128
- traceback: Any,
131
+ traceback: types.TracebackType | None,
129
132
  ) -> None:
130
133
  self.wait()
131
134