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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. _ert/events.py +19 -2
  2. ert/__main__.py +8 -7
  3. ert/analysis/_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 +11 -6
  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 +35 -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.0.dist-info}/METADATA +8 -7
  124. {ert-17.1.9.dist-info → ert-18.0.0.dist-info}/RECORD +160 -159
  125. everest/api/everest_data_api.py +1 -14
  126. everest/bin/config_branch_script.py +3 -6
  127. everest/bin/everconfigdump_script.py +1 -9
  128. everest/bin/everest_script.py +21 -11
  129. everest/bin/kill_script.py +2 -2
  130. everest/bin/monitor_script.py +2 -2
  131. everest/bin/utils.py +6 -3
  132. everest/config/__init__.py +4 -1
  133. everest/config/control_config.py +61 -2
  134. everest/config/control_variable_config.py +2 -1
  135. everest/config/everest_config.py +38 -16
  136. everest/config/forward_model_config.py +5 -3
  137. everest/config/install_data_config.py +7 -5
  138. everest/config/install_job_config.py +7 -3
  139. everest/config/install_template_config.py +3 -3
  140. everest/config/optimization_config.py +19 -6
  141. everest/config/output_constraint_config.py +8 -2
  142. everest/config/server_config.py +6 -49
  143. everest/config/utils.py +25 -105
  144. everest/config/validation_utils.py +10 -10
  145. everest/config_file_loader.py +13 -2
  146. everest/detached/everserver.py +7 -8
  147. everest/everest_storage.py +6 -10
  148. everest/gui/everest_client.py +0 -1
  149. everest/gui/main_window.py +2 -2
  150. everest/optimizer/everest2ropt.py +59 -32
  151. everest/optimizer/opt_model_transforms.py +12 -13
  152. everest/optimizer/utils.py +0 -29
  153. everest/strings.py +0 -5
  154. ert/config/everest_constraints_config.py +0 -95
  155. ert/services/storage_service.py +0 -127
  156. everest/config/sampler_config.py +0 -103
  157. everest/simulator/__init__.py +0 -88
  158. everest/simulator/everest_to_ert.py +0 -51
  159. /ert/gui/{suggestor → ertwidgets/suggestor}/__init__.py +0 -0
  160. /ert/gui/{suggestor → ertwidgets/suggestor}/_colors.py +0 -0
  161. /ert/gui/{suggestor → ertwidgets/suggestor}/suggestor.py +0 -0
  162. {ert-17.1.9.dist-info → ert-18.0.0.dist-info}/WHEEL +0 -0
  163. {ert-17.1.9.dist-info → ert-18.0.0.dist-info}/entry_points.txt +0 -0
  164. {ert-17.1.9.dist-info → ert-18.0.0.dist-info}/licenses/COPYING +0 -0
  165. {ert-17.1.9.dist-info → ert-18.0.0.dist-info}/top_level.txt +0 -0
@@ -3,9 +3,9 @@ from dataclasses import dataclass
3
3
  from typing import cast
4
4
 
5
5
  import numpy as np
6
- from PyQt6.QtCore import Qt
6
+ from PyQt6.QtCore import pyqtSignal
7
7
  from PyQt6.QtCore import pyqtSlot as Slot
8
- from PyQt6.QtWidgets import QFormLayout, QLabel, QWidget
8
+ from PyQt6.QtWidgets import QComboBox, QFormLayout, QLabel, QWidget
9
9
  from typing_extensions import override
10
10
 
11
11
  from ert.config import AnalysisConfig, ErrorInfo
@@ -16,11 +16,11 @@ from ert.gui.ertwidgets import (
16
16
  CopyableLabel,
17
17
  EnsembleSelector,
18
18
  StringBox,
19
+ Suggestor,
19
20
  TargetEnsembleModel,
20
21
  )
21
22
  from ert.gui.simulation.experiment_config_panel import ExperimentConfigPanel
22
- from ert.gui.suggestor import Suggestor
23
- from ert.mode_definitions import MANUAL_UPDATE_MODE
23
+ from ert.mode_definitions import MANUAL_ENIF_UPDATE_MODE, MANUAL_UPDATE_MODE
24
24
  from ert.run_models.manual_update import ManualUpdate
25
25
  from ert.storage import Ensemble, RealizationStorageState
26
26
  from ert.validation import EnsembleRealizationsArgument, ProperNameFormatArgument
@@ -38,6 +38,8 @@ class Arguments:
38
38
 
39
39
 
40
40
  class ManualUpdatePanel(ExperimentConfigPanel):
41
+ updateMethodChanged = pyqtSignal(str)
42
+
41
43
  def __init__(
42
44
  self,
43
45
  run_path: str,
@@ -49,9 +51,17 @@ class ManualUpdatePanel(ExperimentConfigPanel):
49
51
  self.setObjectName("Manual_update_panel")
50
52
 
51
53
  layout = QFormLayout()
52
- lab = QLabel(ManualUpdate.name())
53
- lab.setAlignment(Qt.AlignmentFlag.AlignLeft)
54
- layout.addRow(lab)
54
+ self._update_method_dropdown = QComboBox()
55
+ self._update_method_dropdown.addItems(
56
+ ["ES Update", "EnIF Update (Experimental)"]
57
+ )
58
+ self._update_method_dropdown.currentTextChanged.connect(
59
+ self._on_update_method_changed
60
+ )
61
+ self._update_method_dropdown.setObjectName("manual_update_method_dropdown")
62
+
63
+ layout.addRow("Update method:", self._update_method_dropdown)
64
+
55
65
  self._ensemble_selector = EnsembleSelector(
56
66
  notifier, show_only_with_response_data=True
57
67
  )
@@ -97,6 +107,17 @@ class ManualUpdatePanel(ExperimentConfigPanel):
97
107
  self._ensemble_selector.currentIndexChanged.connect(self._realizations_from_fs)
98
108
  self.setLayout(layout)
99
109
 
110
+ @property
111
+ def selected_update_method(self) -> str:
112
+ return self._update_method_dropdown.currentText()
113
+
114
+ @Slot(str)
115
+ def _on_update_method_changed(self, new_method: str) -> None:
116
+ if new_method == "ES Update":
117
+ self._analysis_module_edit.show()
118
+ else:
119
+ self._analysis_module_edit.hide()
120
+
100
121
  @override
101
122
  def isConfigurationValid(self) -> bool:
102
123
  return (
@@ -107,7 +128,9 @@ class ManualUpdatePanel(ExperimentConfigPanel):
107
128
  @override
108
129
  def get_experiment_arguments(self) -> Arguments:
109
130
  return Arguments(
110
- mode=MANUAL_UPDATE_MODE,
131
+ mode=MANUAL_UPDATE_MODE
132
+ if self.selected_update_method == "ES Update"
133
+ else MANUAL_ENIF_UPDATE_MODE,
111
134
  ensemble_id=str(
112
135
  cast(Ensemble, self._ensemble_selector.selected_ensemble).id
113
136
  ),
@@ -18,14 +18,14 @@ from ert.gui.ertwidgets import (
18
18
  CopyableLabel,
19
19
  EnsembleSelector,
20
20
  StringBox,
21
+ Suggestor,
21
22
  TargetEnsembleModel,
22
23
  TextModel,
23
24
  ValueModel,
25
+ get_parameters_button,
24
26
  )
25
- from ert.gui.ertwidgets.parameterviewer import get_parameters_button
26
- from ert.gui.suggestor import Suggestor
27
27
  from ert.mode_definitions import ES_MDA_MODE
28
- from ert.run_models import MultipleDataAssimilation
28
+ from ert.run_models import MultipleDataAssimilation, MultipleDataAssimilationConfig
29
29
  from ert.storage.realization_storage_state import RealizationStorageState
30
30
  from ert.validation import (
31
31
  ExperimentValidation,
@@ -114,7 +114,7 @@ class MultipleDataAssimilationPanel(ExperimentConfigPanel):
114
114
  self._target_ensemble_format_field.setValidator(ProperNameFormatArgument())
115
115
  layout.addRow("Target ensemble format:", self._target_ensemble_format_field)
116
116
 
117
- self.weights = MultipleDataAssimilation.default_weights
117
+ self.weights = MultipleDataAssimilationConfig.default_weights
118
118
  self.weights_valid = True
119
119
  self._createInputForWeights(layout)
120
120
 
@@ -135,6 +135,8 @@ class MultipleDataAssimilationPanel(ExperimentConfigPanel):
135
135
  self._active_realizations_field.model.setValueFromMask( # type: ignore
136
136
  active_realizations
137
137
  )
138
+ self._initial_active_realizations = active_realizations
139
+
138
140
  self._ensemble_selector = EnsembleSelector(notifier)
139
141
  self._previous_ensemble_realizations_validator = EnsembleRealizationsArgument(
140
142
  lambda: self._ensemble_selector.selected_ensemble,
@@ -215,7 +217,7 @@ class MultipleDataAssimilationPanel(ExperimentConfigPanel):
215
217
 
216
218
  self._relative_iteration_weights_box.setText(
217
219
  self._ensemble_selector.selected_ensemble.relative_weights
218
- or MultipleDataAssimilation.default_weights
220
+ or MultipleDataAssimilationConfig.default_weights
219
221
  )
220
222
  self._evaluate_weights_box_enabled()
221
223
 
@@ -250,9 +252,9 @@ class MultipleDataAssimilationPanel(ExperimentConfigPanel):
250
252
  self._ensemble_selector.selected_ensemble is not None
251
253
  and self._ensemble_selector.selected_ensemble.relative_weights
252
254
  )
253
- or MultipleDataAssimilation.default_weights
255
+ or MultipleDataAssimilationConfig.default_weights
254
256
  if self._restart_box.isChecked()
255
- else MultipleDataAssimilation.default_weights
257
+ else MultipleDataAssimilationConfig.default_weights
256
258
  )
257
259
  if self._restart_box.isChecked():
258
260
  self._active_realizations_field.setValidator(
@@ -264,7 +266,9 @@ class MultipleDataAssimilationPanel(ExperimentConfigPanel):
264
266
  self._active_realizations_field.setValidator(
265
267
  self._new_ensemble_realizations_validator
266
268
  )
267
- self._active_realizations_field.model.setValue(value="")
269
+ self._active_realizations_field.model.setValueFromMask( # type: ignore
270
+ self._initial_active_realizations
271
+ )
268
272
 
269
273
  def _createInputForWeights(self, layout: QFormLayout) -> None:
270
274
  relative_iteration_weights_model = ValueModel(self.weights)
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import logging
4
+ from datetime import datetime
4
5
  from pathlib import Path
5
6
  from queue import SimpleQueue
6
7
  from typing import assert_never, cast
@@ -30,15 +31,18 @@ from PyQt6.QtWidgets import (
30
31
  )
31
32
  from typing_extensions import override
32
33
 
34
+ from _ert.events import EnsembleEvaluationWarning
33
35
  from ert.config import ErrorInfo, QueueSystem, WarningInfo
34
36
  from ert.ensemble_evaluator import (
35
37
  EndEvent,
36
38
  FullSnapshotEvent,
37
39
  SnapshotUpdateEvent,
40
+ StartEvent,
38
41
  WarningEvent,
39
42
  )
40
43
  from ert.ensemble_evaluator import identifiers as ids
41
44
  from ert.gui.ertnotifier import ErtNotifier
45
+ from ert.gui.ertwidgets import Suggestor
42
46
  from ert.gui.model.fm_step_list import FMStepListProxyModel
43
47
  from ert.gui.model.node import IterNode
44
48
  from ert.gui.model.real_list import RealListModel
@@ -49,7 +53,6 @@ from ert.gui.model.snapshot import (
49
53
  RealIens,
50
54
  SnapshotModel,
51
55
  )
52
- from ert.gui.suggestor import Suggestor
53
56
  from ert.gui.tools.file import FileDialog
54
57
  from ert.run_models import (
55
58
  RunModelAPI,
@@ -258,6 +261,7 @@ class RunDialog(QFrame):
258
261
  self._fm_step_label.setObjectName("fm_step_label")
259
262
  self._fm_step_overview = FMStepOverview(self._snapshot_model, self)
260
263
 
264
+ self._start_time: datetime | None = None
261
265
  self.running_time = QLabel("Running time:\n -")
262
266
  self.running_time.setMinimumWidth(150)
263
267
  self.queue_system = QLabel("")
@@ -524,9 +528,11 @@ class RunDialog(QFrame):
524
528
 
525
529
  @Slot()
526
530
  def _on_ticker(self) -> None:
527
- runtime = self._run_model_api.get_runtime()
528
- running_time = f"Running time: {humanize.precisedelta(runtime)}"
529
- self.running_time.setText(running_time[0:14] + "\n" + running_time[14:])
531
+ if self._start_time:
532
+ humanized_runtime = humanize.precisedelta(
533
+ datetime.now() - self._start_time, minimum_unit="seconds", format="%d"
534
+ )
535
+ self.running_time.setText(f"Running time:\n{humanized_runtime}")
530
536
 
531
537
  maximum_memory_usage = self._snapshot_model.root.max_memory_usage
532
538
 
@@ -543,11 +549,16 @@ class RunDialog(QFrame):
543
549
  def _on_event(self, event: object) -> None:
544
550
  model = self._snapshot_model
545
551
  match event:
552
+ case StartEvent():
553
+ self._start_time = event.timestamp
546
554
  case EndEvent(failed=failed, msg=msg):
547
555
  self.simulation_done.emit(failed, msg)
548
556
  self._ticker.stop()
549
557
  case WarningEvent(msg=msg):
550
558
  self.post_simulation_warnings.append(msg)
559
+ case EnsembleEvaluationWarning(warning_message=msg):
560
+ self._show_warning(msg)
561
+
551
562
  case FullSnapshotEvent(
552
563
  status_count=status_count, realization_count=realization_count
553
564
  ):
@@ -650,6 +661,7 @@ class RunDialog(QFrame):
650
661
  if result == QMessageBox.StandardButton.Ok:
651
662
  self.rerun_button.setEnabled(False)
652
663
  self.kill_button.setEnabled(True)
664
+ self.post_simulation_warnings.clear()
653
665
  self._is_rerunning_failed_realizations = True
654
666
  self.rerun_failed_realizations_experiment.emit()
655
667
  self.set_show_warning_button_to_initial_state()
@@ -673,6 +685,15 @@ class RunDialog(QFrame):
673
685
  for file_dialog in self.findChildren(FileDialog):
674
686
  file_dialog.close()
675
687
 
688
+ def _show_warning(self, msg: str) -> None:
689
+ msg_box = QMessageBox(self)
690
+ msg_box.setObjectName("EnsembleEvaluationWarningBox")
691
+ msg_box.setIcon(QMessageBox.Icon.Warning)
692
+ msg_box.setWindowTitle("Ensemble Evaluation Warning")
693
+ msg_box.setText(msg)
694
+ msg_box.setStandardButtons(QMessageBox.StandardButton.Ok)
695
+ msg_box.show()
696
+
676
697
 
677
698
  # Cannot use a non-static method here as
678
699
  # it is called when the object is destroyed
@@ -4,13 +4,13 @@ from PyQt6.QtCore import Qt
4
4
  from PyQt6.QtWidgets import QFormLayout, QLabel
5
5
  from typing_extensions import override
6
6
 
7
+ from ert.config import AnalysisConfig, ParameterConfig
7
8
  from ert.gui.ertnotifier import ErtNotifier
8
9
  from ert.gui.ertwidgets import CopyableLabel
9
10
  from ert.mode_definitions import TEST_RUN_MODE
10
11
  from ert.run_models import SingleTestRun
11
12
 
12
- from ...config import AnalysisConfig, ParameterConfig
13
- from ..ertwidgets.parameterviewer import get_parameters_button
13
+ from ..ertwidgets import get_parameters_button
14
14
  from ._design_matrix_panel import DesignMatrixPanel
15
15
  from .experiment_config_panel import ExperimentConfigPanel
16
16
 
ert/gui/summarypanel.py CHANGED
@@ -13,7 +13,7 @@ from PyQt6.QtWidgets import (
13
13
  QWidget,
14
14
  )
15
15
 
16
- from ert.gui.ertwidgets.models.ertsummary import ErtSummary
16
+ from ert.gui.ertwidgets import ErtSummary
17
17
 
18
18
  if TYPE_CHECKING:
19
19
  from ert.config import ErtConfig
@@ -13,10 +13,10 @@ from ert.gui.ertwidgets import (
13
13
  EnsembleSelector,
14
14
  QApplication,
15
15
  StringBox,
16
+ Suggestor,
16
17
  TextBox,
17
18
  TextModel,
18
19
  )
19
- from ert.gui.suggestor import Suggestor
20
20
  from ert.run_models.run_model import captured_logs
21
21
  from ert.storage.local_ensemble import load_parameters_and_responses_from_runpath
22
22
  from ert.validation import RangeStringArgument, StringDefinition
@@ -189,9 +189,9 @@ class _EnsembleWidget(QWidget):
189
189
 
190
190
  response_type, obs_for_type = next(
191
191
  (
192
- (response_type, _df)
193
- for response_type, _df in observations_dict.items()
194
- if observation_key in _df["observation_key"]
192
+ (response_type, df)
193
+ for response_type, df in observations_dict.items()
194
+ if observation_key in df["observation_key"]
195
195
  ),
196
196
  (None, None),
197
197
  )
@@ -418,14 +418,14 @@ class _RealizationWidget(QWidget):
418
418
  )
419
419
 
420
420
  html = "<table>"
421
- for name, _response_state in ensemble.get_response_state(realization).items():
422
- html += f"<tr><td>{name} - {_response_state.name}</td></tr>"
421
+ for name, response_state in ensemble.get_response_state(realization).items():
422
+ html += f"<tr><td>{name} - {response_state.name}</td></tr>"
423
423
  html += "</table>"
424
424
  self._response_text_edit.setHtml(html)
425
425
 
426
426
  html = "<table>"
427
- for name, _param_state in ensemble.get_parameter_state(realization).items():
428
- html += f"<tr><td>{name} - {_param_state.name}</td></tr>"
427
+ for name, param_state in ensemble.get_parameter_state(realization).items():
428
+ html += f"<tr><td>{name} - {param_state.name}</td></tr>"
429
429
  html += "</table>"
430
430
  self._parameter_text_edit.setHtml(html)
431
431
 
@@ -24,8 +24,7 @@ from PyQt6.QtWidgets import (
24
24
 
25
25
  from ert.config import ErrorInfo, ErtConfig
26
26
  from ert.gui.ertnotifier import ErtNotifier
27
- from ert.gui.ertwidgets.create_experiment_dialog import CreateExperimentDialog
28
- from ert.gui.suggestor import Suggestor
27
+ from ert.gui.ertwidgets import CreateExperimentDialog, Suggestor
29
28
  from ert.storage import Ensemble, Experiment
30
29
 
31
30
  from .storage_model import (
@@ -19,7 +19,7 @@ from pandas.errors import ParserError
19
19
  from resfo_utilities import history_key
20
20
 
21
21
  from ert.config import ParameterMetadata, ResponseMetadata
22
- from ert.services import StorageService
22
+ from ert.services import ErtServer
23
23
  from ert.storage.realization_storage_state import RealizationStorageState
24
24
 
25
25
  logger = logging.getLogger(__name__)
@@ -56,7 +56,7 @@ class PlotApi:
56
56
 
57
57
  @property
58
58
  def api_version(self) -> str:
59
- with StorageService.session(project=self.ens_path) as client:
59
+ with ErtServer.session(project=self.ens_path) as client:
60
60
  try:
61
61
  response = client.get("/version", timeout=self._timeout)
62
62
  self._check_response(response)
@@ -82,7 +82,7 @@ class PlotApi:
82
82
  return self._all_ensembles
83
83
 
84
84
  self._all_ensembles = []
85
- with StorageService.session(project=self.ens_path) as client:
85
+ with ErtServer.session(project=self.ens_path) as client:
86
86
  try:
87
87
  response = client.get("/experiments", timeout=self._timeout)
88
88
  self._check_response(response)
@@ -138,7 +138,7 @@ class PlotApi:
138
138
  all_keys: dict[str, PlotApiKeyDefinition] = {}
139
139
  all_params = {}
140
140
 
141
- with StorageService.session(project=self.ens_path) as client:
141
+ with ErtServer.session(project=self.ens_path) as client:
142
142
  response = client.get("/experiments", timeout=self._timeout)
143
143
  self._check_response(response)
144
144
 
@@ -162,7 +162,7 @@ class PlotApi:
162
162
  def responses_api_key_defs(self) -> list[PlotApiKeyDefinition]:
163
163
  key_defs: dict[str, PlotApiKeyDefinition] = {}
164
164
 
165
- with StorageService.session(project=self.ens_path) as client:
165
+ with ErtServer.session(project=self.ens_path) as client:
166
166
  response = client.get("/experiments", timeout=self._timeout)
167
167
  self._check_response(response)
168
168
 
@@ -224,7 +224,7 @@ class PlotApi:
224
224
  response_key: str,
225
225
  filter_on: dict[str, Any] | None = None,
226
226
  ) -> pd.DataFrame:
227
- with StorageService.session(project=self.ens_path) as client:
227
+ with ErtServer.session(project=self.ens_path) as client:
228
228
  response = client.get(
229
229
  f"/ensembles/{ensemble_id}/responses/{PlotApi.escape(response_key)}",
230
230
  headers={"accept": "application/x-parquet"},
@@ -241,7 +241,10 @@ class PlotApi:
241
241
  try:
242
242
  df.columns = pd.to_datetime(df.columns, format="%Y-%m-%d %H:%M:%S")
243
243
  except (ParserError, ValueError):
244
- df.columns = [int(s) for s in df.columns]
244
+ try:
245
+ df.columns = [int(s) for s in df.columns]
246
+ except ValueError:
247
+ df.columns = [float(s) for s in df.columns]
245
248
 
246
249
  try:
247
250
  return df.astype(float)
@@ -249,7 +252,7 @@ class PlotApi:
249
252
  return df
250
253
 
251
254
  def data_for_parameter(self, ensemble_id: str, parameter_key: str) -> pd.DataFrame:
252
- with StorageService.session(project=self.ens_path) as client:
255
+ with ErtServer.session(project=self.ens_path) as client:
253
256
  parameter = client.get(
254
257
  f"/ensembles/{ensemble_id}/parameters/{PlotApi.escape(parameter_key)}",
255
258
  headers={"accept": "application/x-parquet"},
@@ -291,7 +294,7 @@ class PlotApi:
291
294
  assert key_def.response_metadata is not None
292
295
  actual_response_key = key_def.response_metadata.response_key
293
296
  filter_on = key_def.filter_on
294
- with StorageService.session(project=self.ens_path) as client:
297
+ with ErtServer.session(project=self.ens_path) as client:
295
298
  response = client.get(
296
299
  f"/ensembles/{ensemble.id}/responses/{PlotApi.escape(actual_response_key)}/observations",
297
300
  timeout=self._timeout,
@@ -374,7 +377,7 @@ class PlotApi:
374
377
  if not ensemble:
375
378
  return np.array([])
376
379
 
377
- with StorageService.session(project=self.ens_path) as client:
380
+ with ErtServer.session(project=self.ens_path) as client:
378
381
  response = client.get(
379
382
  f"/ensembles/{ensemble.id}/parameters/{PlotApi.escape(key)}/std_dev",
380
383
  params={"z": z},
@@ -335,6 +335,18 @@ class PlotWindow(QMainWindow):
335
335
  handle_exception(e)
336
336
  plot_context.history_data = None
337
337
 
338
+ if (
339
+ key_def.response_metadata is not None
340
+ and key_def.response_metadata.response_type == "rft"
341
+ ):
342
+ plot_context.setXLabel(key.split(":")[-1])
343
+ plot_context.setYLabel("TVD")
344
+ plot_context.depth_y_axis = True
345
+ for ekey, data in list(ensemble_to_data_map.items()):
346
+ ensemble_to_data_map[ekey] = data.interpolate(
347
+ method="linear", axis="columns"
348
+ )
349
+
338
350
  for data in ensemble_to_data_map.values():
339
351
  data = data.T
340
352
 
@@ -88,6 +88,8 @@ class PlotConfig:
88
88
 
89
89
  self._std_dev_factor = 1 # sigma 1 is default std dev
90
90
 
91
+ self.depth_y_axis = False
92
+
91
93
  def getNumberOfColors(self) -> int:
92
94
  return len(self._line_color_cycle_colors)
93
95
 
@@ -47,6 +47,14 @@ class PlotContext:
47
47
  self._y_axis: str | None = None
48
48
  self._log_scale = False
49
49
 
50
+ @property
51
+ def depth_y_axis(self) -> bool:
52
+ return self._plot_config.depth_y_axis
53
+
54
+ @depth_y_axis.setter
55
+ def depth_y_axis(self, value: bool) -> None:
56
+ self._plot_config.depth_y_axis = value
57
+
50
58
  def plotConfig(self) -> PlotConfig:
51
59
  return self._plot_config
52
60
 
@@ -93,6 +101,12 @@ class PlotContext:
93
101
  )
94
102
  self._y_axis = value
95
103
 
104
+ def setXLabel(self, value: str) -> None:
105
+ self._plot_config.setXLabel(value)
106
+
107
+ def setYLabel(self, value: str) -> None:
108
+ self._plot_config.setYLabel(value)
109
+
96
110
  @property
97
111
  def log_scale(self) -> bool:
98
112
  return self._log_scale
@@ -86,9 +86,16 @@ class EnsemblePlot:
86
86
  if len(data) == 1 and not style.marker:
87
87
  style.marker = "."
88
88
 
89
+ if plot_config.depth_y_axis:
90
+ x = data.to_numpy()
91
+ y = data.index.to_numpy()
92
+ axes.yaxis.set_inverted(True)
93
+ else:
94
+ y = data.to_numpy()
95
+ x = data.index.to_numpy()
89
96
  lines = axes.plot(
90
- data.index.to_numpy(),
91
- data.to_numpy(),
97
+ x,
98
+ y,
92
99
  color=style.color,
93
100
  alpha=style.alpha,
94
101
  marker=style.marker,
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING
3
+ from typing import TYPE_CHECKING, Any
4
4
 
5
5
  import numpy as np
6
6
  from matplotlib.lines import Line2D
@@ -126,10 +126,18 @@ def _plotPercentiles(
126
126
  axes: Axes, plot_config: PlotConfig, data: DataFrame, ensemble_label: str
127
127
  ) -> None:
128
128
  style = plot_config.getStatisticsStyle("mean")
129
+ if plot_config.depth_y_axis:
130
+ axes.yaxis.set_inverted(True)
131
+
132
+ def xy_order(x: Any, y: Any) -> tuple[Any, Any]:
133
+ if plot_config.depth_y_axis:
134
+ return (y, x)
135
+ else:
136
+ return (x, y)
137
+
129
138
  if style.isVisible():
130
139
  axes.plot(
131
- data.index.values,
132
- data["Mean"].values,
140
+ *xy_order(data.index.values, data["Mean"].values),
133
141
  alpha=style.alpha,
134
142
  linestyle=style.line_style,
135
143
  color=style.color,
@@ -141,8 +149,7 @@ def _plotPercentiles(
141
149
  style = plot_config.getStatisticsStyle("p50")
142
150
  if style.isVisible():
143
151
  axes.plot(
144
- data.index.values,
145
- data["p50"].values,
152
+ *xy_order(data.index.values, data["p50"].values),
146
153
  alpha=style.alpha,
147
154
  linestyle=style.line_style,
148
155
  color=style.color,
@@ -153,7 +160,13 @@ def _plotPercentiles(
153
160
 
154
161
  style = plot_config.getStatisticsStyle("std")
155
162
  _plotPercentile(
156
- axes, style, data.index.values, data["std+"].values, data["std-"].values, 0.5
163
+ axes,
164
+ style,
165
+ data.index.values,
166
+ data["std+"].values,
167
+ data["std-"].values,
168
+ 0.5,
169
+ plot_config.depth_y_axis,
157
170
  )
158
171
 
159
172
  style = plot_config.getStatisticsStyle("min-max")
@@ -164,16 +177,29 @@ def _plotPercentiles(
164
177
  data["Maximum"].values,
165
178
  data["Minimum"].values,
166
179
  0.5,
180
+ plot_config.depth_y_axis,
167
181
  )
168
182
 
169
183
  style = plot_config.getStatisticsStyle("p10-p90")
170
184
  _plotPercentile(
171
- axes, style, data.index.values, data["p90"].values, data["p10"].values, 0.5
185
+ axes,
186
+ style,
187
+ data.index.values,
188
+ data["p90"].values,
189
+ data["p10"].values,
190
+ 0.5,
191
+ plot_config.depth_y_axis,
172
192
  )
173
193
 
174
194
  style = plot_config.getStatisticsStyle("p33-p67")
175
195
  _plotPercentile(
176
- axes, style, data.index.values, data["p67"].values, data["p33"].values, 0.5
196
+ axes,
197
+ style,
198
+ data.index.values,
199
+ data["p67"].values,
200
+ data["p33"].values,
201
+ 0.5,
202
+ plot_config.depth_y_axis,
177
203
  )
178
204
 
179
205
 
@@ -184,24 +210,39 @@ def _plotPercentile(
184
210
  top_line_data: npt.ArrayLike,
185
211
  bottom_line_data: npt.ArrayLike,
186
212
  alpha_multiplier: float,
213
+ inverted: bool = False,
187
214
  ) -> None:
188
215
  alpha = style.alpha
189
216
  line_style = style.line_style
190
217
  color = style.color
191
218
  marker = style.marker
192
219
 
220
+ def xy_order(x: Any, y: Any) -> tuple[Any, Any]:
221
+ if inverted:
222
+ return (y, x)
223
+ else:
224
+ return (x, y)
225
+
193
226
  if line_style == "#":
194
- axes.fill_between(
195
- index_values,
196
- bottom_line_data,
197
- top_line_data,
198
- alpha=alpha * alpha_multiplier,
199
- color=color,
200
- )
227
+ if inverted:
228
+ axes.fill_betweenx(
229
+ index_values,
230
+ bottom_line_data,
231
+ top_line_data,
232
+ alpha=alpha * alpha_multiplier,
233
+ color=color,
234
+ )
235
+ else:
236
+ axes.fill_between(
237
+ index_values,
238
+ bottom_line_data,
239
+ top_line_data,
240
+ alpha=alpha * alpha_multiplier,
241
+ color=color,
242
+ )
201
243
  elif style.isVisible():
202
244
  axes.plot(
203
- index_values,
204
- bottom_line_data,
245
+ *xy_order(index_values, bottom_line_data),
205
246
  alpha=alpha,
206
247
  linestyle=line_style,
207
248
  color=color,
@@ -210,8 +251,7 @@ def _plotPercentile(
210
251
  markersize=style.size,
211
252
  )
212
253
  axes.plot(
213
- index_values,
214
- top_line_data,
254
+ *xy_order(index_values, top_line_data),
215
255
  alpha=alpha,
216
256
  linestyle=line_style,
217
257
  color=color,
ert/mode_definitions.py CHANGED
@@ -6,6 +6,7 @@ TEST_RUN_MODE = "test_run"
6
6
  WORKFLOW_MODE = "workflow"
7
7
  EVALUATE_ENSEMBLE_MODE = "evaluate_ensemble"
8
8
  MANUAL_UPDATE_MODE = "manual_update"
9
+ MANUAL_ENIF_UPDATE_MODE = "manual_enif_update"
9
10
 
10
11
  MODULE_MODE = {
11
12
  "EnsembleInformationFilter": ENIF_MODE,
@@ -15,4 +16,5 @@ MODULE_MODE = {
15
16
  "SingleTestRun": TEST_RUN_MODE,
16
17
  "EvaluateEnsemble": EVALUATE_ENSEMBLE_MODE,
17
18
  "ManualUpdate": MANUAL_UPDATE_MODE,
19
+ "ManualEnIFUpdate": MANUAL_ENIF_UPDATE_MODE,
18
20
  }
ert/plugins/__init__.py CHANGED
@@ -25,7 +25,6 @@ def plugin(name: str) -> Callable[[Callable[P, Any]], Callable[P, Any]]:
25
25
  if (
26
26
  func.__name__
27
27
  in {
28
- "installable_jobs",
29
28
  "job_documentation",
30
29
  "installable_workflow_jobs",
31
30
  "help_links",