Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add design matrix panel for parameters preview #8910

Merged
merged 1 commit into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 45 additions & 6 deletions src/ert/gui/simulation/ensemble_experiment_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,21 @@

from qtpy import QtCore
from qtpy.QtCore import Slot
from qtpy.QtWidgets import QFormLayout, QLabel
from qtpy.QtWidgets import QFormLayout, QHBoxLayout, QLabel, QPushButton

from ert.config import AnalysisConfig, DesignMatrix
from ert.gui.ertnotifier import ErtNotifier
from ert.gui.ertwidgets import (
ActiveRealizationsModel,
CopyableLabel,
StringBox,
TextModel,
)
from ert.gui.tools.design_matrix.design_matrix_panel import DesignMatrixPanel
from ert.mode_definitions import ENSEMBLE_EXPERIMENT_MODE
from ert.run_models import EnsembleExperiment
from ert.validation import RangeStringArgument
from ert.validation.proper_name_argument import (
ExperimentValidation,
ProperNameArgument,
)
from ert.validation.proper_name_argument import ExperimentValidation, ProperNameArgument

from .experiment_config_panel import ExperimentConfigPanel

Expand All @@ -31,7 +30,13 @@ class Arguments:


class EnsembleExperimentPanel(ExperimentConfigPanel):
def __init__(self, ensemble_size: int, run_path: str, notifier: ErtNotifier):
def __init__(
self,
analysis_config: AnalysisConfig,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the entire analysisconfig, or only designmatrix?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question and I have thought about it and decided on using the entire config:

  • other panels get the entire analysisconfig too and thus it makes the api more uniform
  • when doing the validation ( not there yet), we might to access more of the configs

ensemble_size: int,
run_path: str,
notifier: ErtNotifier,
):
self.notifier = notifier
super().__init__(EnsembleExperiment)
self.setObjectName("Ensemble_experiment_panel")
Expand Down Expand Up @@ -78,6 +83,21 @@ def __init__(self, ensemble_size: int, run_path: str, notifier: ErtNotifier):
)
layout.addRow("Active realizations", self._active_realizations_field)

design_matrix = analysis_config.design_matrix
if design_matrix is not None:
show_dm_param_button = QPushButton("Show parameters")
show_dm_param_button.setObjectName("show-dm-parameters")
show_dm_param_button.setMinimumWidth(50)

button_layout = QHBoxLayout()
button_layout.addWidget(show_dm_param_button)
button_layout.addStretch() # Add stretch to push the button to the left

layout.addRow("Design Matrix", button_layout)
show_dm_param_button.clicked.connect(
lambda: self.on_show_dm_params_clicked(design_matrix)
)

self.setLayout(layout)

self._active_realizations_field.getValidationSupport().validationChanged.connect(
Expand All @@ -92,6 +112,25 @@ def __init__(self, ensemble_size: int, run_path: str, notifier: ErtNotifier):

self.notifier.ertChanged.connect(self._update_experiment_name_placeholder)

def on_show_dm_params_clicked(self, design_matrix: DesignMatrix) -> None:
assert design_matrix is not None

if design_matrix.design_matrix_df is None:
design_matrix.read_design_matrix()

if (
design_matrix.design_matrix_df is not None
and not design_matrix.design_matrix_df.empty
):
viewer = DesignMatrixPanel(
design_matrix.design_matrix_df,
design_matrix.xls_filename.name,
)
viewer.setMinimumHeight(500)
viewer.setMinimumWidth(1000)
viewer.adjustSize()
viewer.exec_()

@Slot(ExperimentConfigPanel)
def experimentTypeChanged(self, w: ExperimentConfigPanel) -> None:
if isinstance(w, EnsembleExperimentPanel):
Expand Down
5 changes: 3 additions & 2 deletions src/ert/gui/simulation/experiment_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,9 @@ def __init__(
SingleTestRunPanel(run_path, notifier),
True,
)
analysis_config = config.analysis_config
self.addExperimentConfigPanel(
EnsembleExperimentPanel(ensemble_size, run_path, notifier),
EnsembleExperimentPanel(analysis_config, ensemble_size, run_path, notifier),
True,
)
self.addExperimentConfigPanel(
Expand All @@ -154,7 +155,7 @@ def __init__(
experiment_type_valid = bool(
config.ensemble_config.parameter_configs and config.observations
)
analysis_config = config.analysis_config

self.addExperimentConfigPanel(
MultipleDataAssimilationPanel(
analysis_config, run_path, notifier, ensemble_size
Expand Down
50 changes: 50 additions & 0 deletions src/ert/gui/tools/design_matrix/design_matrix_panel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from typing import Optional

import pandas as pd
from qtpy.QtGui import QStandardItem, QStandardItemModel
from qtpy.QtWidgets import QDialog, QTableView, QVBoxLayout, QWidget


class DesignMatrixPanel(QDialog):
def __init__(
self,
design_matrix_df: pd.DataFrame,
filename: str,
parent: Optional[QWidget] = None,
) -> None:
super().__init__(parent)

self.setWindowTitle(f"Design matrix parameters from {filename}")

table_view = QTableView(self)
table_view.setEditTriggers(QTableView.NoEditTriggers)

self.model = self.create_model(design_matrix_df)
table_view.setModel(self.model)

table_view.resizeColumnsToContents()
table_view.resizeRowsToContents()

layout = QVBoxLayout()
layout.addWidget(table_view)
self.setLayout(layout)
self.adjustSize()

@staticmethod
def create_model(design_matrix_df: pd.DataFrame) -> QStandardItemModel:
model = QStandardItemModel()

if isinstance(design_matrix_df.columns, pd.MultiIndex):
header_labels = [str(col[-1]) for col in design_matrix_df.columns]
else:
header_labels = design_matrix_df.columns.astype(str).tolist()

model.setHorizontalHeaderLabels(header_labels)

for index, _ in design_matrix_df.iterrows():
items = [
QStandardItem(str(design_matrix_df.at[index, col]))
for col in design_matrix_df.columns
]
model.appendRow(items)
return model
45 changes: 45 additions & 0 deletions tests/ert/unit_tests/gui/simulation/test_run_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -708,3 +708,48 @@ def test_that_stdout_and_stderr_buttons_react_to_file_content(

with qtbot.waitSignal(run_dialog.accepted, timeout=30000):
run_dialog.close()


@pytest.mark.integration_test
@pytest.mark.usefixtures("use_tmpdir")
@pytest.mark.parametrize(
"design_matrix_entry",
(True, False),
)
def test_that_design_matrix_show_parameters_button_is_visible(
design_matrix_entry, qtbot: QtBot, storage
):
xls_filename = "design_matrix.xls"
with open(f"{xls_filename}", "w", encoding="utf-8"):
pass
config_file = "minimal_config.ert"
with open(config_file, "w", encoding="utf-8") as f:
f.write("NUM_REALIZATIONS 1")
if design_matrix_entry:
f.write(
f"\nDESIGN_MATRIX {xls_filename} DESIGN_SHEET:DesignSheet01 DEFAULT_SHEET:DefaultValues"
)

args_mock = Mock()
args_mock.config = config_file

ert_config = ErtConfig.from_file(config_file)
with StorageService.init_service(
project=os.path.abspath(ert_config.ens_path),
):
gui = _setup_main_window(ert_config, args_mock, GUILogHandler(), storage)
experiment_panel = gui.findChild(ExperimentPanel)
assert isinstance(experiment_panel, ExperimentPanel)

simulation_mode_combo = experiment_panel.findChild(QComboBox)
assert isinstance(simulation_mode_combo, QComboBox)

simulation_mode_combo.setCurrentText(EnsembleExperiment.name())
simulation_settings = gui.findChild(EnsembleExperimentPanel)
show_dm_parameters = simulation_settings.findChild(
QPushButton, "show-dm-parameters"
)
if design_matrix_entry:
assert isinstance(show_dm_parameters, QPushButton)
else:
assert show_dm_parameters is None