Skip to content

Commit da8bdf9

Browse files
committed
Add misfit plot for breakthrough responses
Add snapshot test for breakthrough misfit plotter
1 parent cb1e7fa commit da8bdf9

6 files changed

Lines changed: 120 additions & 88 deletions

File tree

src/ert/dark_storage/endpoints/responses.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ def data_for_response(
207207
return pd.DataFrame()
208208

209209
match response_type:
210-
case "summary":
210+
case "summary" | "breakthrough":
211211
summary_data = ensemble.load_responses(
212212
response_key,
213213
tuple(realizations_with_responses),
@@ -222,8 +222,15 @@ def data_for_response(
222222
# This performs the same aggragation by mean of duplicate values
223223
# as in ert/analysis/_es_update.py
224224
df = df.groupby(["Date", "Realization"]).mean()
225+
summary_value_col = 0
226+
breakthrough_value_col = 1
227+
value_column = (
228+
summary_value_col
229+
if response_type == "summary"
230+
else breakthrough_value_col
231+
)
225232
data = df.reset_index().pivot_table(
226-
index="Realization", columns="Date", values=df.columns[0]
233+
index="Realization", columns="Date", values=df.columns[value_column]
227234
)
228235
return data.astype(float)
229236
case "rft":

src/ert/gui/tools/plot/plot_window.py

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -304,19 +304,17 @@ def updatePlot(self, layer: int | None = None) -> None:
304304
return
305305
key = key_def.key
306306

307-
# Plot the response of corresponding summary key instead of breakthrough key
308-
if isinstance(key_def.response, BreakthroughConfig):
309-
key = next(
310-
(
311-
summary_key
312-
for summary_key in key_def.response.summary_keys
313-
if f"BREAKTHROUGH:{summary_key}" == key
314-
),
315-
key,
316-
)
317-
318307
plot_widget = cast(PlotWidget, self._central_tab.currentWidget())
319308

309+
# For Breakthrough responses, we want to plot summary_key timeseries, but use
310+
# derived breakthrough responses for misfits.
311+
selected_tab = plot_widget.name
312+
if (
313+
isinstance(key_def.response, BreakthroughConfig)
314+
and selected_tab != "Misfits"
315+
):
316+
key = key.replace("BREAKTHROUGH:", "")
317+
320318
is_gradient_plot = plot_widget.name == EVEREST_GRADIENTS_PLOT
321319
self._everest_dock.setVisible(is_gradient_plot)
322320

src/ert/gui/tools/plot/plottery/plots/misfits.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def _wide_pandas_to_long_polars_with_misfits(
9898
observation_data: pd.DataFrame,
9999
response_type: Literal["summary", "gen_data"],
100100
) -> dict[tuple[str, str], pl.DataFrame]:
101-
if response_type == "summary":
101+
if response_type in {"summary", "breakthrough"}:
102102
key_index_with_correct_dtype = pl.col("key_index").str.to_datetime(
103103
strict=False
104104
)
@@ -157,7 +157,7 @@ def plot(
157157
response_type,
158158
)
159159

160-
if response_type == "summary":
160+
if response_type in {"summary", "breakthrough"}:
161161
self._plot_summary_misfits_boxplots(
162162
figure,
163163
data_with_misfits,
18.7 KB
Loading
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import pytest
2+
3+
from ert.gui.tools.plot.plot_window import MISFITS
4+
from tests.ert.ui_tests.gui.test_breakthrough_visualization import (
5+
create_breakthrough_figure,
6+
)
7+
8+
plot_figure = create_breakthrough_figure(MISFITS)
9+
10+
11+
@pytest.mark.mpl_image_compare(tolerance=10.0)
12+
@pytest.mark.skip_mac_ci
13+
@pytest.mark.snapshot_test
14+
@pytest.mark.filterwarnings("ignore:Config contains a SUMMARY key")
15+
def test_that_breakthrough_misfit_visualization_matches_snapshot(plot_figure):
16+
return plot_figure

tests/ert/ui_tests/gui/test_breakthrough_visualization.py

Lines changed: 84 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -61,80 +61,91 @@ def _mock_summary_response(realization: int) -> pl.DataFrame:
6161
)
6262

6363

64-
@pytest.fixture
65-
def plot_figure(use_tmpdir, qtbot: QtBot):
66-
config = _breakthrough_config()
67-
68-
def dump_all(configurations):
69-
return [c.model_dump(mode="json") for c in configurations]
70-
71-
with open_storage(config.ens_path, mode="w") as storage:
72-
experiment = storage.create_experiment(
73-
experiment_config={
74-
"parameter_configuration": dump_all(
75-
config.ensemble_config.parameter_configuration
76-
),
77-
"response_configuration": dump_all(
78-
config.ensemble_config.response_configuration
79-
),
80-
"derived_response_configuration": dump_all(
81-
config.ensemble_config.derived_response_configuration
82-
),
83-
"observations": dump_all(config.observation_declarations),
84-
"ert_templates": config.ert_templates,
85-
},
86-
name="breakthrough-experiment",
87-
)
88-
ensemble = experiment.create_ensemble(
89-
ensemble_size=config.runpath_config.num_realizations,
90-
name="prior",
91-
)
92-
93-
for realization in range(config.runpath_config.num_realizations):
94-
ensemble.save_response(
95-
"summary", _mock_summary_response(realization), realization
64+
def create_breakthrough_figure(plot_tab_name: str):
65+
@pytest.fixture
66+
def plot_figure(use_tmpdir, qtbot: QtBot):
67+
config = _breakthrough_config()
68+
69+
def dump_all(configurations):
70+
return [c.model_dump(mode="json") for c in configurations]
71+
72+
with open_storage(config.ens_path, mode="w") as storage:
73+
experiment = storage.create_experiment(
74+
experiment_config={
75+
"parameter_configuration": dump_all(
76+
config.ensemble_config.parameter_configuration
77+
),
78+
"response_configuration": dump_all(
79+
config.ensemble_config.response_configuration
80+
),
81+
"derived_response_configuration": dump_all(
82+
config.ensemble_config.derived_response_configuration
83+
),
84+
"observations": dump_all(config.observation_declarations),
85+
"ert_templates": config.ert_templates,
86+
},
87+
name="breakthrough-experiment",
9688
)
97-
breakthrough_response = experiment.derived_response_configuration[
98-
"breakthrough"
99-
].derive_from_storage(0, realization, ensemble)
100-
ensemble.save_response("breakthrough", breakthrough_response, realization)
101-
102-
open_storage(config.ens_path, mode="r")
103-
104-
with ErtServerController.init_service(
105-
project=config.ens_path,
106-
):
107-
args_mock = Mock()
108-
args_mock.config = "breakthrough.ert"
109-
gui = _setup_main_window(config, args_mock, Mock(), config.ens_path)
110-
qtbot.addWidget(gui)
111-
112-
button_plot_tool = get_child(gui, QToolButton, name="button_Create_plot")
113-
114-
qtbot.mouseClick(button_plot_tool, Qt.MouseButton.LeftButton)
115-
plot_window = get_child(gui, PlotWindow)
116-
central_tab = plot_window._central_tab
117-
118-
data_types = get_child(plot_window, DataTypeKeysWidget)
119-
key_list = data_types.data_type_keys_widget
120-
key_model = key_list.model()
121-
122-
for key_index in range(key_model.rowCount()):
123-
to_select = data_types.model.itemAt(data_types.model.index(key_index, 0))
124-
assert to_select is not None
125-
if to_select.key == "BREAKTHROUGH:WWCT:OP1":
126-
key_list.setCurrentIndex(key_model.index(key_index, 0))
127-
selected_key = to_select
128-
for tab_index, tab in enumerate(plot_window._plot_widgets):
129-
if tab.name == ENSEMBLE:
130-
assert central_tab.isTabEnabled(tab_index)
131-
central_tab.setCurrentWidget(tab)
132-
assert (
133-
selected_key.dimensionality == tab._plotter.dimensionality
134-
)
135-
yield tab._figure.figure
136-
137-
plot_window.close()
89+
ensemble = experiment.create_ensemble(
90+
ensemble_size=config.runpath_config.num_realizations,
91+
name="prior",
92+
)
93+
94+
for realization in range(config.runpath_config.num_realizations):
95+
ensemble.save_response(
96+
"summary", _mock_summary_response(realization), realization
97+
)
98+
breakthrough_response = experiment.derived_response_configuration[
99+
"breakthrough"
100+
].derive_from_storage(0, realization, ensemble)
101+
ensemble.save_response(
102+
"breakthrough", breakthrough_response, realization
103+
)
104+
105+
open_storage(config.ens_path, mode="r")
106+
107+
with ErtServerController.init_service(
108+
project=config.ens_path,
109+
):
110+
args_mock = Mock()
111+
args_mock.config = "breakthrough.ert"
112+
gui = _setup_main_window(config, args_mock, Mock(), config.ens_path)
113+
qtbot.addWidget(gui)
114+
115+
button_plot_tool = get_child(gui, QToolButton, name="button_Create_plot")
116+
117+
qtbot.mouseClick(button_plot_tool, Qt.MouseButton.LeftButton)
118+
plot_window = get_child(gui, PlotWindow)
119+
central_tab = plot_window._central_tab
120+
121+
data_types = get_child(plot_window, DataTypeKeysWidget)
122+
key_list = data_types.data_type_keys_widget
123+
key_model = key_list.model()
124+
125+
for key_index in range(key_model.rowCount()):
126+
to_select = data_types.model.itemAt(
127+
data_types.model.index(key_index, 0)
128+
)
129+
assert to_select is not None
130+
if to_select.key == "BREAKTHROUGH:WWCT:OP1":
131+
key_list.setCurrentIndex(key_model.index(key_index, 0))
132+
selected_key = to_select
133+
for tab_index, tab in enumerate(plot_window._plot_widgets):
134+
if tab.name == plot_tab_name:
135+
assert central_tab.isTabEnabled(tab_index)
136+
central_tab.setCurrentWidget(tab)
137+
assert (
138+
selected_key.dimensionality
139+
== tab._plotter.dimensionality
140+
)
141+
yield tab._figure.figure
142+
143+
plot_window.close()
144+
145+
return plot_figure
146+
147+
148+
plot_figure = create_breakthrough_figure(ENSEMBLE)
138149

139150

140151
@pytest.mark.mpl_image_compare(tolerance=10.0)

0 commit comments

Comments
 (0)