mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
MswRollUp: Updated Ert to experimental MSW branch. Updated ResInsight code to handle API changes
067fa99faa
This is an intermediate commit and does not compile
p4#: 22212
This commit is contained in:
@@ -1,208 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'gert_main.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
#--------------------------------------------------------------------------------
|
||||
# This file is the main script of the ert with graphical UI, e.g. gert or
|
||||
# ert_gui. To run successfully the ert GUI requires a quite well prepared
|
||||
# environment. This includes the following:
|
||||
#
|
||||
# 1. A Python interpreter with the the ctypes library available.
|
||||
#
|
||||
# 2. The program must be able to locate all the required shared libraries with
|
||||
# no fuss. This includes:
|
||||
#
|
||||
# o The ert libraries libecl.so, libenkf.so, libutil.so, librms.so,
|
||||
# libsched.so, libconfig.so
|
||||
#
|
||||
# o The libraries used by the ert libraries, this includes liblapack.so,
|
||||
# libz.so, libblas.so, libpthread.so and in some cases the libg2c.so
|
||||
# library.
|
||||
#
|
||||
# o The lsf libraries libbat, liblsf and also libnsl. In the current
|
||||
# implementation the dependance on the lsf libraries is hard, this should
|
||||
# be relaxed so that the lsf libraries are not linked before an attempt to
|
||||
# actually use lsf is made.
|
||||
# When an attempt is actually made to use LSF the additional environment
|
||||
# variables LSF_LIBDIR, XLSF_UIDDIR, LSF_SERVERDIR, LSF_ENVDIR and
|
||||
# LSF_BINDIR must also be set. That is an LSF requirement and not
|
||||
# related to ert as such. These variables can naturally be set from the
|
||||
# site config file.
|
||||
#
|
||||
#
|
||||
# 3. The program must be able to locate all the necessary Python modules, in
|
||||
# short this means that the directory containing the ert/ and ert_gui/
|
||||
# directories must be on Python path, i.e. the import statements
|
||||
#
|
||||
# import ert
|
||||
# import ert_gui
|
||||
#
|
||||
# should just work.
|
||||
#
|
||||
# 4. The environment variable GERT_SHARE_PATH should be set to point to the
|
||||
# /share directory of the current gert installation. The /share directory
|
||||
# contains html help files and images/icons.
|
||||
#
|
||||
# 5. The environment variable ERT_SITE_CONFIG must be set to point to the site
|
||||
# wide configuration file.
|
||||
#
|
||||
#
|
||||
# Now the important point is that this python script WILL NOT PERFORM ANY
|
||||
# SPECIAL HOOPS TO TRY TO LOCATE THE REQUIRED FILES, i.e. the environment must
|
||||
# be fully prepared prior to invoking this script. This will typically involve:
|
||||
#
|
||||
# 1. Update the LD_LIBRARY_PATH variable to contain directories with all the
|
||||
# required shared libraries.
|
||||
#
|
||||
# 2. Update the PYTHONPATH variable to contain the directory containg ert/ and
|
||||
# ert_gui/ directories.
|
||||
#
|
||||
# 3. Set the environment variabel GERT_SHARE_PATH to point to the directory
|
||||
# containg the /share files for the current gert installation.
|
||||
#
|
||||
# 4. Set the environment variable ERT_SITE_CONFIG to point to the location of
|
||||
# the site configuration file.
|
||||
#
|
||||
# An example shell script achieving this could look like:
|
||||
#
|
||||
#-------------------- <Example shell script> --------------------
|
||||
# #!/bin/bash
|
||||
#
|
||||
# # The LSF libraries are installed in directory /site/LSF/7.0/linux/lib, this
|
||||
# # directory must be included in the LD_LIBRARY_PATH variable. Furthermore we
|
||||
# # assume that the ERT libraries like libecl.so and libenkf.so are located in
|
||||
# # /opt/ert/lib, then LD_LIBRARY_PATH will be updated as:
|
||||
#
|
||||
# export LD_LIBRARY_PATH=/site/LSF/7.0/linux/lib:/opt/ert/lib:$LD_LIBRARY_PATH
|
||||
#
|
||||
# # The python modules ert and ert_gui are located in /opt/ert/python, so we
|
||||
# # update PYTHONPATH as:
|
||||
#
|
||||
# export PYTHONPATH=/opt/ert/python:$PYTHONPATH
|
||||
#
|
||||
# # The shared gert files are installed in /opt/ert/share; this directory can
|
||||
# # in principle be shared among gert versions built for different operating
|
||||
# # system versions:
|
||||
#
|
||||
# export GERT_SHARE_PATH=/opt/ert/share
|
||||
#
|
||||
# # The ERT site configuration file is assumed to be in
|
||||
# # /opt/ert/etc/site-config, i.e. we set the variable ERT_SITE_CONFIG as:
|
||||
#
|
||||
# export ERT_SITE_CONFIG=/opt/ert/etc/site-config
|
||||
#
|
||||
# # Now the environment should be fully initialized, and we are ready to invoke
|
||||
# # the gert_main.py script, i.e. this file:
|
||||
#
|
||||
# exec python /opt/ert/python/ert_gui/gert_main.py
|
||||
#
|
||||
#-------------------- </Example shell script> --------------------
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
import sys
|
||||
import os
|
||||
|
||||
from ert.ert.ertwrapper import ErtWrapper
|
||||
|
||||
import ert_gui.widgets.util
|
||||
import ert_gui.widgets.help
|
||||
ert_gui.widgets.help.help_prefix = os.getenv("GERT_SHARE_PATH")+ "/help/"
|
||||
ert_gui.widgets.util.img_prefix = os.getenv("GERT_SHARE_PATH")+ "/img/"
|
||||
|
||||
|
||||
|
||||
from ert_gui.newconfig import NewConfigurationDialog
|
||||
|
||||
app = QtGui.QApplication(sys.argv) #Early so that QT is initialized before other imports
|
||||
|
||||
from ert_gui.pages.application import Application
|
||||
from ert_gui.pages.init.initpanel import InitPanel
|
||||
from ert_gui.pages.run.runpanel import RunPanel
|
||||
from ert_gui.pages.config.configpages import ConfigPages
|
||||
from ert_gui.pages.plot.plotpanel import PlotPanel
|
||||
from ert_gui.widgets.helpedwidget import ContentModel
|
||||
from ert_gui.widgets.util import resourceImage, resourceIcon
|
||||
|
||||
import matplotlib
|
||||
print "PyQt4 version: ", QtCore.qVersion()
|
||||
print "matplotlib version: ", matplotlib.__version__
|
||||
|
||||
splash = QtGui.QSplashScreen(resourceImage("splash") , QtCore.Qt.WindowStaysOnTopHint)
|
||||
splash.show()
|
||||
splash.showMessage("Starting up...", color=QtCore.Qt.white)
|
||||
app.processEvents()
|
||||
|
||||
window = Application()
|
||||
|
||||
splash.showMessage("Bootstrapping...", color=QtCore.Qt.white)
|
||||
app.processEvents()
|
||||
|
||||
ert = ErtWrapper( )
|
||||
strict = True
|
||||
site_config = os.getenv("ERT_SITE_CONFIG")
|
||||
if len(sys.argv) == 1:
|
||||
print "-----------------------------------------------------------------"
|
||||
print "-- You must supply the name of configuration file as the first --"
|
||||
print "-- commandline argument: --"
|
||||
print "-- --"
|
||||
print "-- bash% gert <config_file> --"
|
||||
print "-- --"
|
||||
print "-- If the configuration file does not exist, gert will create --"
|
||||
print "-- create a new configuration file. --"
|
||||
print "-----------------------------------------------------------------"
|
||||
sys.exit( )
|
||||
|
||||
enkf_config = sys.argv[1]
|
||||
if not os.path.exists(enkf_config):
|
||||
print "Trying to start new config"
|
||||
new_configuration_dialog = NewConfigurationDialog(enkf_config)
|
||||
success = new_configuration_dialog.exec_()
|
||||
if not success:
|
||||
print "Can not run without a configuration file."
|
||||
sys.exit(1)
|
||||
else:
|
||||
enkf_config = new_configuration_dialog.getConfigurationPath()
|
||||
firste_case_name = new_configuration_dialog.getCaseName()
|
||||
dbase_type = new_configuration_dialog.getDBaseType()
|
||||
num_realizations = new_configuration_dialog.getNumberOfRealizations()
|
||||
storage_path = new_configuration_dialog.getStoragePath()
|
||||
ert.enkf.enkf_main_create_new_config(enkf_config, storage_path , firste_case_name, dbase_type, num_realizations)
|
||||
strict = False
|
||||
|
||||
ert.bootstrap(enkf_config, site_config = site_config, strict = strict)
|
||||
window.setSaveFunction(ert.save)
|
||||
|
||||
splash.showMessage("Creating GUI...", color=QtCore.Qt.white)
|
||||
app.processEvents()
|
||||
|
||||
#window.addPage("Configuration", resourceIcon("config"), ConfigPages(window))
|
||||
window.addPage("Init", resourceIcon("db"), InitPanel(window))
|
||||
window.addPage("Run", resourceIcon("run"), RunPanel(window))
|
||||
window.addPage("Plots", resourceIcon("plot"), PlotPanel())
|
||||
|
||||
splash.showMessage("Communicating with ERT...", color=QtCore.Qt.white)
|
||||
app.processEvents()
|
||||
|
||||
ContentModel.contentModel = ert
|
||||
ContentModel.updateObservers()
|
||||
|
||||
window.show()
|
||||
splash.finish(window)
|
||||
|
||||
sys.exit(app.exec_())
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'newconfig.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4.QtGui import QDialog, QFormLayout, QLabel, QDialogButtonBox, QComboBox, QCheckBox , QSpinBox , QLineEdit
|
||||
from PyQt4.QtCore import Qt, SIGNAL
|
||||
from widgets.util import createSpace
|
||||
import os
|
||||
|
||||
class NewConfigurationDialog(QDialog):
|
||||
"""A dialog for selecting defaults for a new configuration."""
|
||||
def __init__(self, configuration_path, parent = None):
|
||||
QDialog.__init__(self, parent)
|
||||
|
||||
self.setModal(True)
|
||||
self.setWindowTitle("New configuration file")
|
||||
self.setMinimumWidth(250)
|
||||
self.setMinimumHeight(150)
|
||||
|
||||
layout = QFormLayout()
|
||||
|
||||
directory, filename = os.path.split(configuration_path)
|
||||
|
||||
if directory.strip() == "":
|
||||
directory = os.path.abspath(os.curdir)
|
||||
self.configuration_path = "%s/%s" % (directory, filename)
|
||||
else:
|
||||
self.configuration_path = configuration_path
|
||||
|
||||
|
||||
configuration_location = QLabel()
|
||||
configuration_location.setText(directory)
|
||||
|
||||
configuration_name = QLabel()
|
||||
configuration_name.setText(filename)
|
||||
|
||||
self.db_type = QComboBox()
|
||||
self.db_type.addItem("BLOCK_FS")
|
||||
self.db_type.addItem("PLAIN")
|
||||
|
||||
self.first_case_name = QLineEdit()
|
||||
self.first_case_name.setText("default")
|
||||
self.connect(self.first_case_name, SIGNAL('textChanged(QString)'), self._validateName)
|
||||
|
||||
self.num_realizations = QSpinBox()
|
||||
self.num_realizations.setMinimum( 1 )
|
||||
self.num_realizations.setMaximum( 1000 )
|
||||
self.num_realizations.setValue( 10 )
|
||||
|
||||
self.storage_path = QLineEdit()
|
||||
self.storage_path.setText("Storage")
|
||||
self.connect(self.storage_path, SIGNAL('textChanged(QString)'), self._validateName)
|
||||
|
||||
|
||||
layout.addRow(createSpace(10))
|
||||
layout.addRow("Configuration name:", configuration_name)
|
||||
layout.addRow("Configuration location:", configuration_location)
|
||||
layout.addRow("Path to store DBase:",self.storage_path)
|
||||
layout.addRow("DBase type:", self.db_type)
|
||||
layout.addRow("Name of first case:", self.first_case_name)
|
||||
layout.addRow("Number of realizations" , self.num_realizations)
|
||||
layout.addRow(createSpace(10))
|
||||
|
||||
buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self)
|
||||
self.ok_button = buttons.button(QDialogButtonBox.Ok)
|
||||
|
||||
layout.addRow(buttons)
|
||||
|
||||
self.connect(buttons, SIGNAL('accepted()'), self.accept)
|
||||
self.connect(buttons, SIGNAL('rejected()'), self.reject)
|
||||
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
|
||||
def getNumberOfRealizations(self):
|
||||
return self.num_realizations.value()
|
||||
|
||||
def getConfigurationPath(self):
|
||||
return self.configuration_path
|
||||
|
||||
def getCaseName(self):
|
||||
"""Return the name of the first case."""
|
||||
return str(self.first_case_name.text()).strip()
|
||||
|
||||
def getDBaseType(self):
|
||||
"""Return the DBase type"""
|
||||
return str(self.db_type.currentText())
|
||||
|
||||
def getStoragePath(self):
|
||||
"""Return the DBase storage path"""
|
||||
return str(self.storage_path.text()).strip()
|
||||
|
||||
def _validateName(self, name):
|
||||
name = str(name)
|
||||
enabled = len(name) > 0 and name.find(" ") == -1
|
||||
self.ok_button.setEnabled(enabled)
|
||||
@@ -1,17 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file '__init__.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'application.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from PyQt4.QtGui import QDockWidget
|
||||
from PyQt4.QtCore import Qt, QSettings
|
||||
|
||||
class Application(QtGui.QMainWindow):
|
||||
"""An application (window widget) with a list of "tasks" on the left side and a panel on the right side"""
|
||||
|
||||
def __init__(self):
|
||||
"""Constructor"""
|
||||
QtGui.QMainWindow.__init__(self)
|
||||
|
||||
self.resize(900, 700)
|
||||
self.setWindowTitle('ERT GUI')
|
||||
|
||||
centralWidget = QtGui.QWidget()
|
||||
widgetLayout = QtGui.QVBoxLayout()
|
||||
|
||||
self.contentsWidget = QtGui.QListWidget()
|
||||
self.contentsWidget.setViewMode(QtGui.QListView.IconMode)
|
||||
self.contentsWidget.setIconSize(QtCore.QSize(96, 96))
|
||||
self.contentsWidget.setMovement(QtGui.QListView.Static)
|
||||
self.contentsWidget.setMaximumWidth(128)
|
||||
self.contentsWidget.setMinimumWidth(128)
|
||||
self.contentsWidget.setSpacing(12)
|
||||
|
||||
dock = self._createDock()
|
||||
|
||||
self.addDockWidget(Qt.LeftDockWidgetArea, dock)
|
||||
|
||||
self.pagesWidget = QtGui.QStackedWidget()
|
||||
|
||||
|
||||
horizontalLayout = QtGui.QHBoxLayout()
|
||||
horizontalLayout.addWidget(self.pagesWidget, 1)
|
||||
widgetLayout.addLayout(horizontalLayout)
|
||||
|
||||
self._createMenu(dock)
|
||||
|
||||
centralWidget.setLayout(widgetLayout)
|
||||
self.setCentralWidget(centralWidget)
|
||||
|
||||
self.save_function = None
|
||||
|
||||
self._fetchSettings()
|
||||
|
||||
def setSaveFunction(self, save_function):
|
||||
"""Set the function to be called when the save menu choice is selected."""
|
||||
self.save_function = save_function
|
||||
|
||||
def _save(self):
|
||||
if not self.save_function is None:
|
||||
self.save_function()
|
||||
|
||||
def _createDock(self):
|
||||
dock = QDockWidget("Workflow")
|
||||
dock.setObjectName("ERTGUI Workflow")
|
||||
dock.setWidget(self.contentsWidget)
|
||||
dock.setFeatures(QDockWidget.DockWidgetClosable)
|
||||
dock.setAllowedAreas(Qt.LeftDockWidgetArea)
|
||||
return dock
|
||||
|
||||
def _createMenu(self, dock):
|
||||
file_menu = self.menuBar().addMenu("&File")
|
||||
file_menu.addAction("Save configuration", self._save)
|
||||
file_menu.addAction("Close", self._quit)
|
||||
|
||||
self.view_menu = self.menuBar().addMenu("&View")
|
||||
self.view_menu.addAction(dock.toggleViewAction())
|
||||
self.view_menu.addSeparator()
|
||||
|
||||
def addPage(self, name, icon, page):
|
||||
"""Add another page to the application"""
|
||||
button = QtGui.QListWidgetItem(self.contentsWidget)
|
||||
button.setIcon(icon)
|
||||
button.setText(name)
|
||||
button.setTextAlignment(QtCore.Qt.AlignHCenter)
|
||||
button.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
||||
|
||||
def switchPage():
|
||||
self.contentsWidget.setCurrentRow(self.contentsWidget.row(button))
|
||||
|
||||
self.view_menu.addAction(name, switchPage)
|
||||
|
||||
self.pagesWidget.addWidget(page)
|
||||
self.connect(self.contentsWidget, QtCore.SIGNAL('currentItemChanged(QListWidgetItem *, QListWidgetItem *)'), self._changePage)
|
||||
|
||||
self.contentsWidget.setCurrentRow(0)
|
||||
|
||||
|
||||
def _changePage(self, current, previous):
|
||||
"""Switch page. Connected to the: currentItemChanged() signal of the list widget on the left side"""
|
||||
if current is None:
|
||||
current = previous
|
||||
|
||||
self.pagesWidget.setCurrentIndex(self.contentsWidget.row(current))
|
||||
|
||||
def _quit(self):
|
||||
self._saveSettings()
|
||||
QtGui.qApp.quit()
|
||||
|
||||
def _saveSettings(self):
|
||||
settings = QSettings("Statoil", "ErtGui")
|
||||
settings.setValue("geometry", self.saveGeometry())
|
||||
settings.setValue("windowState", self.saveState())
|
||||
|
||||
def closeEvent(self, event):
|
||||
#Use QT settings saving mechanism
|
||||
#settings stored in ~/.config/Statoil/ErtGui.conf
|
||||
self._saveSettings()
|
||||
QtGui.QMainWindow.closeEvent(self, event)
|
||||
|
||||
def _fetchSettings(self):
|
||||
settings = QSettings("Statoil", "ErtGui")
|
||||
self.restoreGeometry(settings.value("geometry").toByteArray())
|
||||
self.restoreState(settings.value("windowState").toByteArray())
|
||||
@@ -1,17 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file '__init__.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'analysis.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------------------------
|
||||
# Analysis tab
|
||||
# ----------------------------------------------------------------------------------------------
|
||||
from ert_gui.widgets.checkbox import CheckBox
|
||||
from ert_gui.widgets.spinnerwidgets import IntegerSpinner, DoubleSpinner, DoubleSpinner
|
||||
import ert_gui.widgets.tablewidgets
|
||||
from ert_gui.widgets.pathchooser import PathChooser
|
||||
from ert_gui.widgets.combochoice import ComboChoice
|
||||
from PyQt4 import QtGui
|
||||
import ert.enkf
|
||||
|
||||
def createAnalysisPage(configPanel, parent):
|
||||
configPanel.startPage("Analysis")
|
||||
|
||||
r = configPanel.addRow(CheckBox(parent, "ENKF rerun", "config/analysis/enkf_rerun", "Perform rerun"))
|
||||
r.getter = lambda ert : ert.enkf.analysis_config_get_rerun(ert.analysis_config)
|
||||
r.setter = lambda ert, value : ert.enkf.analysis_config_set_rerun(ert.analysis_config, value)
|
||||
|
||||
r = configPanel.addRow(IntegerSpinner(parent, "Rerun start", "config/analysis/rerun_start", 0, 100000))
|
||||
r.getter = lambda ert : ert.enkf.analysis_config_get_rerun_start(ert.analysis_config)
|
||||
r.setter = lambda ert, value : ert.enkf.analysis_config_set_rerun_start(ert.analysis_config, value)
|
||||
|
||||
r = configPanel.addRow(PathChooser(parent, "ENKF schedule file", "config/analysis/enkf_sched_file"))
|
||||
r.getter = lambda ert : ert.enkf.model_config_get_enkf_sched_file(ert.enkf.enkf_main_get_model_config(ert.main))
|
||||
r.setter = lambda ert, value : ert.enkf.model_config_set_enkf_sched_file(ert.enkf.enkf_main_get_model_config(ert.main), str(value))
|
||||
|
||||
r = configPanel.addRow(ert_gui.widgets.tablewidgets.KeywordList(parent, "Local config", "config/analysis/local_config"))
|
||||
r.newKeywordPopup = lambda list : QtGui.QFileDialog.getOpenFileName(r, "Select a path", "")
|
||||
|
||||
def get_local_config_files(ert):
|
||||
local_config = ert.enkf.enkf_main_get_local_config(ert.main)
|
||||
config_files_pointer = ert.enkf.local_config_get_config_files(local_config)
|
||||
return ert.getStringList(config_files_pointer)
|
||||
|
||||
r.getter = get_local_config_files
|
||||
|
||||
def add_config_file(ert, value):
|
||||
local_config = ert.enkf.enkf_main_get_local_config(ert.main)
|
||||
ert.enkf.local_config_clear_config_files(local_config)
|
||||
|
||||
for file in value:
|
||||
ert.enkf.local_config_add_config_file(local_config, file)
|
||||
|
||||
r.setter = add_config_file
|
||||
|
||||
r = configPanel.addRow(PathChooser(parent, "Update log", "config/analysis/update_log"))
|
||||
r.getter = lambda ert : ert.enkf.analysis_config_get_log_path(ert.analysis_config)
|
||||
r.setter = lambda ert, value : ert.enkf.analysis_config_set_log_path(ert.analysis_config, str(value))
|
||||
|
||||
|
||||
configPanel.startGroup("EnKF")
|
||||
|
||||
r = configPanel.addRow(DoubleSpinner(parent, "Alpha", "config/analysis/enkf_alpha", 0, 100000, 2))
|
||||
r.getter = lambda ert : ert.enkf.analysis_config_get_alpha(ert.analysis_config)
|
||||
r.setter = lambda ert, value : ert.enkf.analysis_config_set_alpha(ert.analysis_config, value)
|
||||
|
||||
r = configPanel.addRow(CheckBox(parent, "Merge Observations", "config/analysis/enkf_merge_observations", "Perform merge"))
|
||||
r.getter = lambda ert : ert.enkf.analysis_config_get_merge_observations(ert.analysis_config)
|
||||
r.setter = lambda ert, value : ert.enkf.analysis_config_set_merge_observations(ert.analysis_config, value)
|
||||
|
||||
|
||||
enkf_mode_type = {"ENKF_STANDARD" : 10, "ENKF_SQRT" : 20}
|
||||
enkf_mode_type_inverted = {10 : "ENKF_STANDARD" , 20 : "ENKF_SQRT"}
|
||||
r = configPanel.addRow(ComboChoice(parent, enkf_mode_type.keys(), "Mode", "config/analysis/enkf_mode"))
|
||||
r.getter = lambda ert : enkf_mode_type_inverted[ert.enkf.analysis_config_get_enkf_mode(ert.analysis_config)]
|
||||
r.setter = lambda ert, value : ert.enkf.analysis_config_set_enkf_mode(ert.analysis_config, enkf_mode_type[str(value)])
|
||||
|
||||
|
||||
r = configPanel.addRow(DoubleSpinner(parent, "Truncation", "config/analysis/enkf_truncation", 0, 1, 2))
|
||||
r.getter = lambda ert : ert.enkf.analysis_config_get_truncation(ert.analysis_config)
|
||||
r.setter = lambda ert, value : ert.enkf.analysis_config_set_truncation(ert.analysis_config, value)
|
||||
|
||||
|
||||
|
||||
configPanel.endGroup()
|
||||
configPanel.endPage()
|
||||
@@ -1,41 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'configpages.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from ert_gui.widgets.configpanel import ConfigPanel
|
||||
import eclipse
|
||||
import analysis
|
||||
import queuesystem
|
||||
import systemenv
|
||||
import plot
|
||||
import ensemble
|
||||
import observations
|
||||
import simulation
|
||||
|
||||
class ConfigPages(ConfigPanel):
|
||||
|
||||
|
||||
def __init__(self, parent):
|
||||
ConfigPanel.__init__(self, parent)
|
||||
|
||||
eclipse.createEclipsePage(self, parent)
|
||||
analysis.createAnalysisPage(self, parent)
|
||||
queuesystem.createQueueSystemPage(self, parent)
|
||||
systemenv.createSystemPage(self, parent)
|
||||
ensemble.createEnsemblePage(self, parent)
|
||||
observations.createObservationsPage(self, parent)
|
||||
simulation.createSimulationsPage(self, parent)
|
||||
plot.createPlotPage(self, parent)
|
||||
@@ -1,102 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'eclipse.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------------------------
|
||||
# Eclipse tab
|
||||
# ----------------------------------------------------------------------------------------------
|
||||
from ert_gui.widgets.pathchooser import PathChooser
|
||||
from ert_gui.widgets.tablewidgets import KeywordTable, KeywordList
|
||||
from ert_gui.widgets.configpanel import ConfigPanel
|
||||
import ert.enkf
|
||||
|
||||
def createEclipsePage(configPanel, parent):
|
||||
configPanel.startPage("Eclipse")
|
||||
|
||||
r = configPanel.addRow(PathChooser(parent, "Eclipse Base", "config/eclipse/eclbase", path_format=True))
|
||||
r.getter = lambda ert : ert.enkf.ecl_config_get_eclbase(ert.ecl_config)
|
||||
r.setter = lambda ert, value : ert.enkf.enkf_main_set_eclbase(ert.main , str(value))
|
||||
|
||||
r = configPanel.addRow(PathChooser(parent, "Data file", "config/eclipse/data_file", show_files=True))
|
||||
r.getter = lambda ert : ert.enkf.ecl_config_get_data_file(ert.ecl_config)
|
||||
r.setter = lambda ert, value : ert.enkf.enkf_main_set_data_file(ert.main , str(value))
|
||||
|
||||
r = configPanel.addRow(PathChooser(parent, "Grid", "config/eclipse/grid", show_files=True))
|
||||
r.getter = lambda ert : ert.enkf.ecl_config_get_gridfile(ert.ecl_config)
|
||||
r.setter = lambda ert, value : ert.enkf.ecl_config_set_grid(ert.ecl_config, str(value))
|
||||
|
||||
r = configPanel.addRow(PathChooser(parent, "Schedule file" , "config/eclipse/schedule_file" , show_files = True))
|
||||
r.getter = lambda ert : ert.enkf.ecl_config_get_schedule_file(ert.ecl_config)
|
||||
r.setter = lambda ert, value : ert.enkf.ecl_config_set_schedule_file(ert.ecl_config, str(value))
|
||||
|
||||
|
||||
r = configPanel.addRow(PathChooser(parent, "Init section", "config/eclipse/init_section", show_files=True))
|
||||
r.getter = lambda ert : ert.enkf.ecl_config_get_init_section(ert.ecl_config)
|
||||
r.setter = lambda ert, value : ert.enkf.ecl_config_set_init_section(ert.ecl_config, str(value))
|
||||
|
||||
|
||||
r = configPanel.addRow(PathChooser(parent, "Refcase", "config/eclipse/refcase", show_files=True))
|
||||
r.getter = lambda ert : ert.enkf.ecl_config_get_refcase_name(ert.ecl_config)
|
||||
r.setter = lambda ert, value : ert.enkf.ecl_config_load_refcase(ert.ecl_config, str(value))
|
||||
|
||||
r = configPanel.addRow(PathChooser(parent, "Schedule prediction file", "config/eclipse/schedule_prediction_file", show_files=True))
|
||||
r.getter = lambda ert : ert.enkf.enkf_main_get_schedule_prediction_file(ert.main)
|
||||
r.setter = lambda ert, value : ert.enkf.enkf_main_set_schedule_prediction_file(ert.main, ert.nonify( value ))
|
||||
|
||||
r = configPanel.addRow(KeywordTable(parent, "Data keywords", "config/eclipse/data_kw"))
|
||||
r.getter = lambda ert : ert.getSubstitutionList(ert.enkf.enkf_main_get_data_kw(ert.main))
|
||||
|
||||
def add_data_kw(ert, listOfKeywords):
|
||||
ert.enkf.enkf_main_clear_data_kw(ert.main)
|
||||
|
||||
for keyword in listOfKeywords:
|
||||
ert.enkf.enkf_main_add_data_kw(ert.main, keyword[0], keyword[1])
|
||||
|
||||
r.setter = add_data_kw
|
||||
|
||||
|
||||
|
||||
configPanel.addSeparator()
|
||||
|
||||
internalPanel = ConfigPanel(parent)
|
||||
|
||||
internalPanel.startPage("Static keywords")
|
||||
|
||||
r = internalPanel.addRow(KeywordList(parent, "", "config/eclipse/add_static_kw"))
|
||||
r.getter = lambda ert : ert.getStringList(ert.enkf.ecl_config_get_static_kw_list(ert.ecl_config))
|
||||
|
||||
def add_static_kw(ert, listOfKeywords):
|
||||
ert.enkf.ecl_config_clear_static_kw(ert.ecl_config)
|
||||
|
||||
for keyword in listOfKeywords:
|
||||
ert.enkf.ecl_config_add_static_kw(ert.ecl_config, keyword)
|
||||
|
||||
r.setter = add_static_kw
|
||||
|
||||
internalPanel.endPage()
|
||||
|
||||
# todo: add support for fixed length schedule keywords
|
||||
#internalPanel.startPage("Fixed length schedule keywords")
|
||||
#
|
||||
#r = internalPanel.addRow(KeywordList(widget, "", "add_fixed_length_schedule_kw"))
|
||||
#r.getter = lambda ert : ert.getAttribute("add_fixed_length_schedule_kw")
|
||||
#r.setter = lambda ert, value : ert.setAttribute("add_fixed_length_schedule_kw", value)
|
||||
#
|
||||
#internalPanel.endPage()
|
||||
|
||||
configPanel.addRow(internalPanel)
|
||||
|
||||
configPanel.endPage()
|
||||
@@ -1,243 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'ensemble.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------------------------
|
||||
# Ensemble tab
|
||||
# ----------------------------------------------------------------------------------------------
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from ert_gui.widgets.spinnerwidgets import IntegerSpinner
|
||||
from parameters.parameterpanel import ParameterPanel, enums
|
||||
from parameters.parametermodels import SummaryModel, DataModel, FieldModel, KeywordModel
|
||||
from ert.ert.enums import field_type
|
||||
from ert.ert.enums import truncation_type
|
||||
from ert.ert.enums import gen_data_file_format
|
||||
|
||||
def createEnsemblePage(configPanel, parent):
|
||||
configPanel.startPage("Ensemble")
|
||||
|
||||
r = configPanel.addRow(IntegerSpinner(parent, "Number of realizations", "config/ensemble/num_realizations", 1, 10000))
|
||||
|
||||
r.getter = lambda ert : ert.enkf.enkf_main_get_ensemble_size(ert.main)
|
||||
r.setter = lambda ert, value : ert.enkf.enkf_main_resize_ensemble(ert.main, value)
|
||||
|
||||
parent.connect(r, QtCore.SIGNAL("contentsChanged()"), lambda : r.modelEmit("ensembleResized()"))
|
||||
|
||||
|
||||
configPanel.startGroup("Parameters")
|
||||
r = configPanel.addRow(ParameterPanel(parent, "", "")) # no help file necessary
|
||||
parent.connect(r, QtCore.SIGNAL("contentsChanged()"), lambda : r.modelEmit("ensembleUpdated()"))
|
||||
|
||||
def getEnsembleParameters(ert):
|
||||
keys = ert.getStringList(ert.enkf.ensemble_config_alloc_keylist(ert.ensemble_config), free_after_use=True)
|
||||
|
||||
parameters = []
|
||||
for key in keys:
|
||||
node = ert.enkf.ensemble_config_get_node(ert.ensemble_config, key)
|
||||
type = ert.enkf.enkf_config_node_get_impl_type(node)
|
||||
data = ert.enkf.enkf_config_node_get_ref(node)
|
||||
#print key, type
|
||||
|
||||
model = None
|
||||
if type == FieldModel.TYPE:
|
||||
model = FieldModel(key)
|
||||
|
||||
field_type = ert.enkf.field_config_get_type(data)
|
||||
field_type = enums.field_type[field_type]
|
||||
model["type"] = field_type
|
||||
|
||||
truncation = ert.enkf.field_config_get_truncation_mode(data)
|
||||
|
||||
if truncation & enums.truncation_type.TRUNCATE_MAX:
|
||||
model["max"] = ert.enkf.field_config_get_truncation_max(data)
|
||||
|
||||
if truncation & enums.truncation_type.TRUNCATE_MIN:
|
||||
model["min"] = ert.enkf.field_config_get_truncation_min(data)
|
||||
|
||||
model["init"] = ert.enkf.field_config_get_init_transform_name(data)
|
||||
model["output"] = ert.enkf.field_config_get_output_transform_name(data)
|
||||
|
||||
model["init_files"] = ert.enkf.field_config_get_init_file_fmt(data)
|
||||
model["min_std"] = ert.enkf.enkf_config_node_get_min_std_file(node)
|
||||
model["enkf_outfile"] = ert.enkf.enkf_config_node_get_enkf_outfile(node)
|
||||
model["enkf_infile"] = ert.enkf.enkf_config_node_get_enkf_infile(node)
|
||||
|
||||
elif type == DataModel.TYPE:
|
||||
model = DataModel(key)
|
||||
|
||||
output_format_value = ert.enkf.gen_data_config_get_output_format(data)
|
||||
output_format = gen_data_file_format.resolveValue(output_format_value)
|
||||
|
||||
input_format_value = ert.enkf.gen_data_config_get_input_format(data)
|
||||
input_format = gen_data_file_format.resolveValue(input_format_value)
|
||||
|
||||
template_file = ert.enkf.gen_data_config_get_template_file(data)
|
||||
template_key = ert.enkf.gen_data_config_get_template_key(data)
|
||||
init_file_fmt = ert.enkf.gen_data_config_get_init_file_fmt(data)
|
||||
|
||||
model["output_format"] = output_format
|
||||
model["input_format"] = input_format
|
||||
model["template_file"] = template_file
|
||||
model["template_key"] = template_key
|
||||
model["init_file_fmt"] = init_file_fmt
|
||||
|
||||
min_std = ert.enkf.enkf_config_node_get_min_std_file(node)
|
||||
enkf_outfile = ert.enkf.enkf_config_node_get_enkf_outfile(node)
|
||||
enkf_infile = ert.enkf.enkf_config_node_get_enkf_infile(node)
|
||||
|
||||
|
||||
|
||||
model["min_std"] = min_std
|
||||
model["enkf_outfile"] = enkf_outfile
|
||||
model["enkf_infile"] = enkf_infile
|
||||
|
||||
elif type == KeywordModel.TYPE:
|
||||
model = KeywordModel(key)
|
||||
model["min_std"] = ert.enkf.enkf_config_node_get_min_std_file(node)
|
||||
model["enkf_outfile"] = ert.enkf.enkf_config_node_get_enkf_outfile(node)
|
||||
model["template"] = ert.enkf.gen_kw_config_get_template_file(data)
|
||||
model["init_file"] = ert.enkf.gen_kw_config_get_init_file_fmt(data)
|
||||
model["parameter_file"] = ert.enkf.gen_kw_config_get_parameter_file(data)
|
||||
elif type == SummaryModel.TYPE:
|
||||
model = SummaryModel(key)
|
||||
else:
|
||||
pass #Unknown type
|
||||
|
||||
model.setValid(ert.enkf.enkf_config_node_is_valid(node))
|
||||
|
||||
parameters.append(model)
|
||||
|
||||
return parameters
|
||||
|
||||
def removeParameter(ert, parameter_key):
|
||||
ert.enkf.enkf_main_del_node(ert.main, parameter_key)
|
||||
|
||||
def insertParameter(ert, parameter):
|
||||
key = parameter.getName()
|
||||
if parameter.getType() == FieldModel.TYPE:
|
||||
grid = ert.enkf.ecl_config_get_grid(ert.ecl_config)
|
||||
node = ert.enkf.ensemble_config_add_field(ert.ensemble_config, key, grid)
|
||||
parameter.setValid(ert.enkf.enkf_config_node_is_valid(node))
|
||||
elif parameter.getType() == DataModel.TYPE:
|
||||
node = ert.enkf.ensemble_config_add_gen_data(ert.ensemble_config, key)
|
||||
parameter.setValid(ert.enkf.enkf_config_node_is_valid(node))
|
||||
elif parameter.getType() == KeywordModel.TYPE:
|
||||
node = ert.enkf.ensemble_config_add_gen_kw(ert.ensemble_config, key)
|
||||
parameter.setValid(ert.enkf.enkf_config_node_is_valid(node))
|
||||
elif parameter.getType() == SummaryModel.TYPE:
|
||||
parameter.setValid(True)
|
||||
b = ert.enkf.ensemble_config_add_summary(ert.ensemble_config, key)
|
||||
return b > 0 #0 == NULL
|
||||
else:
|
||||
print "Unknown type: ", parameter
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def updateParameter(ert, parameter_model):
|
||||
key = parameter_model.getName()
|
||||
node = ert.enkf.ensemble_config_get_node(ert.ensemble_config, key)
|
||||
|
||||
if isinstance(parameter_model, FieldModel):
|
||||
type = parameter_model["type"]
|
||||
|
||||
minimum = parameter_model["min"]
|
||||
maximum = parameter_model["max"]
|
||||
truncate = truncation_type.resolveTruncationType(minimum, maximum)
|
||||
|
||||
if minimum == "":
|
||||
minimum = 0.0
|
||||
|
||||
if maximum == "":
|
||||
maximum = 0.0
|
||||
|
||||
if type == field_type.ECLIPSE_RESTART: #dynamic
|
||||
ert.enkf.enkf_config_node_update_state_field(node,
|
||||
truncate.value(),
|
||||
float(minimum),
|
||||
float(maximum))
|
||||
elif type == field_type.ECLIPSE_PARAMETER: #parameter
|
||||
ert.enkf.enkf_config_node_update_parameter_field(node,
|
||||
ert.nonify(parameter_model["enkf_outfile"]),
|
||||
ert.nonify(parameter_model["init_files"]),
|
||||
ert.nonify(parameter_model["min_std"]),
|
||||
truncate.value(),
|
||||
float(minimum),
|
||||
float(maximum),
|
||||
parameter_model["init"],
|
||||
parameter_model["output"])
|
||||
elif type == field_type.GENERAL: #general
|
||||
ert.enkf.enkf_config_node_update_general_field(node,
|
||||
ert.nonify(parameter_model["enkf_outfile"]),
|
||||
ert.nonify(parameter_model["enkf_infile"]),
|
||||
ert.nonify(parameter_model["init_files"]),
|
||||
ert.nonify(parameter_model["min_std"]),
|
||||
truncate.value(),
|
||||
float(minimum),
|
||||
float(maximum),
|
||||
parameter_model["init"],
|
||||
None,
|
||||
parameter_model["output"])
|
||||
|
||||
parameter_model.setValid(ert.enkf.enkf_config_node_is_valid(node))
|
||||
|
||||
elif isinstance(parameter_model, KeywordModel):
|
||||
enkf_outfile_fmt = parameter_model["enkf_outfile"]
|
||||
template_file = parameter_model["template"]
|
||||
parameter_file = parameter_model["parameter_file"]
|
||||
min_std_file = parameter_model["min_std"]
|
||||
init_file_fmt = parameter_model["init_files"]
|
||||
ert.enkf.enkf_config_node_update_gen_kw(node,
|
||||
ert.nonify(enkf_outfile_fmt),
|
||||
ert.nonify(template_file),
|
||||
ert.nonify(parameter_file),
|
||||
ert.nonify(min_std_file),
|
||||
ert.nonify(init_file_fmt))
|
||||
parameter_model.setValid(ert.enkf.enkf_config_node_is_valid(node))
|
||||
elif isinstance(parameter_model, SummaryModel):
|
||||
#should never be called from SummaryModel...
|
||||
raise AssertionError("Summary keys can not be updated!")
|
||||
elif isinstance(parameter_model, DataModel):
|
||||
input_format = gen_data_file_format.resolveName(str(parameter_model["input_format"]))
|
||||
output_format = gen_data_file_format.resolveName(str(parameter_model["output_format"]))
|
||||
ert.enkf.enkf_config_node_update_gen_data(node,
|
||||
input_format.value(),
|
||||
output_format.value(),
|
||||
ert.nonify(parameter_model["init_file_fmt"]),
|
||||
ert.nonify(parameter_model["template_file"]),
|
||||
ert.nonify(parameter_model["template_key"]),
|
||||
ert.nonify(parameter_model["enkf_outfile"]),
|
||||
ert.nonify(parameter_model["enkf_infile"]),
|
||||
ert.nonify(parameter_model["min_std"]))
|
||||
parameter_model.setValid(ert.enkf.enkf_config_node_is_valid(node))
|
||||
else:
|
||||
raise AssertionError("Type is not supported: %s" % (parameter_model.__class__))
|
||||
|
||||
if ert.enkf.enkf_config_node_is_valid(node):
|
||||
ert.enkf.enkf_main_update_node( ert.main , key )
|
||||
|
||||
|
||||
|
||||
|
||||
r.getter = getEnsembleParameters
|
||||
r.remove = removeParameter
|
||||
r.insert = insertParameter
|
||||
r.setter = updateParameter
|
||||
configPanel.endGroup()
|
||||
|
||||
configPanel.endPage()
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file '__init__.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
@@ -1,197 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'forwardmodelpanel.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from ert_gui.widgets.helpedwidget import HelpedWidget, ContentModel
|
||||
from ert_gui.widgets.searchablelist import SearchableList
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from ert_gui.widgets.pathchooser import PathChooser
|
||||
from ert_gui.widgets.validateddialog import ValidatedDialog
|
||||
import ert_gui.widgets.util
|
||||
import os
|
||||
from ert_gui.widgets.util import ValidationInfo
|
||||
from jobsdialog import EditJobDialog
|
||||
from ert_gui.widgets.stringbox import StringBox
|
||||
|
||||
class ForwardModelPanel(HelpedWidget):
|
||||
"""
|
||||
Widget for adding, removing and editing forward models.
|
||||
Only uses the setter and getter hooks.
|
||||
The panel expects remove to return True or False based on the success of the removal.
|
||||
"""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
HelpedWidget.__init__(self, parent, "Forward Model", "config/simulation/forward_model")
|
||||
|
||||
self.forward_model_job = ForwardModelJob("undefined")
|
||||
|
||||
self.createWidgets(parent)
|
||||
|
||||
self.emptyPanel = ert_gui.widgets.util.createEmptyPanel()
|
||||
|
||||
self.pagesWidget = QtGui.QStackedWidget()
|
||||
self.pagesWidget.addWidget(self.emptyPanel)
|
||||
self.pagesWidget.addWidget(self.forward_model_panel)
|
||||
self.addWidget(self.pagesWidget)
|
||||
|
||||
self.addHelpButton()
|
||||
|
||||
def createWidgets(self, parent):
|
||||
self.searchableList = SearchableList(parent, list_height=150, list_width=150, ignore_case=True, order_editable=True)
|
||||
self.addWidget(self.searchableList)
|
||||
self.connect(self.searchableList, QtCore.SIGNAL('currentItemChanged(QListWidgetItem, QListWidgetItem)'),
|
||||
self.changeParameter)
|
||||
self.connect(self.searchableList, QtCore.SIGNAL('addItem(list)'), self.addItem)
|
||||
self.connect(self.searchableList, QtCore.SIGNAL('removeItem(list)'), self.removeItem)
|
||||
self.connect(self.searchableList, QtCore.SIGNAL('orderChanged(list)'), self.forwardModelChanged)
|
||||
|
||||
|
||||
self.forward_model_panel = ert_gui.widgets.util.createEmptyPanel()
|
||||
|
||||
layout = QtGui.QFormLayout()
|
||||
layout.setLabelAlignment(QtCore.Qt.AlignRight)
|
||||
|
||||
|
||||
self.forward_model_args = StringBox(self, "", "config/simulation/forward_model_arguments")
|
||||
self.forward_model_args.initialize = ContentModel.emptyInitializer
|
||||
self.forward_model_args.setter = self.setArguments
|
||||
self.forward_model_args.getter = lambda model: self.forward_model_job.arguments
|
||||
|
||||
layout.addRow("Arguments:", self.forward_model_args)
|
||||
|
||||
layout.addRow(ert_gui.widgets.util.createSpace(20))
|
||||
|
||||
self.help_text = QtGui.QLabel()
|
||||
self.help_text.setText("")
|
||||
|
||||
layout.addRow(ert_gui.widgets.util.centeredWidget(self.help_text))
|
||||
|
||||
self.forward_model_panel.setLayout(layout)
|
||||
self.modelConnect('jobListChanged()', self.fetchContent)
|
||||
|
||||
def setArguments(self, model, arguments):
|
||||
"""Set the arguments of the current forward model job."""
|
||||
self.forward_model_job.setArguments(arguments)
|
||||
self.forwardModelChanged()
|
||||
|
||||
def fetchContent(self):
|
||||
"""
|
||||
Retrieves data from the model and inserts it into the widget.
|
||||
Expects a hash containing these two keys: available_jobs and forward_model.
|
||||
available_jobs=list of names
|
||||
forward_model)list of tuples containing(name, arguments, help_text)
|
||||
"""
|
||||
data = self.getFromModel()
|
||||
|
||||
self.available_jobs = data['available_jobs']
|
||||
|
||||
forward_model = data['forward_model']
|
||||
self.searchableList.list.clear()
|
||||
for job in forward_model:
|
||||
jobitem = QtGui.QListWidgetItem()
|
||||
jobitem.setText(job[0])
|
||||
forward_model_job = ForwardModelJob(job[0])
|
||||
forward_model_job.setArguments(job[1])
|
||||
forward_model_job.setHelpText(job[2])
|
||||
|
||||
jobitem.setData(QtCore.Qt.UserRole, forward_model_job)
|
||||
jobitem.setToolTip(job[0])
|
||||
self.searchableList.list.addItem(jobitem)
|
||||
|
||||
def setForwardModelJob(self, forward_model_job):
|
||||
"""Set the current visible forward model job"""
|
||||
self.forward_model_job = forward_model_job
|
||||
self.help_text.setText(forward_model_job.help_text)
|
||||
self.forward_model_args.fetchContent()
|
||||
|
||||
def changeParameter(self, current, previous):
|
||||
"""Switch between forward models. Selection from the list"""
|
||||
if current is None:
|
||||
self.pagesWidget.setCurrentWidget(self.emptyPanel)
|
||||
else:
|
||||
self.pagesWidget.setCurrentWidget(self.forward_model_panel)
|
||||
self.setForwardModelJob(current.data(QtCore.Qt.UserRole).toPyObject())
|
||||
|
||||
def forwardModelChanged(self):
|
||||
"""
|
||||
Called whenever the forward model is changed. (reordering, adding, removing)
|
||||
The data submitted to the updateContent() (from ContentModel) is a list of tuples (name, arguments)
|
||||
"""
|
||||
items = self.searchableList.getItems()
|
||||
currentRow = self.searchableList.list.currentRow()
|
||||
forward_model = []
|
||||
for item in items:
|
||||
forward_model_job = item.data(QtCore.Qt.UserRole).toPyObject()
|
||||
forward_model.append((forward_model_job.name, forward_model_job.arguments))
|
||||
|
||||
self.updateContent(forward_model)
|
||||
self.fetchContent()
|
||||
self.searchableList.list.setCurrentRow(currentRow)
|
||||
|
||||
def addToList(self, list, name):
|
||||
"""Adds a new job to the list"""
|
||||
param = QtGui.QListWidgetItem()
|
||||
param.setText(name)
|
||||
|
||||
new_job = ForwardModelJob(name)
|
||||
param.setData(QtCore.Qt.UserRole, new_job)
|
||||
|
||||
list.addItem(param)
|
||||
list.setCurrentItem(param)
|
||||
return param
|
||||
|
||||
def addItem(self, list):
|
||||
"""Called by the add button to insert a new job"""
|
||||
|
||||
pd = ValidatedDialog(self, "New forward model job", "Select a job:", self.available_jobs, True)
|
||||
if pd.exec_():
|
||||
self.addToList(list, pd.getName())
|
||||
self.forwardModelChanged()
|
||||
|
||||
def removeItem(self, list):
|
||||
"""Called by the remove button to remove a selected job"""
|
||||
currentRow = list.currentRow()
|
||||
|
||||
if currentRow >= 0:
|
||||
title = "Delete forward model job?"
|
||||
msg = "Are you sure you want to delete the job from the forward model?"
|
||||
btns = QtGui.QMessageBox.Yes | QtGui.QMessageBox.No
|
||||
doDelete = QtGui.QMessageBox.question(self, title, msg, btns)
|
||||
|
||||
if doDelete == QtGui.QMessageBox.Yes:
|
||||
list.takeItem(currentRow)
|
||||
self.forwardModelChanged()
|
||||
|
||||
class ForwardModelJob:
|
||||
"""Stores the name, arguments and help text of a job."""
|
||||
|
||||
def __init__(self, name, arguments=None, help_text=""):
|
||||
self.name = name
|
||||
self.setArguments(arguments)
|
||||
self.setHelpText(help_text)
|
||||
|
||||
def setArguments(self, args):
|
||||
if args is None:
|
||||
args = ""
|
||||
self.arguments = args
|
||||
|
||||
def setHelpText(self, text):
|
||||
if text == "":
|
||||
self.help_text = "No help available for this job."
|
||||
else:
|
||||
self.help_text = text
|
||||
|
||||
|
||||
@@ -1,191 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'jobsdialog.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from ert_gui.widgets.configpanel import ConfigPanel
|
||||
from ert_gui.widgets.pathchooser import PathChooser
|
||||
from ert_gui.widgets.tablewidgets import KeywordTable
|
||||
from ert_gui.widgets.tablewidgets import KeywordList
|
||||
from ert_gui.widgets.stringbox import StringBox
|
||||
import os
|
||||
from ert_gui.widgets.spinnerwidgets import IntegerSpinner
|
||||
import ert_gui.widgets.util
|
||||
from ert_gui.widgets.helpedwidget import ContentModelProxy
|
||||
|
||||
class EditJobDialog(QtGui.QDialog):
|
||||
"""
|
||||
A panel for creating custom jobs.
|
||||
"""
|
||||
def __init__(self, parent=None):
|
||||
QtGui.QDialog.__init__(self, parent)
|
||||
self.setModal(True)
|
||||
self.setWindowTitle("Edit job")
|
||||
self.setMinimumWidth(650)
|
||||
|
||||
layout = QtGui.QVBoxLayout()
|
||||
|
||||
self.jobPanel = JobConfigPanel(parent)
|
||||
|
||||
layout.addWidget(self.jobPanel)
|
||||
|
||||
self.doneButton = QtGui.QPushButton("Done", self)
|
||||
self.cancelButton = QtGui.QPushButton("Cancel", self)
|
||||
self.connect(self.doneButton, QtCore.SIGNAL('clicked()'), self.saveJob)
|
||||
self.connect(self.cancelButton, QtCore.SIGNAL('clicked()'), self.reject)
|
||||
|
||||
self.validationInfo = widgets.util.ValidationInfo()
|
||||
|
||||
buttonLayout = QtGui.QHBoxLayout()
|
||||
buttonLayout.addWidget(self.validationInfo)
|
||||
buttonLayout.addStretch(1)
|
||||
buttonLayout.addWidget(self.doneButton)
|
||||
buttonLayout.addWidget(self.cancelButton)
|
||||
|
||||
layout.addSpacing(10)
|
||||
layout.addLayout(buttonLayout)
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
if not event.key() == QtCore.Qt.Key_Escape:
|
||||
QtGui.QDialog.keyPressEvent(self, event)
|
||||
|
||||
def setJob(self, job):
|
||||
self.jobPanel.setJob(job)
|
||||
|
||||
def saveJob(self):
|
||||
msg = self.jobPanel.saveJob()
|
||||
if msg is None:
|
||||
self.accept()
|
||||
else:
|
||||
self.validationInfo.setMessage(msg)
|
||||
|
||||
|
||||
class JobConfigPanel(ConfigPanel):
|
||||
def __init__(self, parent=None):
|
||||
ConfigPanel.__init__(self, parent)
|
||||
|
||||
self.initialized = False
|
||||
|
||||
layout = QtGui.QFormLayout()
|
||||
layout.setLabelAlignment(QtCore.Qt.AlignRight)
|
||||
|
||||
def jid(ert):
|
||||
"""Returns the pointer to the current job (self.job)"""
|
||||
jl = ert.enkf.site_config_get_installed_jobs(ert.site_config)
|
||||
return ert.job_queue.ext_joblist_get_job(jl, self.job.name)
|
||||
|
||||
self.stdin = PathChooser(self, "", "config/systemenv/install_job_stdin", show_files=True, must_be_set=False, must_exist=True)
|
||||
self.stdin.setter = lambda ert, value : ert.job_queue.ext_job_set_stdin_file(jid(ert), value)
|
||||
self.stdin.getter = lambda ert : ert.job_queue.ext_job_get_stdin_file(jid(ert))
|
||||
|
||||
self.stdout = PathChooser(self, "", "config/systemenv/install_job_stdout", show_files=True, must_be_set=True, must_exist=False)
|
||||
self.stdout.setter = lambda ert, value : ert.job_queue.ext_job_set_stdout_file(jid(ert), value)
|
||||
self.stdout.getter = lambda ert : ert.job_queue.ext_job_get_stdout_file(jid(ert))
|
||||
|
||||
self.stderr = PathChooser(self, "", "config/systemenv/install_job_stderr", show_files=True, must_be_set=True, must_exist=False)
|
||||
self.stderr.setter = lambda ert, value : ert.job_queue.ext_job_set_stderr_file(jid(ert), value)
|
||||
self.stderr.getter = lambda ert : ert.job_queue.ext_job_get_stderr_file(jid(ert))
|
||||
|
||||
self.target_file = PathChooser(self, "", "config/systemenv/install_job_target_file", show_files=True, must_be_set=False,
|
||||
must_exist=False)
|
||||
self.target_file.setter = lambda ert, value : ert.job_queue.ext_job_set_target_file(jid(ert), value)
|
||||
self.target_file.getter = lambda ert : ert.job_queue.ext_job_get_target_file(jid(ert))
|
||||
|
||||
self.executable = PathChooser(self, "", "config/systemenv/install_job_executable", show_files=True, must_be_set=True,
|
||||
must_exist=True, is_executable_file=True)
|
||||
self.executable.setter = lambda ert, value : ert.job_queue.ext_job_set_executable(jid(ert), value)
|
||||
self.executable.getter = lambda ert : ert.job_queue.ext_job_get_executable(jid(ert))
|
||||
|
||||
def setEnv(ert, value):
|
||||
job = jid(ert)
|
||||
ert.job_queue.ext_job_clear_environment(job)
|
||||
|
||||
for env in value:
|
||||
ert.job_queue.ext_job_add_environment(job, env[0], env[1])
|
||||
|
||||
self.env = KeywordTable(self, "", "config/systemenv/install_job_env", colHead1="Variable", colHead2="Value")
|
||||
self.env.setter = setEnv
|
||||
self.env.getter = lambda ert : ert.getHash(ert.job_queue.ext_job_get_environment(jid(ert)))
|
||||
|
||||
self.arglist = StringBox(self, "", "config/systemenv/install_job_arglist")
|
||||
self.arglist.setter = lambda ert, value : ert.job_queue.ext_job_set_private_args_from_string(jid(ert), value)
|
||||
self.arglist.getter = lambda ert : ert.job_queue.ext_job_get_private_args_as_string(jid(ert))
|
||||
|
||||
self.max_running = IntegerSpinner(self, "", "config/systemenv/install_job_max_running", 0, 10000)
|
||||
self.max_running.setter = lambda ert, value : ert.job_queue.ext_job_set_max_running(jid(ert), value)
|
||||
self.max_running.getter = lambda ert : ert.job_queue.ext_job_get_max_running(jid(ert))
|
||||
|
||||
self.max_running_minutes = IntegerSpinner(self, "", "config/systemenv/install_job_max_running_minutes", 0, 10000)
|
||||
self.max_running_minutes.setter = lambda ert, value : ert.job_queue.ext_job_set_max_running_minutes(jid(ert), value)
|
||||
self.max_running_minutes.getter = lambda ert : ert.job_queue.ext_job_get_max_running_minutes(jid(ert))
|
||||
|
||||
|
||||
self.startPage("Standard")
|
||||
self.add("Executable.:", self.executable)
|
||||
self.add("Stdout:", self.stdout)
|
||||
self.add("Stderr:", self.stderr)
|
||||
self.add("Target file:", self.target_file)
|
||||
self.add("Arglist.:", self.arglist)
|
||||
self.endPage()
|
||||
|
||||
self.startPage("Advanced")
|
||||
self.add("Stdin:", self.stdin)
|
||||
self.add("Max running:", self.max_running)
|
||||
self.max_running.setInfo("(0=unlimited)")
|
||||
self.add("Max running minutes:", self.max_running_minutes)
|
||||
self.max_running_minutes.setInfo("(0=unlimited)")
|
||||
self.add("Env.:", self.env)
|
||||
self.endPage()
|
||||
|
||||
def add(self, label, widget):
|
||||
self.addRow(widget, label)
|
||||
|
||||
|
||||
def setJob(self, job):
|
||||
self.job = job
|
||||
|
||||
self.initialize(self.stdin.getModel())
|
||||
|
||||
self.cmproxy = ContentModelProxy() #Since only the last change matters and no insert and remove is done
|
||||
self.cmproxy.proxify(self.stdin, self.stdout, self.stderr, self.target_file, self.executable,
|
||||
self.env, self.arglist,
|
||||
self.max_running, self.max_running_minutes)
|
||||
|
||||
self.stdin.fetchContent()
|
||||
self.stdout.fetchContent()
|
||||
self.stderr.fetchContent()
|
||||
self.target_file.fetchContent()
|
||||
self.executable.fetchContent()
|
||||
self.env.fetchContent()
|
||||
self.arglist.fetchContent()
|
||||
self.max_running.fetchContent()
|
||||
self.max_running_minutes.fetchContent()
|
||||
|
||||
def saveJob(self):
|
||||
if self.executable.isValid() and self.stderr.isValid() and self.stdout.isValid():
|
||||
self.cmproxy.apply()
|
||||
|
||||
ert = self.stdin.getModel()
|
||||
jl = ert.enkf.site_config_get_installed_jobs(ert.site_config)
|
||||
jid = ert.job_queue.ext_joblist_get_job(jl, self.job.name)
|
||||
ert.job_queue.ext_job_save(jid)
|
||||
return None
|
||||
else:
|
||||
return "These fields are required: executable, stdout and stderr!"
|
||||
|
||||
@@ -1,187 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'jobspanel.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from ert_gui.widgets.helpedwidget import HelpedWidget, ContentModel
|
||||
from ert_gui.widgets.searchablelist import SearchableList
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from ert_gui.widgets.pathchooser import PathChooser
|
||||
from ert_gui.widgets.validateddialog import ValidatedDialog
|
||||
import ert_gui.widgets.util
|
||||
import os
|
||||
from ert_gui.widgets.util import ValidationInfo
|
||||
from jobsdialog import EditJobDialog
|
||||
|
||||
class JobsPanel(HelpedWidget):
|
||||
"""
|
||||
Widget for adding, removing and editing jobs.
|
||||
These additional ContentModel functions must be implemented: insert and remove.
|
||||
The panel expects remove to return True or False based on the success of the removal.
|
||||
"""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
HelpedWidget.__init__(self, parent, "", "config/systemenv/install_jobs")
|
||||
|
||||
self.job = Job("undefined")
|
||||
|
||||
self.createWidgets(parent)
|
||||
|
||||
self.emptyPanel = ert_gui.widgets.util.createEmptyPanel()
|
||||
|
||||
self.pagesWidget = QtGui.QStackedWidget()
|
||||
self.pagesWidget.addWidget(self.emptyPanel)
|
||||
self.pagesWidget.addWidget(self.jobPanel)
|
||||
self.addWidget(self.pagesWidget)
|
||||
|
||||
def createWidgets(self, parent):
|
||||
self.searchableList = SearchableList(parent, list_height=200, list_width=150, ignore_case=True)
|
||||
self.addWidget(self.searchableList)
|
||||
self.connect(self.searchableList, QtCore.SIGNAL('currentItemChanged(QListWidgetItem, QListWidgetItem)'),
|
||||
self.changeParameter)
|
||||
self.connect(self.searchableList, QtCore.SIGNAL('addItem(list)'), self.addItem)
|
||||
self.connect(self.searchableList, QtCore.SIGNAL('removeItem(list)'), self.removeItem)
|
||||
|
||||
|
||||
self.jobPanel = ert_gui.widgets.util.createEmptyPanel()
|
||||
|
||||
layout = QtGui.QFormLayout()
|
||||
layout.setLabelAlignment(QtCore.Qt.AlignRight)
|
||||
|
||||
self.jobpath = PathChooser(self, "", "config/systemenv/install_job_path", show_files=True, must_be_set=True)
|
||||
self.jobpath.initialize = ContentModel.emptyInitializer
|
||||
self.jobpath.setter = self.setPath
|
||||
self.jobpath.getter = lambda model: self.job.path
|
||||
|
||||
layout.addRow("Job:", self.jobpath)
|
||||
|
||||
layout.addRow(ert_gui.widgets.util.createSpace(20))
|
||||
|
||||
self.validationInfo = ValidationInfo(ValidationInfo.EXCLAMATION)
|
||||
self.validationInfo.setMessage("Pressing edit will create a job that does not exist.")
|
||||
|
||||
self.editButton = QtGui.QPushButton(self)
|
||||
self.editButton.setToolTip("Edit job")
|
||||
self.editButton.setIcon(ert_gui.widgets.util.resourceIcon("cog"))
|
||||
self.editButton.setText("Edit")
|
||||
self.connect(self.editButton, QtCore.SIGNAL('clicked()'), self.editJob)
|
||||
|
||||
|
||||
layout.addRow(ert_gui.widgets.util.centeredWidget(self.editButton))
|
||||
|
||||
layout.addRow(ert_gui.widgets.util.centeredWidget(self.validationInfo))
|
||||
|
||||
|
||||
self.jobPanel.setLayout(layout)
|
||||
|
||||
def setPath(self, model, path):
|
||||
self.job.set("path", path)
|
||||
self.updateContent(self.job)
|
||||
|
||||
# if os.path.exists(path):
|
||||
# self.validationInfo.setMessage("")
|
||||
# else:
|
||||
# self.validationInfo.setMessage("The path must exist! Edit to create the job.")
|
||||
|
||||
def editJob(self):
|
||||
if not os.path.exists(Job.path_prefix):
|
||||
os.mkdir(Job.path_prefix)
|
||||
|
||||
ejd = EditJobDialog(self)
|
||||
ejd.setJob(self.job)
|
||||
ejd.exec_()
|
||||
self.jobpath.validatePath()
|
||||
|
||||
def fetchContent(self):
|
||||
"""Retrieves data from the model and inserts it into the widget"""
|
||||
jobs = self.getFromModel()
|
||||
|
||||
for job in jobs:
|
||||
jobitem = QtGui.QListWidgetItem()
|
||||
jobitem.setText(job.name)
|
||||
jobitem.setData(QtCore.Qt.UserRole, job)
|
||||
jobitem.setToolTip(job.name)
|
||||
self.searchableList.list.addItem(jobitem)
|
||||
|
||||
def setJob(self, job):
|
||||
self.job = job
|
||||
self.jobpath.fetchContent()
|
||||
|
||||
def changeParameter(self, current, previous):
|
||||
"""Switch between jobs. Selection from the list"""
|
||||
if current is None:
|
||||
self.pagesWidget.setCurrentWidget(self.emptyPanel)
|
||||
else:
|
||||
self.pagesWidget.setCurrentWidget(self.jobPanel)
|
||||
self.setJob(current.data(QtCore.Qt.UserRole).toPyObject())
|
||||
|
||||
def addToList(self, list, name):
|
||||
"""Adds a new job to the list"""
|
||||
param = QtGui.QListWidgetItem()
|
||||
param.setText(name)
|
||||
|
||||
new_job = Job(name)
|
||||
param.setData(QtCore.Qt.UserRole, new_job)
|
||||
|
||||
list.addItem(param)
|
||||
list.setCurrentItem(param)
|
||||
return new_job
|
||||
|
||||
def addItem(self, list):
|
||||
"""Called by the add button to insert a new job"""
|
||||
uniqueNames = []
|
||||
for index in range(list.count()):
|
||||
uniqueNames.append(str(list.item(index).text()))
|
||||
|
||||
pd = ValidatedDialog(self, "New job", "Enter name of new job:", uniqueNames)
|
||||
if pd.exec_():
|
||||
new_job = self.addToList(list, pd.getName())
|
||||
|
||||
self.updateContent(new_job, operation=self.INSERT)
|
||||
self.modelEmit('jobListChanged()')
|
||||
|
||||
def removeItem(self, list):
|
||||
"""Called by the remove button to remove a selected job"""
|
||||
currentRow = list.currentRow()
|
||||
|
||||
if currentRow >= 0:
|
||||
title = "Delete job?"
|
||||
msg = "Are you sure you want to delete the job?"
|
||||
btns = QtGui.QMessageBox.Yes | QtGui.QMessageBox.No
|
||||
doDelete = QtGui.QMessageBox.question(self, title, msg, btns)
|
||||
|
||||
if doDelete == QtGui.QMessageBox.Yes:
|
||||
item = list.currentItem()
|
||||
job = item.data(QtCore.Qt.UserRole).toPyObject()
|
||||
success = self.updateContent(job, operation=self.REMOVE)
|
||||
if success:
|
||||
list.takeItem(currentRow)
|
||||
self.modelEmit('jobListChanged()')
|
||||
|
||||
|
||||
class Job:
|
||||
path_prefix = "private_jobs"
|
||||
|
||||
def __init__(self, name, path=None):
|
||||
self.name = name
|
||||
|
||||
if path is None:
|
||||
self.path = self.path_prefix + "/" + name
|
||||
else:
|
||||
self.path = str(path)
|
||||
|
||||
|
||||
def set(self, attr, value):
|
||||
setattr(self, attr, value)
|
||||
@@ -1,62 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'observations.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------------------------
|
||||
# Observations tab
|
||||
# ----------------------------------------------------------------------------------------------
|
||||
from ert_gui.widgets.combochoice import ComboChoice
|
||||
from ert_gui.widgets.pathchooser import PathChooser
|
||||
from ert.ert.enums import history_source_type
|
||||
from ert_gui.widgets.reloadbutton import ReloadButton
|
||||
|
||||
def createObservationsPage(configPanel, parent):
|
||||
configPanel.startPage("Observations")
|
||||
|
||||
r = configPanel.addRow(ComboChoice(parent, history_source_type.values(), "History source", "config/observations/history_source"))
|
||||
|
||||
def get_history_source(ert):
|
||||
history_source = ert.enkf.model_config_get_history_source(ert.model_config)
|
||||
return history_source_type.resolveValue(history_source)
|
||||
|
||||
r.getter = get_history_source
|
||||
|
||||
def set_history_source(ert, value):
|
||||
history_source = history_source_type.resolveName(str(value))
|
||||
ert.enkf.model_config_get_history_source(ert.model_config, history_source.value())
|
||||
|
||||
r.setter = set_history_source
|
||||
|
||||
|
||||
r = configPanel.addRow(PathChooser(parent, "Observations config", "config/observations/obs_config", True))
|
||||
|
||||
def get_obs(ert):
|
||||
obs = ert.enkf.enkf_main_get_obs(ert.main)
|
||||
return ert.enkf.enkf_obs_get_config_file(obs)
|
||||
|
||||
r.getter = get_obs
|
||||
|
||||
|
||||
def set_obs(ert, value):
|
||||
ert.enkf.enkf_main_load_obs(ert.main, str(value))
|
||||
r.setter = set_obs
|
||||
|
||||
|
||||
r = configPanel.addRow(ReloadButton(parent, "Reload Observations", "config/observations/reload_observation", "Reload"))
|
||||
r.getter = lambda ert : ert.enkf.enkf_main_reload_obs(ert.main)
|
||||
|
||||
|
||||
configPanel.endPage()
|
||||
@@ -1,17 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file '__init__.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'datapanel.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from ert_gui.widgets.combochoice import ComboChoice
|
||||
from ert_gui.widgets.stringbox import DoubleBox
|
||||
from ert_gui.widgets.pathchooser import PathChooser
|
||||
from parametermodels import DataModel
|
||||
import ert.ert.enums as enums
|
||||
import ert_gui.widgets.helpedwidget
|
||||
|
||||
class DataPanel(QtGui.QFrame):
|
||||
|
||||
def __init__(self, parent):
|
||||
QtGui.QFrame.__init__(self, parent)
|
||||
|
||||
self.setFrameShape(QtGui.QFrame.StyledPanel)
|
||||
self.setFrameShadow(QtGui.QFrame.Plain)
|
||||
self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
|
||||
|
||||
layout = QtGui.QFormLayout()
|
||||
layout.setLabelAlignment(QtCore.Qt.AlignRight)
|
||||
|
||||
self.dataModel = DataModel("")
|
||||
|
||||
self.input = ComboChoice(self, enums.gen_data_file_format.INPUT_TYPES, "", "config/ensemble/gen_data_param_init")
|
||||
self.modelWrap(self.input, "input_format")
|
||||
|
||||
self.output = ComboChoice(self, enums.gen_data_file_format.OUTPUT_TYPES, "", "config/ensemble/gen_data_param_output")
|
||||
self.modelWrap(self.output, "output_format")
|
||||
|
||||
self.template_file = PathChooser(self, "", "config/ensemble/gen_data_template_file", True , must_be_set=False)
|
||||
self.modelWrap(self.template_file, "template_file")
|
||||
|
||||
self.template_key = PathChooser(self, "", "config/ensemble/gen_data_template_key", True , must_be_set=False)
|
||||
self.modelWrap(self.template_key, "template_key")
|
||||
|
||||
self.init_file_fmt = PathChooser(self, "", "config/ensemble/gen_data_init_file_fmt", True , must_be_set=False)
|
||||
self.modelWrap(self.init_file_fmt, "init_file_fmt")
|
||||
|
||||
|
||||
self.file_generated_by_enkf = PathChooser(self, "", "config/ensemble/gen_data_file_generated_by_enkf", True, must_be_set=False)
|
||||
self.modelWrap(self.file_generated_by_enkf, "enkf_outfile")
|
||||
|
||||
self.file_loaded_by_enkf = PathChooser(self, "", "config/ensemble/gen_data_file_loaded_by_enkf", True, must_be_set=False)
|
||||
self.modelWrap(self.file_loaded_by_enkf, "enkf_infile")
|
||||
|
||||
self.min_std = PathChooser(self, "", "config/ensemble/gen_data_min_std", True, must_be_set=False)
|
||||
self.modelWrap(self.min_std, "min_std")
|
||||
|
||||
layout.addRow("Input:", self.input)
|
||||
layout.addRow("Output:", self.output)
|
||||
layout.addRow("Template file:", self.template_file)
|
||||
layout.addRow("Template key:", self.template_key)
|
||||
layout.addRow("Init files:", self.init_file_fmt)
|
||||
layout.addRow("Include file:", self.file_generated_by_enkf)
|
||||
layout.addRow("Min. std.:", self.min_std)
|
||||
layout.addRow("File loaded by EnKF:", self.file_loaded_by_enkf)
|
||||
|
||||
button = QtGui.QPushButton()
|
||||
button.setText("Reload")
|
||||
button.setMaximumWidth(70)
|
||||
self.connect(button, QtCore.SIGNAL('clicked()'), self._reload)
|
||||
|
||||
layout.addRow("Reload template:", button)
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
def _reload(self):
|
||||
self.dataModel.emitUpdate()
|
||||
|
||||
def modelWrap(self, widget, attribute):
|
||||
widget.initialize = ert_gui.widgets.helpedwidget.ContentModel.emptyInitializer
|
||||
widget.setter = lambda model, value: self.dataModel.set(attribute, value)
|
||||
widget.getter = lambda model: self.dataModel[attribute]
|
||||
|
||||
def setDataModel(self, dataModel):
|
||||
self.dataModel = dataModel
|
||||
|
||||
self.input.fetchContent()
|
||||
self.output.fetchContent()
|
||||
self.template_file.fetchContent()
|
||||
self.template_key.fetchContent()
|
||||
self.init_file_fmt.fetchContent()
|
||||
self.file_generated_by_enkf.fetchContent()
|
||||
self.file_loaded_by_enkf.fetchContent()
|
||||
self.min_std.fetchContent()
|
||||
@@ -1,122 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'fieldpanel.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from ert_gui.widgets.combochoice import ComboChoice
|
||||
from ert_gui.widgets.stringbox import DoubleBox
|
||||
from ert_gui.widgets.pathchooser import PathChooser
|
||||
from parametermodels import FieldModel
|
||||
from ert.ert.enums import field_type
|
||||
from ert_gui.widgets.helpedwidget import ContentModel
|
||||
|
||||
class FieldPanel(QtGui.QFrame):
|
||||
|
||||
def __init__(self, parent):
|
||||
QtGui.QFrame.__init__(self, parent)
|
||||
|
||||
self.setFrameShape(QtGui.QFrame.StyledPanel)
|
||||
self.setFrameShadow(QtGui.QFrame.Plain)
|
||||
self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
|
||||
|
||||
layout = QtGui.QFormLayout()
|
||||
layout.setLabelAlignment(QtCore.Qt.AlignRight)
|
||||
|
||||
self.fieldModel = FieldModel("")
|
||||
|
||||
self.fieldType = ComboChoice(self, field_type.values(), "", "config/ensemble/field_type")
|
||||
self.fieldType.setter = lambda model, value: self.typeChanged(field_type[str(value)])
|
||||
self.fieldType.getter = lambda model: str(self.fieldModel["type"])
|
||||
self.fieldType.initialize = ContentModel.emptyInitializer
|
||||
|
||||
self.min = DoubleBox(self, "", "config/ensemble/field_min")
|
||||
self.modelWrap(self.min, "min")
|
||||
|
||||
self.max = DoubleBox(self, "", "config/ensemble/field_max")
|
||||
self.modelWrap(self.max, "max")
|
||||
|
||||
self.init = ComboChoice(self, ["None", "EXP", "LOG", "POW10", "ADD", "MUL", "RANDINT", "RANDFLOAT"], "", "config/ensemble/field_init")
|
||||
self.modelWrap(self.init, "init")
|
||||
|
||||
self.output = ComboChoice(self, ["None", "EXP", "LOG", "POW10", "ADD", "MUL", "RANDINT", "RANDFLOAT"], "", "config/ensemble/field_output")
|
||||
self.modelWrap(self.output, "output")
|
||||
|
||||
self.init_files = PathChooser(self, "", "config/ensemble/field_init_files", True)
|
||||
self.modelWrap(self.init_files, "init_files")
|
||||
|
||||
self.file_generated_by_enkf = PathChooser(self, "", "config/ensemble/field_file_generated_by_enkf", True)
|
||||
self.modelWrap(self.file_generated_by_enkf, "enkf_outfile")
|
||||
|
||||
self.file_loaded_by_enkf = PathChooser(self, "", "config/ensemble/field_file_loaded_by_enkf", True)
|
||||
self.modelWrap(self.file_loaded_by_enkf, "enkf_infile")
|
||||
|
||||
self.min_std = PathChooser(self, "", "config/ensemble/field_min_std", True, must_be_set=False)
|
||||
self.modelWrap(self.min_std, "min_std")
|
||||
|
||||
layout.addRow("Field type:", self.fieldType)
|
||||
layout.addRow("Include file:", self.file_generated_by_enkf) # generated by ERT
|
||||
layout.addRow("Init files:", self.init_files)
|
||||
layout.addRow("Min:", self.min)
|
||||
layout.addRow("Max:", self.max)
|
||||
layout.addRow("Init transformation:", self.init)
|
||||
layout.addRow("Output transformation:", self.output)
|
||||
layout.addRow("Min. std.:", self.min_std)
|
||||
layout.addRow("File loaded by EnKF:", self.file_loaded_by_enkf)
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
self.typeChanged(field_type.ECLIPSE_RESTART)
|
||||
|
||||
def modelWrap(self, widget, attribute):
|
||||
widget.initialize = ContentModel.emptyInitializer
|
||||
widget.setter = lambda model, value: self.fieldModel.set(attribute, value)
|
||||
widget.getter = lambda model: self.fieldModel[attribute]
|
||||
|
||||
def typeChanged(self, value):
|
||||
setattr(self.fieldModel, "type", value)
|
||||
|
||||
self.min.setEnabled(True)
|
||||
self.max.setEnabled(True)
|
||||
self.init.setEnabled(True)
|
||||
self.output.setEnabled(True)
|
||||
self.init_files.setEnabled(True)
|
||||
self.file_generated_by_enkf.setEnabled(True)
|
||||
self.file_loaded_by_enkf.setEnabled(True)
|
||||
self.min_std.setEnabled(True)
|
||||
|
||||
if value == field_type.ECLIPSE_RESTART:
|
||||
self.init.setEnabled(False)
|
||||
self.output.setEnabled(False)
|
||||
self.init_files.setEnabled(False)
|
||||
self.file_generated_by_enkf.setEnabled(False)
|
||||
self.file_loaded_by_enkf.setEnabled(False)
|
||||
self.min_std.setEnabled(False)
|
||||
|
||||
elif value == field_type.ECLIPSE_PARAMETER:
|
||||
self.file_loaded_by_enkf.setEnabled(False)
|
||||
|
||||
def setFieldModel(self, fieldModel):
|
||||
self.fieldModel = fieldModel
|
||||
|
||||
self.fieldType.fetchContent()
|
||||
self.min.fetchContent()
|
||||
self.max.fetchContent()
|
||||
self.init.fetchContent()
|
||||
self.output.fetchContent()
|
||||
self.init_files.fetchContent()
|
||||
self.file_generated_by_enkf.fetchContent()
|
||||
self.file_loaded_by_enkf.fetchContent()
|
||||
self.min_std.fetchContent()
|
||||
@@ -1,84 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'keywordpanel.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from ert_gui.widgets.combochoice import ComboChoice
|
||||
from ert_gui.widgets.stringbox import DoubleBox
|
||||
from ert_gui.widgets.pathchooser import PathChooser
|
||||
from parametermodels import KeywordModel
|
||||
from ert_gui.widgets.helpedwidget import ContentModel
|
||||
|
||||
class KeywordPanel(QtGui.QFrame):
|
||||
def __init__(self, parent):
|
||||
QtGui.QFrame.__init__(self, parent)
|
||||
|
||||
self.setFrameShape(QtGui.QFrame.StyledPanel)
|
||||
self.setFrameShadow(QtGui.QFrame.Plain)
|
||||
self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
|
||||
|
||||
layout = QtGui.QFormLayout()
|
||||
layout.setLabelAlignment(QtCore.Qt.AlignRight)
|
||||
|
||||
self.keywordModel = KeywordModel("")
|
||||
|
||||
self.min_std = PathChooser(self, "", "config/ensemble/gen_kw_min_std", True , must_be_set = False)
|
||||
self.modelWrap(self.min_std, "min_std")
|
||||
|
||||
self.template = PathChooser(self, "", "config/ensemble/gen_kw_template", True)
|
||||
self.modelWrap(self.template, "template")
|
||||
|
||||
self.enkf_outfile = PathChooser(self, "", "config/ensemble/gen_kw_enkf_outfile", True, must_be_set=False)
|
||||
self.modelWrap(self.enkf_outfile, "enkf_outfile")
|
||||
|
||||
self.init_files = PathChooser(self, "", "config/ensemble/gen_kw_init_files", True, must_be_set=False)
|
||||
self.modelWrap(self.init_files, "init_files")
|
||||
|
||||
self.parameter_file = PathChooser(self, "", "config/ensemble/gen_kw_parameter_file", True, must_be_set=False)
|
||||
self.modelWrap(self.parameter_file, "parameter_file")
|
||||
|
||||
layout.addRow("Parameter file:" , self.parameter_file)
|
||||
layout.addRow("Include file:" , self.enkf_outfile)
|
||||
layout.addRow("Template:" , self.template)
|
||||
layout.addRow("Minimum std:" , self.min_std)
|
||||
layout.addRow("Init files:" , self.init_files)
|
||||
|
||||
button = QtGui.QPushButton()
|
||||
button.setText("Reload")
|
||||
button.setMaximumWidth(70)
|
||||
self.connect(button, QtCore.SIGNAL('clicked()'), self._reload)
|
||||
|
||||
layout.addRow("Reload files:", button)
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
def _reload(self):
|
||||
self.keywordModel.emitUpdate()
|
||||
|
||||
def setKeywordModel(self, keywordModel):
|
||||
self.keywordModel = keywordModel
|
||||
|
||||
self.min_std.fetchContent()
|
||||
self.template.fetchContent()
|
||||
self.enkf_outfile.fetchContent()
|
||||
self.init_files.fetchContent()
|
||||
self.parameter_file.fetchContent()
|
||||
|
||||
def modelWrap(self, widget, attribute):
|
||||
widget.initialize = ContentModel.emptyInitializer
|
||||
widget.setter = lambda model, value: self.keywordModel.set(attribute, value)
|
||||
widget.getter = lambda model: self.keywordModel[attribute]
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'parameterdialog.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from ert_gui.widgets.validateddialog import ValidatedDialog
|
||||
|
||||
class ParameterDialog(ValidatedDialog):
|
||||
"""A dialog for creating parameters based on type and name. Performs validation of name."""
|
||||
|
||||
def __init__(self, parent, types, uniqueNames):
|
||||
"""Creates a new dialog that validates uniqueness against the provided list"""
|
||||
ValidatedDialog.__init__(self, parent, 'Create new parameter', "Select type and enter name of parameter:", uniqueNames)
|
||||
|
||||
self.paramCombo = QtGui.QComboBox(self)
|
||||
|
||||
keys = types.keys()
|
||||
keys.sort()
|
||||
for key in keys:
|
||||
self.paramCombo.addItem(types[key], key.name)
|
||||
|
||||
self.layout.insertRow(2, "Type:", self.paramCombo)
|
||||
|
||||
|
||||
def getTypeName(self):
|
||||
"""Return the type selected by the user"""
|
||||
return str(self.paramCombo.currentText()).strip()
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'parametermodels.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from ert.ert.enums import enkf_impl_type, field_type
|
||||
from PyQt4.QtCore import QObject
|
||||
from PyQt4.Qt import SIGNAL
|
||||
|
||||
class Model(QObject):
|
||||
|
||||
def __init__(self, name):
|
||||
QObject.__init__(self)
|
||||
self.name = name
|
||||
self.data = {}
|
||||
self.valid = True
|
||||
|
||||
def set(self, attr, value):
|
||||
self[attr] = value
|
||||
|
||||
def __setitem__(self, attr, value):
|
||||
self.data[attr] = value
|
||||
self.emitUpdate()
|
||||
|
||||
|
||||
def __getitem__(self, item):
|
||||
return self.data[item]
|
||||
|
||||
def isValid(self):
|
||||
return self.valid
|
||||
|
||||
def setValid(self, valid):
|
||||
if not self.valid == valid:
|
||||
self.valid = valid
|
||||
self.emitUpdate()
|
||||
|
||||
def emitUpdate(self):
|
||||
self.emit(SIGNAL("modelChanged(Model)"), self)
|
||||
|
||||
|
||||
def getName(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class FieldModel(Model):
|
||||
TYPE = enkf_impl_type.FIELD
|
||||
|
||||
def __init__(self, name):
|
||||
Model.__init__(self, name)
|
||||
self.name = name
|
||||
|
||||
self["type"] = field_type.GENERAL
|
||||
self["min"] = ""
|
||||
self["max"] = ""
|
||||
self["init"] = "None"
|
||||
self["output"] = "None"
|
||||
self["init_files"] = ""
|
||||
self["enkf_outfile"] = ""
|
||||
self["enkf_infile"] = ""
|
||||
self["min_std"] = ""
|
||||
|
||||
class KeywordModel(Model):
|
||||
TYPE = enkf_impl_type.GEN_KW
|
||||
|
||||
def __init__(self, name):
|
||||
Model.__init__(self, name)
|
||||
self.name = name
|
||||
|
||||
self["min_std"] = ""
|
||||
self["enkf_outfile"] = ""
|
||||
self["template"] = ""
|
||||
self["init_files"] = ""
|
||||
self["parameter_file"] = ""
|
||||
|
||||
class DataModel(Model):
|
||||
TYPE = enkf_impl_type.GEN_DATA
|
||||
|
||||
def __init__(self, name):
|
||||
Model.__init__(self, name)
|
||||
self.name = name
|
||||
|
||||
self["input_format"] = ""
|
||||
self["output_format"] = ""
|
||||
self["template_file"] = ""
|
||||
self["template_key"] = ""
|
||||
self["init_file_fmt"] = ""
|
||||
self["enkf_outfile"] = ""
|
||||
self["enkf_infile"] = ""
|
||||
self["min_std"] = ""
|
||||
|
||||
class SummaryModel(Model):
|
||||
TYPE = enkf_impl_type.SUMMARY
|
||||
|
||||
def __init__(self, name):
|
||||
Model.__init__(self, name)
|
||||
self.name = name
|
||||
@@ -1,219 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'parameterpanel.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
|
||||
from ert_gui.widgets.helpedwidget import *
|
||||
from ert_gui.widgets.tablewidgets import AddRemoveWidget
|
||||
from ert_gui.widgets import util
|
||||
from ert_gui.widgets.pathchooser import PathChooser
|
||||
from ert_gui.widgets.combochoice import ComboChoice
|
||||
import ert_gui.widgets.stringbox
|
||||
from fieldpanel import *
|
||||
from parameterdialog import ParameterDialog
|
||||
from ert_gui.widgets.searchablelist import SearchableList
|
||||
from datapanel import DataPanel
|
||||
from keywordpanel import KeywordPanel
|
||||
import ert_gui.widgets.util
|
||||
from parametermodels import SummaryModel, FieldModel, DataModel, KeywordModel
|
||||
from PyQt4.QtCore import SIGNAL
|
||||
|
||||
class ParameterPanel(HelpedWidget):
|
||||
"""Shows a widget for parameters. The data structure expected and sent to the getter and setter is an array of Parameters."""
|
||||
|
||||
def __init__(self, parent=None, label="", help=""):
|
||||
"""Construct a ParameterPanel."""
|
||||
HelpedWidget.__init__(self, parent, label, help)
|
||||
|
||||
self.searchableList = SearchableList(converter=lambda item : item.getName(), list_width=175)
|
||||
self.addWidget(self.searchableList)
|
||||
|
||||
|
||||
self.pagesWidget = QtGui.QStackedWidget()
|
||||
|
||||
self.emptyPanel = ert_gui.widgets.util.createEmptyPanel()
|
||||
|
||||
self.fieldPanel = FieldPanel(self)
|
||||
self.dataPanel = DataPanel(self)
|
||||
self.keywordPanel = KeywordPanel(self)
|
||||
|
||||
self.pagesWidget.addWidget(self.emptyPanel)
|
||||
self.pagesWidget.addWidget(self.fieldPanel)
|
||||
self.pagesWidget.addWidget(self.dataPanel)
|
||||
self.pagesWidget.addWidget(self.keywordPanel)
|
||||
|
||||
self.addWidget(self.pagesWidget)
|
||||
|
||||
self.connect(self.searchableList, QtCore.SIGNAL('currentItemChanged(QListWidgetItem, QListWidgetItem)'), self.changeParameter)
|
||||
self.connect(self.searchableList, QtCore.SIGNAL('addItem(list)'), self.addItem)
|
||||
self.connect(self.searchableList, QtCore.SIGNAL('removeItem(list)'), self.removeItem)
|
||||
|
||||
#self.addHelpButton()
|
||||
|
||||
|
||||
def changeParameter(self, current, previous):
|
||||
if not current:
|
||||
self.pagesWidget.setCurrentWidget(self.emptyPanel)
|
||||
elif FieldModel.TYPE == current.getType():
|
||||
self.pagesWidget.setCurrentWidget(self.fieldPanel)
|
||||
self.fieldPanel.setFieldModel(current.getUserData())
|
||||
elif DataModel.TYPE == current.getType():
|
||||
self.pagesWidget.setCurrentWidget(self.dataPanel)
|
||||
self.dataPanel.setDataModel(current.getUserData())
|
||||
elif KeywordModel.TYPE == current.getType():
|
||||
self.pagesWidget.setCurrentWidget(self.keywordPanel)
|
||||
self.keywordPanel.setKeywordModel(current.getUserData())
|
||||
else:
|
||||
self.pagesWidget.setCurrentWidget(self.emptyPanel)
|
||||
|
||||
|
||||
def createParameter(self, type_name, name):
|
||||
"""Adds a new parameter to the list"""
|
||||
|
||||
if type_name == FieldModel.TYPE.name:
|
||||
type = FieldModel.TYPE
|
||||
data = FieldModel(name)
|
||||
elif type_name == DataModel.TYPE.name:
|
||||
type = DataModel.TYPE
|
||||
data = DataModel(name)
|
||||
elif type_name == KeywordModel.TYPE.name:
|
||||
type = KeywordModel.TYPE
|
||||
data = KeywordModel(name)
|
||||
elif type_name == SummaryModel.TYPE.name:
|
||||
type = SummaryModel.TYPE
|
||||
data = SummaryModel(name)
|
||||
else:
|
||||
raise AssertionError("Type name unknown: %s" % (type_name))
|
||||
|
||||
param = Parameter(name, type)
|
||||
param.setUserData(data)
|
||||
param.setValid(False)
|
||||
return param
|
||||
|
||||
|
||||
def addToList(self, list, parameter):
|
||||
list.addItem(parameter)
|
||||
list.setCurrentItem(parameter)
|
||||
|
||||
user_data = parameter.getUserData()
|
||||
self.connect(user_data, SIGNAL('modelChanged(Model)'), self.modelChanged)
|
||||
|
||||
def modelChanged(self, parameter_model):
|
||||
"""Called whenever the content of a model changes"""
|
||||
self.updateContent(parameter_model)
|
||||
|
||||
|
||||
def addItem(self, list):
|
||||
"""Called by the add button to insert a new parameter. A Parameter object is sent to the ContentModel inserter"""
|
||||
uniqueNames = []
|
||||
for index in range(list.count()):
|
||||
uniqueNames.append(str(list.item(index).text()))
|
||||
|
||||
pd = ParameterDialog(self, Parameter.typeIcons, uniqueNames)
|
||||
if pd.exec_():
|
||||
parameter = self.createParameter(pd.getTypeName(), pd.getName())
|
||||
ok = self.updateContent(parameter, operation=ContentModel.INSERT)
|
||||
if ok:
|
||||
self.addToList(list, parameter)
|
||||
|
||||
# todo: emit when a new field is added also make initandcopy listen -> self.modelEmit("casesUpdated()")
|
||||
|
||||
|
||||
def removeItem(self, list):
|
||||
"""Called by the remove button to remove a selected parameter. The key is forwarded to the ContentModel remover"""
|
||||
currentRow = list.currentRow()
|
||||
|
||||
if currentRow >= 0:
|
||||
doDelete = QtGui.QMessageBox.question(self, "Delete parameter?", "Are you sure you want to delete the parameter?", QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
|
||||
|
||||
if doDelete == QtGui.QMessageBox.Yes:
|
||||
item = list.item(currentRow)
|
||||
user_data = item.getUserData()
|
||||
self.disconnect(user_data, SIGNAL('modelChanged(Model)'), self.modelChanged)
|
||||
self.updateContent(item.getName(), operation=ContentModel.REMOVE)
|
||||
list.takeItem(currentRow)
|
||||
#todo: emit change
|
||||
|
||||
def fetchContent(self):
|
||||
"""Retrieves data from the model and inserts it into the list"""
|
||||
parameters = self.getFromModel()
|
||||
|
||||
for parameter in parameters:
|
||||
if parameter is None:
|
||||
raise AssertionError("Unknown type name!")
|
||||
|
||||
param = Parameter(parameter.name, parameter.TYPE)
|
||||
param.setUserData(parameter)
|
||||
param.setValid(parameter.isValid())
|
||||
|
||||
self.addToList(self.searchableList.getList(), param)
|
||||
|
||||
if self.searchableList.getList().count > 0:
|
||||
self.searchableList.getList().setCurrentRow(0)
|
||||
|
||||
|
||||
class Parameter(QtGui.QListWidgetItem):
|
||||
"""ListWidgetItem class that represents a Parameter with an associated icon."""
|
||||
typeIcons = {FieldModel.TYPE: util.resourceIcon("grid_16"),
|
||||
DataModel.TYPE: util.resourceIcon("data"),
|
||||
SummaryModel.TYPE: util.resourceIcon("summary"),
|
||||
KeywordModel.TYPE: util.resourceIcon("key")}
|
||||
|
||||
|
||||
def __init__(self, name, type, icon=None):
|
||||
if icon is None:
|
||||
icon = Parameter.typeIcons[type]
|
||||
|
||||
QtGui.QListWidgetItem.__init__(self, icon, name)
|
||||
self.type = type
|
||||
self.name = name
|
||||
self.user_data = None
|
||||
self.setValid(True)
|
||||
|
||||
def getType(self):
|
||||
"""Retruns the type of this parameter"""
|
||||
return self.type
|
||||
|
||||
def getName(self):
|
||||
"""Returns the name of this parameter (keyword)"""
|
||||
return self.name
|
||||
|
||||
def __ge__(self, other):
|
||||
if self.type.name == other.type.name:
|
||||
return self.name.lower() >= other.name.lower()
|
||||
else:
|
||||
return self.type.name >= other.type.name
|
||||
|
||||
def __lt__(self, other):
|
||||
return not self >= other
|
||||
|
||||
def setUserData(self, data):
|
||||
"""Set user data for this parameter."""
|
||||
self.user_data = data
|
||||
|
||||
def getUserData(self):
|
||||
"""Retrieve the user data."""
|
||||
return self.user_data
|
||||
|
||||
def setValid(self, valid):
|
||||
"""Set the validity of this item. An invalid item is colored red"""
|
||||
self.valid = valid
|
||||
|
||||
if valid:
|
||||
self.setBackgroundColor(QtCore.Qt.white)
|
||||
else:
|
||||
self.setBackgroundColor(HelpedWidget.STRONG_ERROR_COLOR)
|
||||
@@ -1,58 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'plot.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------------------------
|
||||
# Plot tab
|
||||
# ----------------------------------------------------------------------------------------------
|
||||
from ert_gui.widgets.pathchooser import PathChooser
|
||||
from ert_gui.widgets.combochoice import ComboChoice
|
||||
from ert_gui.widgets.spinnerwidgets import IntegerSpinner
|
||||
|
||||
|
||||
def createPlotPage(configPanel, parent):
|
||||
configPanel.startPage("Plot")
|
||||
|
||||
r = configPanel.addRow(PathChooser(parent, "Output path", "config/plot/path"))
|
||||
r.getter = lambda ert : ert.enkf.plot_config_get_path(ert.plot_config)
|
||||
r.setter = lambda ert, value : ert.enkf.plot_config_set_path(ert.plot_config, str(value))
|
||||
|
||||
r = configPanel.addRow(ComboChoice(parent, ["PLPLOT", "TEXT"], "Driver", "config/plot/plot_driver"))
|
||||
r.getter = lambda ert : ert.enkf.plot_config_get_driver(ert.plot_config)
|
||||
r.setter = lambda ert, value : ert.enkf.plot_config_set_driver(ert.plot_config, str(value))
|
||||
|
||||
r = configPanel.addRow(IntegerSpinner(parent, "Errorbar max", "config/plot/plot_errorbar_max", 1, 10000000))
|
||||
r.getter = lambda ert : ert.enkf.plot_config_get_errorbar_max(ert.plot_config)
|
||||
r.setter = lambda ert, value : ert.enkf.plot_config_set_errorbar_max(ert.plot_config, value)
|
||||
|
||||
r = configPanel.addRow(IntegerSpinner(parent, "Width", "config/plot/width", 1, 10000))
|
||||
r.getter = lambda ert : ert.enkf.plot_config_get_width(ert.plot_config)
|
||||
r.setter = lambda ert, value : ert.enkf.plot_config_set_width(ert.plot_config, value)
|
||||
|
||||
r = configPanel.addRow(IntegerSpinner(parent, "Height", "config/plot/plot_height", 1, 10000))
|
||||
r.getter = lambda ert : ert.enkf.plot_config_get_height(ert.plot_config)
|
||||
r.setter = lambda ert, value : ert.enkf.plot_config_set_height(ert.plot_config, value)
|
||||
|
||||
r = configPanel.addRow(PathChooser(parent, "Image Viewer", "config/plot/image_viewer", True))
|
||||
r.getter = lambda ert : ert.enkf.plot_config_get_viewer(ert.plot_config)
|
||||
r.setter = lambda ert, value : ert.enkf.plot_config_set_viewer(ert.plot_config, str(value))
|
||||
|
||||
r = configPanel.addRow(ComboChoice(parent, ["bmp", "jpg", "png", "tif"], "Image type", "config/plot/image_type"))
|
||||
r.getter = lambda ert : ert.enkf.plot_config_get_image_type(ert.plot_config)
|
||||
r.setter = lambda ert, value : ert.enkf.plot_config_set_image_type(ert.plot_config, str(value))
|
||||
|
||||
|
||||
configPanel.endPage()
|
||||
@@ -1,93 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'queuesystem.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------------------------
|
||||
# Queue System tab
|
||||
# ----------------------------------------------------------------------------------------------
|
||||
from ert_gui.widgets.configpanel import ConfigPanel
|
||||
from ert_gui.widgets.combochoice import ComboChoice
|
||||
from ert_gui.widgets.stringbox import StringBox
|
||||
from ert_gui.widgets.pathchooser import PathChooser
|
||||
from ert_gui.widgets.spinnerwidgets import IntegerSpinner
|
||||
from ert_gui.widgets.tablewidgets import KeywordTable
|
||||
|
||||
def createQueueSystemPage(configPanel, parent):
|
||||
configPanel.startPage("Queue System")
|
||||
|
||||
r = configPanel.addRow(ComboChoice(parent, ["LSF", "RSH", "LOCAL"], "Queue system", "config/queue_system/queue_system"))
|
||||
r.getter = lambda ert : ert.enkf.site_config_get_queue_name(ert.site_config)
|
||||
r.setter = lambda ert, value : ert.enkf.site_config_set_job_queue(ert.site_config, str(value))
|
||||
|
||||
internalPanel = ConfigPanel(parent)
|
||||
|
||||
internalPanel.startPage("LSF")
|
||||
|
||||
r = internalPanel.addRow(StringBox(parent, "LSF Queue", "config/queue_system/lsf_queue"))
|
||||
r.getter = lambda ert : ert.enkf.site_config_get_lsf_queue(ert.site_config)
|
||||
r.setter = lambda ert, value : ert.enkf.site_config_set_lsf_queue(ert.site_config, str(value))
|
||||
|
||||
r = internalPanel.addRow(IntegerSpinner(parent, "Max running", "config/queue_system/max_running_lsf", 1, 1000))
|
||||
r.getter = lambda ert : ert.enkf.site_config_get_max_running_lsf(ert.site_config)
|
||||
r.setter = lambda ert, value : ert.enkf.site_config_set_max_running_lsf(ert.site_config, value)
|
||||
|
||||
r = internalPanel.addRow(StringBox(parent, "Resources", "config/queue_system/lsf_resources"))
|
||||
r.getter = lambda ert : ert.enkf.site_config_get_lsf_request(ert.site_config)
|
||||
r.setter = lambda ert, value : ert.enkf.site_config_set_lsf_request(ert.site_config, str(value))
|
||||
|
||||
internalPanel.endPage()
|
||||
|
||||
|
||||
internalPanel.startPage("RSH")
|
||||
|
||||
r = internalPanel.addRow(PathChooser(parent, "Command", "config/queue_system/rsh_command", show_files=True, must_exist=True, is_executable_file=True))
|
||||
r.getter = lambda ert : ert.enkf.site_config_get_rsh_command(ert.site_config)
|
||||
r.setter = lambda ert, value : ert.enkf.site_config_set_rsh_command(ert.site_config, str(value))
|
||||
|
||||
r = internalPanel.addRow(IntegerSpinner(parent, "Max running", "config/queue_system/max_running_rsh", 1, 1000))
|
||||
r.getter = lambda ert : ert.enkf.site_config_get_max_running_rsh(ert.site_config)
|
||||
r.setter = lambda ert, value : ert.enkf.site_config_set_max_running_rsh(ert.site_config, value)
|
||||
|
||||
|
||||
r = internalPanel.addRow(KeywordTable(parent, "Host List", "config/queue_system/rsh_host_list", "Host", "Number of jobs"))
|
||||
r.getter = lambda ert : ert.getHash(ert.enkf.site_config_get_rsh_host_list(ert.site_config), True)
|
||||
|
||||
def add_rsh_host(ert, listOfKeywords):
|
||||
ert.enkf.site_config_clear_rsh_host_list(ert.site_config)
|
||||
|
||||
for keyword in listOfKeywords:
|
||||
if keyword[1].strip() == "":
|
||||
max_running = 1
|
||||
else:
|
||||
max_running = int(keyword[1])
|
||||
|
||||
ert.enkf.site_config_add_rsh_host(ert.site_config, keyword[0], max_running)
|
||||
|
||||
r.setter = add_rsh_host
|
||||
|
||||
|
||||
internalPanel.endPage()
|
||||
|
||||
internalPanel.startPage("LOCAL")
|
||||
|
||||
r = internalPanel.addRow(IntegerSpinner(parent, "Max running", "config/queue_system/max_running_local", 1, 1000))
|
||||
r.getter = lambda ert : ert.enkf.site_config_get_max_running_local(ert.site_config)
|
||||
r.setter = lambda ert, value : ert.enkf.site_config_set_max_running_local(ert.site_config, value)
|
||||
|
||||
internalPanel.endPage()
|
||||
configPanel.addRow(internalPanel)
|
||||
|
||||
configPanel.endPage()
|
||||
@@ -1,197 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'simulation.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------------------------
|
||||
# Simulations tab
|
||||
# ----------------------------------------------------------------------------------------------
|
||||
from PyQt4 import QtCore
|
||||
from ert_gui.widgets.spinnerwidgets import IntegerSpinner
|
||||
from ert_gui.widgets.tablewidgets import KeywordTable
|
||||
from ert_gui.widgets.pathchooser import PathChooser
|
||||
from ert_gui.widgets.checkbox import CheckBox
|
||||
from ert_gui.widgets.configpanel import ConfigPanel
|
||||
from ert_gui.widgets.stringbox import StringBox
|
||||
from jobs.forwardmodelpanel import ForwardModelPanel
|
||||
from simulations.runpathpanel import RunpathMemberList, RunpathMemberPanel
|
||||
from ert.ert.enums import keep_runpath_type
|
||||
from simulations.runtemplatepanel import RunTemplatePanel
|
||||
import ert_gui.widgets.helpedwidget
|
||||
import os
|
||||
|
||||
def createSimulationsPage(configPanel, parent):
|
||||
configPanel.startPage("Simulations")
|
||||
|
||||
|
||||
r = configPanel.addRow(IntegerSpinner(parent, "Max submit", "config/simulation/max_submit", 1, 10000))
|
||||
r.getter = lambda ert : ert.enkf.site_config_get_max_submit(ert.site_config)
|
||||
r.setter = lambda ert, value : ert.enkf.site_config_set_max_submit(ert.site_config, value)
|
||||
|
||||
r = configPanel.addRow(IntegerSpinner(parent, "Max resample", "config/simulation/max_resample", 1, 10000))
|
||||
r.getter = lambda ert : ert.enkf.model_config_get_max_resample(ert.model_config)
|
||||
r.setter = lambda ert, value : ert.enkf.model_config_set_max_resample(ert.model_config, value)
|
||||
|
||||
|
||||
|
||||
r = configPanel.addRow(ForwardModelPanel(parent))
|
||||
|
||||
|
||||
def get_forward_model(ert):
|
||||
site_config = ert.site_config
|
||||
installed_jobs_pointer = ert.enkf.site_config_get_installed_jobs(site_config)
|
||||
installed_jobs_stringlist_pointer = ert.job_queue.ext_joblist_alloc_list(installed_jobs_pointer)
|
||||
available_jobs = ert.getStringList(installed_jobs_stringlist_pointer , free_after_use=True)
|
||||
|
||||
result = {'available_jobs': available_jobs}
|
||||
|
||||
model_config = ert.model_config
|
||||
forward_model = ert.enkf.model_config_get_forward_model(model_config)
|
||||
name_string_list = ert.job_queue.forward_model_alloc_joblist(forward_model)
|
||||
job_names = ert.getStringList(name_string_list, free_after_use=True)
|
||||
|
||||
forward_model_jobs = []
|
||||
|
||||
count = 0
|
||||
for name in job_names:
|
||||
ext_job = ert.job_queue.forward_model_iget_job(forward_model, count)
|
||||
arg_string = ert.job_queue.ext_job_get_private_args_as_string(ext_job)
|
||||
help_text = ert.job_queue.ext_job_get_help_text(ext_job)
|
||||
forward_model_jobs.append((name, arg_string, help_text))
|
||||
count+=1
|
||||
|
||||
result['forward_model'] = forward_model_jobs
|
||||
|
||||
return result
|
||||
|
||||
r.getter = get_forward_model
|
||||
|
||||
def update_forward_model(ert, forward_model):
|
||||
forward_model_pointer = ert.enkf.model_config_get_forward_model(ert.model_config)
|
||||
ert.job_queue.forward_model_clear(forward_model_pointer)
|
||||
|
||||
for job in forward_model:
|
||||
name = job[0]
|
||||
args = job[1]
|
||||
ext_job = ert.job_queue.forward_model_add_job(forward_model_pointer, name)
|
||||
ert.job_queue.ext_job_set_private_args_from_string(ext_job, args)
|
||||
|
||||
r.setter = update_forward_model
|
||||
|
||||
|
||||
|
||||
r = configPanel.addRow(PathChooser(parent, "Case table", "config/simulation/case_table"))
|
||||
|
||||
|
||||
def get_case_table(ert):
|
||||
return ert.enkf.model_config_get_case_table_file(ert.model_config)
|
||||
r.getter = get_case_table
|
||||
|
||||
def set_case_table(ert, value):
|
||||
if os.path.exists(value):
|
||||
ert.enkf.enkf_main_set_case_table(ert.model_config, ert.nonify(value))
|
||||
r.setter = set_case_table
|
||||
|
||||
|
||||
r = configPanel.addRow(PathChooser(parent, "License path", "config/simulation/license_path"))
|
||||
r.getter = lambda ert : ert.enkf.site_config_get_license_root_path(ert.site_config)
|
||||
|
||||
def ls(string):
|
||||
if string is None:
|
||||
return ""
|
||||
else:
|
||||
return string
|
||||
|
||||
r.setter = lambda ert, value : ert.enkf.site_config_set_license_root_path(ert.site_config, ls(value))
|
||||
|
||||
|
||||
|
||||
internalPanel = ConfigPanel(parent)
|
||||
|
||||
internalPanel.startPage("Runpath")
|
||||
|
||||
r = internalPanel.addRow(PathChooser(parent, "Runpath", "config/simulation/runpath", path_format=True))
|
||||
|
||||
r.getter = lambda ert : ert.enkf.model_config_get_runpath_as_char(ert.model_config)
|
||||
r.setter = lambda ert, value : ert.enkf.model_config_set_runpath_fmt(ert.model_config, str(value))
|
||||
parent.connect(r, QtCore.SIGNAL("contentsChanged()"), lambda : r.modelEmit("runpathChanged()"))
|
||||
|
||||
|
||||
r = internalPanel.addRow(CheckBox(parent, "Pre clear", "config/simulation/pre_clear_runpath", "Perform pre clear"))
|
||||
|
||||
r.getter = lambda ert : ert.enkf.enkf_main_get_pre_clear_runpath(ert.main)
|
||||
r.setter = lambda ert, value : ert.enkf.enkf_main_set_pre_clear_runpath(ert.main, value)
|
||||
|
||||
|
||||
r = internalPanel.addRow(RunpathMemberPanel(widgetLabel="Retain runpath", helpLabel="config/simulation/runpath_retain"))
|
||||
def get_runpath_retain_state(ert):
|
||||
ensemble_size = ert.enkf.enkf_main_get_ensemble_size(ert.main)
|
||||
|
||||
result = []
|
||||
for index in range(ensemble_size):
|
||||
state = ert.enkf.enkf_main_iget_keep_runpath(ert.main, index)
|
||||
result.append((index, keep_runpath_type.resolveValue(state)))
|
||||
|
||||
return result
|
||||
|
||||
r.getter = get_runpath_retain_state
|
||||
|
||||
def set_runpath_retain_state(ert, items):
|
||||
for item in items:
|
||||
ert.enkf.enkf_main_iset_keep_runpath(ert.main, item.member, item.runpath_state.value())
|
||||
|
||||
r.setter = set_runpath_retain_state
|
||||
|
||||
|
||||
internalPanel.endPage()
|
||||
|
||||
internalPanel.startPage("Run Template")
|
||||
|
||||
r = internalPanel.addRow(RunTemplatePanel(parent))
|
||||
|
||||
def get_run_templates(ert):
|
||||
templates = ert.enkf.enkf_main_get_templates(ert.main)
|
||||
template_list = ert.enkf.ert_template_alloc_list(templates)
|
||||
|
||||
template_names = ert.getStringList(template_list, free_after_use=True)
|
||||
result = []
|
||||
for name in template_names:
|
||||
template = ert.enkf.ert_template_get_template(templates, name)
|
||||
template_file = ert.enkf.ert_template_get_template_file(template)
|
||||
target_file = ert.enkf.ert_template_get_target_file(template)
|
||||
arguments = ert.enkf.ert_template_get_args_as_string(template)
|
||||
result.append((name, template_file, target_file, arguments))
|
||||
return result
|
||||
|
||||
r.getter = get_run_templates
|
||||
|
||||
def set_run_templates(ert, template_list):
|
||||
templates_pointer = ert.enkf.enkf_main_get_templates(ert.main)
|
||||
ert.enkf.ert_template_clear(templates_pointer)
|
||||
|
||||
for template in template_list:
|
||||
ert.enkf.ert_template_add_template(templates_pointer, template[0], template[1], template[2], template[3])
|
||||
|
||||
r.setter = set_run_templates
|
||||
|
||||
# r = internalPanel.addRow(MultiColumnTable(parent, "", "run_template", ["Template", "Target file", "Arguments"]))
|
||||
# r.getter = lambda ert : ert.getAttribute("run_template")
|
||||
# r.setter = lambda ert, value : ert.setAttribute("run_template", value)
|
||||
|
||||
internalPanel.endPage()
|
||||
configPanel.addRow(internalPanel)
|
||||
|
||||
|
||||
configPanel.endPage()
|
||||
@@ -1,17 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file '__init__.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
@@ -1,175 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'runpathpanel.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from ert.ert.enums import keep_runpath_type
|
||||
from ert_gui.widgets.helpedwidget import HelpedWidget
|
||||
from ert_gui.pages.run.legend import Legend
|
||||
|
||||
class RunpathMemberList(QtGui.QListWidget):
|
||||
"""A list widget with custom items representing members"""
|
||||
def __init__(self):
|
||||
QtGui.QListWidget.__init__(self)
|
||||
|
||||
self.setViewMode(QtGui.QListView.IconMode)
|
||||
self.setMovement(QtGui.QListView.Static)
|
||||
self.setResizeMode(QtGui.QListView.Adjust)
|
||||
|
||||
self.setItemDelegate(RunpathMemberItemDelegate())
|
||||
self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
|
||||
self.setSelectionRectVisible(False)
|
||||
|
||||
self.setSortingEnabled(True)
|
||||
self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
|
||||
|
||||
|
||||
class RunpathMemberItem(QtGui.QListWidgetItem):
|
||||
"""Items for the custom SimulationList"""
|
||||
def __init__(self, member, runpath_state):
|
||||
self.runpath_state = runpath_state
|
||||
self.member = member
|
||||
QtGui.QListWidgetItem.__init__(self)
|
||||
self.setData(QtCore.Qt.DisplayRole, (member, runpath_state))
|
||||
|
||||
def __ge__(self, other):
|
||||
return self.member >= other.member
|
||||
|
||||
def __lt__(self, other):
|
||||
return not self >= other
|
||||
|
||||
def setState(self, state):
|
||||
self.runpath_state = state
|
||||
self.setData(QtCore.Qt.DisplayRole, (self.member, self.runpath_state))
|
||||
|
||||
|
||||
class RunpathMemberItemDelegate(QtGui.QStyledItemDelegate):
|
||||
"""The delegate that renders the custom RunpathMemberItems"""
|
||||
|
||||
default = QtGui.QColor(255, 255, 240)
|
||||
delete = QtGui.QColor(255, 200, 200)
|
||||
keep = QtGui.QColor(200, 255, 200)
|
||||
unknown = QtGui.QColor(255, 200, 64)
|
||||
|
||||
size = QtCore.QSize(32, 18)
|
||||
|
||||
def __init__(self):
|
||||
QtGui.QStyledItemDelegate.__init__(self)
|
||||
|
||||
def paint(self, painter, option, index):
|
||||
"""Renders the item"""
|
||||
painter.save()
|
||||
painter.setRenderHint(QtGui.QPainter.Antialiasing)
|
||||
|
||||
data = index.data(QtCore.Qt.DisplayRole)
|
||||
|
||||
if data is None:
|
||||
data = (0, keep_runpath_type.DEFAULT_KEEP)
|
||||
else:
|
||||
data = data.toPyObject()
|
||||
|
||||
if data[1] == keep_runpath_type.DEFAULT_KEEP:
|
||||
color = self.default
|
||||
elif data[1] == keep_runpath_type.EXPLICIT_KEEP:
|
||||
color = self.keep
|
||||
elif data[1] == keep_runpath_type.EXPLICIT_DELETE:
|
||||
color = self.delete
|
||||
else:
|
||||
color = self.unknown
|
||||
|
||||
painter.setPen(color)
|
||||
rect = QtCore.QRect(option.rect)
|
||||
rect.setX(rect.x() + 1)
|
||||
rect.setY(rect.y() + 1)
|
||||
rect.setWidth(rect.width() - 2)
|
||||
rect.setHeight(rect.height() - 2)
|
||||
painter.fillRect(rect, color)
|
||||
|
||||
painter.setPen(QtCore.Qt.black)
|
||||
|
||||
painter.setRenderHint(QtGui.QPainter.Antialiasing, False)
|
||||
painter.drawRect(rect)
|
||||
|
||||
if option.state & QtGui.QStyle.State_Selected:
|
||||
painter.fillRect(option.rect, QtGui.QColor(255, 255, 255, 150))
|
||||
|
||||
painter.drawText(rect, QtCore.Qt.AlignCenter + QtCore.Qt.AlignVCenter, str(data[0]))
|
||||
|
||||
painter.restore()
|
||||
|
||||
def sizeHint(self, option, index):
|
||||
"""Returns the size of the item"""
|
||||
return self.size
|
||||
|
||||
|
||||
class RunpathMemberPanel(HelpedWidget):
|
||||
"""A dialog that shows the progress of a simulation"""
|
||||
def __init__(self, parent=None, widgetLabel="", helpLabel=""):
|
||||
HelpedWidget.__init__(self, widgetLabel=widgetLabel, helpLabel=helpLabel)
|
||||
|
||||
layout = QtGui.QVBoxLayout()
|
||||
self.runpath_member_list = RunpathMemberList()
|
||||
self.runpath_member_list.contextMenuEvent = self._contextMenu
|
||||
layout.addWidget(self.runpath_member_list)
|
||||
#self.addWidget(self.runpath_member_list)
|
||||
#self.connect(self.runpath_member_list, QtCore.SIGNAL('itemSelectionChanged()'), self.ctrl.selectSimulation)
|
||||
|
||||
legendLayout = QtGui.QHBoxLayout()
|
||||
legendLayout.addLayout(Legend("Default", RunpathMemberItemDelegate.default))
|
||||
legendLayout.addLayout(Legend("Keep", RunpathMemberItemDelegate.keep))
|
||||
legendLayout.addLayout(Legend("Delete", RunpathMemberItemDelegate.delete))
|
||||
layout.addLayout(legendLayout)
|
||||
self.addLayout(layout)
|
||||
|
||||
self.addHelpButton()
|
||||
|
||||
|
||||
def _createAction(self, name, func, parent=None):
|
||||
"""Create an action for the right click menu"""
|
||||
action = QtGui.QAction(name, parent)
|
||||
action.connect(action, QtCore.SIGNAL("triggered()"), func)
|
||||
return action
|
||||
|
||||
def _contextMenu(self, event):
|
||||
"""Create a right click menu for the simulation view."""
|
||||
menu = QtGui.QMenu(self.runpath_member_list)
|
||||
selectAll = self._createAction("Select all", self.runpath_member_list.selectAll)
|
||||
unselectAll = self._createAction("Unselect all", self.runpath_member_list.clearSelection)
|
||||
defaultSelected = self._createAction("Default", lambda : self.setState(keep_runpath_type.DEFAULT_KEEP))
|
||||
keepSelected = self._createAction("Keep", lambda : self.setState(keep_runpath_type.EXPLICIT_KEEP))
|
||||
deleteSelected = self._createAction("Delete", lambda : self.setState(keep_runpath_type.EXPLICIT_DELETE))
|
||||
|
||||
menu.addAction(defaultSelected)
|
||||
menu.addAction(keepSelected)
|
||||
menu.addAction(deleteSelected)
|
||||
menu.addSeparator()
|
||||
menu.addAction(selectAll)
|
||||
menu.addAction(unselectAll)
|
||||
menu.exec_(event.globalPos())
|
||||
|
||||
def fetchContent(self):
|
||||
data = self.getFromModel()
|
||||
self.runpath_member_list.clear()
|
||||
|
||||
for item in data:
|
||||
self.runpath_member_list.addItem(RunpathMemberItem(item[0], item[1]))
|
||||
|
||||
def setState(self, state):
|
||||
items = self.runpath_member_list.selectedItems()
|
||||
for item in items:
|
||||
item.setState(state)
|
||||
|
||||
self.updateContent(items)
|
||||
@@ -1,213 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'runtemplatepanel.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from ert_gui.widgets.helpedwidget import HelpedWidget
|
||||
from ert_gui.widgets.searchablelist import SearchableList
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from ert_gui.widgets.pathchooser import PathChooser
|
||||
from ert_gui.widgets.validateddialog import ValidatedDialog
|
||||
import ert_gui.widgets.util
|
||||
import os
|
||||
from ert_gui.widgets.util import ValidationInfo
|
||||
from ert_gui.pages.config.jobs.jobsdialog import EditJobDialog
|
||||
from ert_gui.widgets.stringbox import StringBox
|
||||
from ert_gui.widgets.helpedwidget import ContentModel
|
||||
|
||||
class RunTemplatePanel(HelpedWidget):
|
||||
"""
|
||||
Widget for adding, removing and editing run templates.
|
||||
"""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
HelpedWidget.__init__(self, parent, "", "config/simulation/run_template")
|
||||
|
||||
self.run_template = RunTemplate("undefined", "", "", "")
|
||||
|
||||
self.createWidgets(parent)
|
||||
|
||||
self.emptyPanel = ert_gui.widgets.util.createEmptyPanel()
|
||||
|
||||
self.pagesWidget = QtGui.QStackedWidget()
|
||||
self.pagesWidget.addWidget(self.emptyPanel)
|
||||
self.pagesWidget.addWidget(self.run_template_panel)
|
||||
self.addWidget(self.pagesWidget)
|
||||
|
||||
self.addHelpButton()
|
||||
|
||||
def createWidgets(self, parent):
|
||||
self.searchableList = SearchableList(parent, list_height=150, list_width=150, ignore_case=True)
|
||||
self.addWidget(self.searchableList)
|
||||
self.connect(self.searchableList, QtCore.SIGNAL('currentItemChanged(QListWidgetItem, QListWidgetItem)'),
|
||||
self.changeParameter)
|
||||
self.connect(self.searchableList, QtCore.SIGNAL('addItem(list)'), self.addItem)
|
||||
self.connect(self.searchableList, QtCore.SIGNAL('removeItem(list)'), self.removeItem)
|
||||
|
||||
|
||||
self.run_template_panel = ert_gui.widgets.util.createEmptyPanel()
|
||||
|
||||
layout = QtGui.QFormLayout()
|
||||
layout.setLabelAlignment(QtCore.Qt.AlignRight)
|
||||
|
||||
self.run_template_file = PathChooser(self, "", "config/simulation/run_template_file", show_files=True)
|
||||
self.run_template_file.initialize = ContentModel.emptyInitializer
|
||||
self.run_template_file.setter = self.setTemplateFile
|
||||
self.run_template_file.getter = lambda model: self.run_template.template_file
|
||||
|
||||
self.run_template_target = PathChooser(self, "", "config/simulation/run_template_target", show_files=True)
|
||||
self.run_template_target.initialize = ContentModel.emptyInitializer
|
||||
self.run_template_target.setter = self.setTargetFile
|
||||
self.run_template_target.getter = lambda model: self.run_template.target_file
|
||||
|
||||
self.run_template_args = StringBox(self, "", "config/simulation/run_template_arguments")
|
||||
self.run_template_args.initialize = ContentModel.emptyInitializer
|
||||
self.run_template_args.setter = self.setArguments
|
||||
self.run_template_args.getter = lambda model: self.run_template.arguments
|
||||
|
||||
layout.addRow("Template file:", self.run_template_file)
|
||||
layout.addRow("Target file:", self.run_template_target)
|
||||
layout.addRow("Arguments:", self.run_template_args)
|
||||
|
||||
layout.addRow(ert_gui.widgets.util.createSpace(20))
|
||||
|
||||
self.run_template_panel.setLayout(layout)
|
||||
|
||||
def setArguments(self, model, arguments):
|
||||
self.run_template.setArguments(arguments)
|
||||
self.runTemplateChanged()
|
||||
|
||||
def setTemplateFile(self, model, template_file):
|
||||
self.run_template.setTemplateFile(template_file)
|
||||
self.runTemplateChanged()
|
||||
|
||||
def setTargetFile(self, model, target_file):
|
||||
self.run_template.setTargetFile(target_file)
|
||||
self.runTemplateChanged()
|
||||
|
||||
|
||||
def fetchContent(self):
|
||||
"""
|
||||
Retrieves data from the model and inserts it into the widget.
|
||||
List of tuples: (name, template_file, target_file, arguments)
|
||||
"""
|
||||
data = self.getFromModel()
|
||||
|
||||
self.searchableList.list.clear()
|
||||
for item in data:
|
||||
jobitem = QtGui.QListWidgetItem()
|
||||
jobitem.setText(item[0])
|
||||
run_template = RunTemplate(item[0], item[1], item[2], item[3])
|
||||
|
||||
jobitem.setData(QtCore.Qt.UserRole, run_template)
|
||||
jobitem.setToolTip(item[0])
|
||||
self.searchableList.list.addItem(jobitem)
|
||||
|
||||
def setRunTemplate(self, run_template):
|
||||
"""Set the current visible run template"""
|
||||
self.run_template = run_template
|
||||
self.run_template_args.fetchContent()
|
||||
self.run_template_file.fetchContent()
|
||||
self.run_template_target.fetchContent()
|
||||
|
||||
def changeParameter(self, current, previous):
|
||||
"""Switch between run templates. Selection from the list"""
|
||||
if current is None:
|
||||
self.pagesWidget.setCurrentWidget(self.emptyPanel)
|
||||
else:
|
||||
self.pagesWidget.setCurrentWidget(self.run_template_panel)
|
||||
self.setRunTemplate(current.data(QtCore.Qt.UserRole).toPyObject())
|
||||
|
||||
def runTemplateChanged(self):
|
||||
"""
|
||||
Called whenever the run template is changed. (adding, removing)
|
||||
The data submitted to the updateContent() (from ContentModel) is a list of tuples (name, template_file, target_file, arguments)
|
||||
"""
|
||||
items = self.searchableList.getItems()
|
||||
currentRow = self.searchableList.list.currentRow()
|
||||
run_templates = []
|
||||
for item in items:
|
||||
r_t = item.data(QtCore.Qt.UserRole).toPyObject()
|
||||
run_template_tuple = (r_t.name, r_t.template_file, r_t.target_file, r_t.arguments)
|
||||
run_templates.append(run_template_tuple)
|
||||
|
||||
self.updateContent(run_templates)
|
||||
self.fetchContent()
|
||||
self.searchableList.list.setCurrentRow(currentRow)
|
||||
|
||||
def addToList(self, list, name):
|
||||
"""Adds a new run template to the list"""
|
||||
param = QtGui.QListWidgetItem()
|
||||
param.setText(name)
|
||||
|
||||
new_job = RunTemplate(name)
|
||||
param.setData(QtCore.Qt.UserRole, new_job)
|
||||
|
||||
list.addItem(param)
|
||||
list.setCurrentItem(param)
|
||||
return param
|
||||
|
||||
def addItem(self, list):
|
||||
"""Called by the add button to insert a new run template"""
|
||||
uniqueNames = []
|
||||
for index in range(list.count()):
|
||||
uniqueNames.append(str(list.item(index).text()))
|
||||
|
||||
pd = ValidatedDialog(self, "New run template", "Enter name of new run template:", uniqueNames)
|
||||
if pd.exec_():
|
||||
self.addToList(list, pd.getName())
|
||||
self.runTemplateChanged()
|
||||
|
||||
def removeItem(self, list):
|
||||
"""Called by the remove button to remove a selected job"""
|
||||
currentRow = list.currentRow()
|
||||
|
||||
if currentRow >= 0:
|
||||
title = "Delete run template?"
|
||||
msg = "Are you sure you want to delete the run template?"
|
||||
btns = QtGui.QMessageBox.Yes | QtGui.QMessageBox.No
|
||||
doDelete = QtGui.QMessageBox.question(self, title, msg, btns)
|
||||
|
||||
if doDelete == QtGui.QMessageBox.Yes:
|
||||
list.takeItem(currentRow)
|
||||
self.runTemplateChanged()
|
||||
|
||||
class RunTemplate:
|
||||
"""Stores the name, arguments and help text of a run template."""
|
||||
|
||||
def __init__(self, name, template_file="", target_file="", arguments=""):
|
||||
self.name = name
|
||||
self.setArguments(arguments)
|
||||
self.setTargetFile(target_file)
|
||||
self.setTemplateFile(template_file)
|
||||
|
||||
def setArguments(self, args):
|
||||
if args is None:
|
||||
args = ""
|
||||
self.arguments = args
|
||||
|
||||
def setTemplateFile(self, template_file):
|
||||
if template_file is None:
|
||||
template_file = ""
|
||||
self.template_file = template_file
|
||||
|
||||
def setTargetFile(self, target_file):
|
||||
if target_file is None:
|
||||
target_file = ""
|
||||
self.target_file = target_file
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,161 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'systemenv.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------------------------
|
||||
# System tab
|
||||
# ----------------------------------------------------------------------------------------------
|
||||
from ert_gui.widgets.pathchooser import PathChooser
|
||||
from ert_gui.widgets.configpanel import ConfigPanel
|
||||
from ert_gui.widgets.tablewidgets import KeywordTable, KeywordList
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from jobs.jobspanel import JobsPanel, Job
|
||||
import os
|
||||
import ert_gui.widgets.spinnerwidgets
|
||||
from ert_gui.widgets.activelabel import ActiveLabel
|
||||
|
||||
def createSystemPage(configPanel, parent):
|
||||
configPanel.startPage("System")
|
||||
|
||||
# Should call enkf_main_get_site_config_file() to get the name of
|
||||
# the site configuration file; this should only be a label - not
|
||||
# user editable.
|
||||
r = configPanel.addRow(ActiveLabel(None, "Site Config", "", "Not specified."))
|
||||
r.getter = lambda ert : ert.enkf.enkf_main_get_site_config_file(ert.main)
|
||||
r.modelConnect("casesUpdated()", r.fetchContent)
|
||||
|
||||
|
||||
|
||||
r = configPanel.addRow(PathChooser(parent, "Job script", "config/systemenv/job_script", True))
|
||||
r.getter = lambda ert : ert.enkf.site_config_get_job_script(ert.site_config)
|
||||
r.setter = lambda ert, value : ert.enkf.site_config_set_job_script(ert.site_config, str(value))
|
||||
|
||||
internalPanel = ConfigPanel(parent)
|
||||
internalPanel.startPage("setenv")
|
||||
|
||||
r = internalPanel.addRow(KeywordTable(parent, "", "config/systemenv/setenv"))
|
||||
r.getter = lambda ert : ert.getHash(ert.enkf.site_config_get_env_hash(ert.site_config))
|
||||
|
||||
def setenv(ert, value):
|
||||
ert.enkf.site_config_clear_env(ert.site_config)
|
||||
for env in value:
|
||||
ert.enkf.site_config_setenv(ert.site_config, env[0], env[1])
|
||||
|
||||
r.setter = setenv
|
||||
|
||||
internalPanel.endPage()
|
||||
|
||||
internalPanel.startPage("Update path")
|
||||
|
||||
r = internalPanel.addRow(KeywordTable(parent, "", "config/systemenv/update_path"))
|
||||
def get_update_path(ert):
|
||||
paths = ert.getStringList(ert.enkf.site_config_get_path_variables(ert.site_config))
|
||||
values = ert.getStringList(ert.enkf.site_config_get_path_values(ert.site_config))
|
||||
|
||||
return [[p, v] for p, v in zip(paths, values)]
|
||||
|
||||
r.getter = get_update_path
|
||||
|
||||
def update_pathvar(ert, value):
|
||||
ert.enkf.site_config_clear_pathvar(ert.site_config)
|
||||
|
||||
for pathvar in value:
|
||||
ert.enkf.site_config_update_pathvar(ert.site_config, pathvar[0], pathvar[1])
|
||||
|
||||
r.setter = update_pathvar
|
||||
|
||||
internalPanel.endPage()
|
||||
|
||||
|
||||
internalPanel.startPage("Jobs")
|
||||
|
||||
r = internalPanel.addRow(JobsPanel(parent))
|
||||
def get_jobs(ert):
|
||||
jl = ert.enkf.site_config_get_installed_jobs(ert.site_config)
|
||||
h = ert.job_queue.ext_joblist_get_jobs(jl)
|
||||
|
||||
jobs = ert.getHash(h, return_type="long")
|
||||
|
||||
private_jobs = []
|
||||
for k, v in jobs:
|
||||
v = int(v)
|
||||
path = ert.job_queue.ext_job_get_config_file(v)
|
||||
if ert.job_queue.ext_job_is_private(v):
|
||||
private_jobs.append(Job(k, path))
|
||||
|
||||
return private_jobs
|
||||
|
||||
def update_job(ert, value):
|
||||
jl = ert.enkf.site_config_get_installed_jobs(ert.site_config)
|
||||
|
||||
if os.path.exists(value.path):
|
||||
license = ert.enkf.site_config_get_license_root_path(ert.site_config)
|
||||
job = ert.job_queue.ext_job_fscanf_alloc(value.name, license, True, value.path)
|
||||
ert.job_queue.ext_joblist_add_job(jl, value.name, job)
|
||||
else:
|
||||
job = ert.job_queue.ext_joblist_get_job(jl, value.name)
|
||||
ert.job_queue.ext_job_set_config_file(job, value.path)
|
||||
|
||||
|
||||
def add_job(ert, value):
|
||||
jl = ert.enkf.site_config_get_installed_jobs(ert.site_config)
|
||||
if not ert.job_queue.ext_joblist_has_job(jl, value.name):
|
||||
license = ert.enkf.site_config_get_license_root_path(ert.site_config)
|
||||
if os.path.exists(value.path):
|
||||
job = ert.job_queue.ext_job_fscanf_alloc(value.name, license, True, value.path)
|
||||
ert.job_queue.ext_joblist_add_job(jl, value.name, job)
|
||||
else:
|
||||
job = ert.job_queue.ext_job_alloc(value.name, license, True)
|
||||
ert.job_queue.ext_job_set_config_file(job, value.path)
|
||||
ert.job_queue.ext_joblist_add_job(jl, value.name, job)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def remove_job(ert, value):
|
||||
jl = ert.enkf.site_config_get_installed_jobs(ert.site_config)
|
||||
success = ert.job_queue.ext_joblist_del_job(jl, value.name)
|
||||
|
||||
if not success:
|
||||
QtGui.QMessageBox.question(parent, "Failed", "Unable to delete job!", QtGui.QMessageBox.Ok)
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
r.getter = get_jobs
|
||||
r.setter = update_job
|
||||
r.insert = add_job
|
||||
r.remove = remove_job
|
||||
|
||||
|
||||
|
||||
internalPanel.endPage()
|
||||
configPanel.addRow(internalPanel)
|
||||
|
||||
r = configPanel.addRow(PathChooser(parent, "Log file", "config/systemenv/log_file", True))
|
||||
r.getter = lambda ert : ert.util.log_get_filename(ert.logh)
|
||||
r.setter = lambda ert, value : ert.util.log_reset_filename(ert.logh, value)
|
||||
|
||||
r = configPanel.addRow(ert_gui.widgets.spinnerwidgets.IntegerSpinner(parent, "Log level", "config/systemenv/log_level", 0, 1000))
|
||||
r.getter = lambda ert : ert.util.log_get_level(ert.logh)
|
||||
r.setter = lambda ert, value : ert.util.log_set_level(ert.logh, value)
|
||||
|
||||
configPanel.endPage()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file '__init__.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
@@ -1,385 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'initandcopy.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from ert_gui.widgets.helpedwidget import HelpedWidget
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from ert_gui.widgets.util import resourceIcon, ListCheckPanel, ValidatedTimestepCombo, getItemsFromList
|
||||
from ert.ert.enums import ert_state_enum
|
||||
|
||||
class ParametersAndMembers(HelpedWidget):
|
||||
|
||||
listOfParameters = []
|
||||
listOfDynamicParameters = []
|
||||
maxTimeStep = 11
|
||||
|
||||
|
||||
def __init__(self, parent = None):
|
||||
HelpedWidget.__init__(self, parent)
|
||||
|
||||
radioLayout = self.createRadioButtons()
|
||||
listLayout = self.createParameterMemberPanel()
|
||||
stLayout = self.createSourceTargetLayout()
|
||||
actionLayout = self.createActionButton()
|
||||
|
||||
layout = QtGui.QVBoxLayout()
|
||||
layout.addLayout(radioLayout)
|
||||
layout.addSpacing(5)
|
||||
layout.addLayout(listLayout)
|
||||
layout.addSpacing(5)
|
||||
layout.addLayout(stLayout)
|
||||
layout.addSpacing(5)
|
||||
layout.addLayout(actionLayout)
|
||||
|
||||
self.addLayout(layout)
|
||||
|
||||
self.initialized = False
|
||||
self.modelConnect("casesUpdated()", self.fetchContent)
|
||||
self.modelConnect("ensembleResized()", self.fetchContent)
|
||||
self.modelConnect("ensembleUpdated()", self.fetchContent)
|
||||
|
||||
self.toggleScratch.toggle()
|
||||
|
||||
|
||||
def toggleCompleteEnsembleState(self, checkState):
|
||||
self.parametersList.setSelectionEnabled(not checkState)
|
||||
|
||||
if checkState:
|
||||
self.parametersList.selectAll()
|
||||
|
||||
|
||||
def toggleActionState(self, action="Initialize", showCopyParameters = False, selectSource = False, selectTarget = False):
|
||||
self.sourceLabel.setEnabled(selectSource)
|
||||
self.sourceCase.setEnabled(selectSource)
|
||||
self.sourceType.setEnabled(selectSource)
|
||||
self.sourceReportStep.setEnabled(selectSource)
|
||||
self.sourceCompleteEnsembleCheck.setEnabled(showCopyParameters)
|
||||
|
||||
if not selectSource:
|
||||
self.sourceReportStep.setCurrentIndex(0)
|
||||
|
||||
self.targetLabel.setEnabled(selectTarget)
|
||||
self.targetCaseLabel.setEnabled(selectTarget)
|
||||
self.targetType.setEnabled(selectTarget)
|
||||
self.targetReportStep.setEnabled(selectTarget)
|
||||
|
||||
|
||||
if not selectTarget:
|
||||
self.targetReportStep.setCurrentIndex(0)
|
||||
|
||||
self.actionButton.setText(action)
|
||||
|
||||
|
||||
self.parametersList.clear()
|
||||
self.parametersList.addItems(self.listOfParameters)
|
||||
|
||||
self.parametersList.setEnabled(True)
|
||||
self.parametersList.checkAll.setEnabled(True)
|
||||
self.parametersList.uncheckAll.setEnabled(True)
|
||||
|
||||
|
||||
if showCopyParameters:
|
||||
self.parametersList.addItems(self.listOfDynamicParameters)
|
||||
self.toggleCompleteEnsembleState(self.sourceCompleteEnsembleCheck.isChecked())
|
||||
|
||||
self.parametersList.selectAll()
|
||||
self.membersList.selectAll()
|
||||
|
||||
|
||||
def initializeCaseFromScratch(self, parameters, members):
|
||||
ert = self.getModel()
|
||||
|
||||
stringlist = ert.createStringList(parameters)
|
||||
|
||||
for member in members:
|
||||
m = int(member.strip())
|
||||
ert.enkf.enkf_main_initialize_from_scratch(ert.main, stringlist, m , m)
|
||||
|
||||
ert.freeStringList(stringlist)
|
||||
|
||||
def initializeCaseFromCase(self, selected_parameters, selected_members):
|
||||
ert = self.getModel()
|
||||
|
||||
selected_parameters = [str(parameter) for parameter in selected_parameters]
|
||||
selected_members = [int(member.strip()) for member in selected_members]
|
||||
|
||||
source_case = str(self.sourceCase.currentText())
|
||||
source_report_step = self.sourceReportStep.getSelectedValue()
|
||||
source_state = ert_state_enum.resolveName(str(self.sourceType.currentText())).value()
|
||||
member_mask = ert.createBoolVector(self.membersList.count(), selected_members)
|
||||
ranking_key = None
|
||||
node_list = ert.createStringList(selected_parameters)
|
||||
|
||||
ert.enkf.enkf_main_initialize_from_existing__(ert.main,
|
||||
source_case,
|
||||
source_report_step,
|
||||
source_state,
|
||||
member_mask,
|
||||
ranking_key,
|
||||
node_list)
|
||||
|
||||
ert.freeStringList(node_list)
|
||||
ert.freeBoolVector(member_mask)
|
||||
|
||||
def copyEnsemble(self, selected_parameters, selected_members):
|
||||
ert = self.getModel()
|
||||
|
||||
selected_parameters = [str(parameter) for parameter in selected_parameters]
|
||||
selected_members = [int(member.strip()) for member in selected_members]
|
||||
|
||||
source_case = str(self.sourceCase.currentText())
|
||||
source_report_step = self.sourceReportStep.getSelectedValue()
|
||||
source_state = ert_state_enum.resolveName(str(self.sourceType.currentText())).value()
|
||||
|
||||
target_case = str(self.targetCaseLabel.text())
|
||||
target_report_step = self.targetReportStep.getSelectedValue()
|
||||
target_state = ert_state_enum.resolveName(str(self.targetType.currentText())).value()
|
||||
|
||||
member_mask = ert.createBoolVector(self.membersList.count(), selected_members)
|
||||
ranking_key = None
|
||||
node_list = ert.createStringList(selected_parameters)
|
||||
|
||||
ert.enkf.enkf_main_copy_ensemble(ert.main,
|
||||
source_case,
|
||||
source_report_step,
|
||||
source_state,
|
||||
target_case,
|
||||
target_report_step,
|
||||
target_state,
|
||||
member_mask,
|
||||
ranking_key,
|
||||
node_list)
|
||||
|
||||
ert.freeStringList(node_list)
|
||||
ert.freeBoolVector(member_mask)
|
||||
|
||||
def initializeOrCopy(self):
|
||||
selected_parameters = getItemsFromList(self.parametersList)
|
||||
selected_members = getItemsFromList(self.membersList)
|
||||
|
||||
if len(selected_parameters) == 0 or len(selected_members) == 0:
|
||||
QtGui.QMessageBox.warning(self, "Missing data", "At least one parameter and one member must be selected!")
|
||||
return
|
||||
|
||||
if self.toggleScratch.isChecked():
|
||||
self.initializeCaseFromScratch(selected_parameters, selected_members)
|
||||
elif self.toggleInitCopy.isChecked():
|
||||
self.initializeCaseFromCase(selected_parameters, selected_members)
|
||||
else:
|
||||
self.copyEnsemble(selected_parameters, selected_members)
|
||||
|
||||
|
||||
def fetchContent(self):
|
||||
data = self.getFromModel()
|
||||
|
||||
self.parametersList.clear()
|
||||
self.membersList.clear()
|
||||
self.sourceCase.clear()
|
||||
|
||||
self.listOfParameters = data["parameters"]
|
||||
self.listOfDynamicParameters = data["dynamic_parameters"]
|
||||
|
||||
|
||||
for member in data["members"]:
|
||||
self.membersList.addItem("%03d" % (member))
|
||||
#self.membersList.addItem(str(member))
|
||||
|
||||
for case in data["cases"]:
|
||||
if not case == data["current_case"]:
|
||||
self.sourceCase.addItem(case)
|
||||
|
||||
self.maxTimeStep = data["history_length"]
|
||||
|
||||
self.sourceReportStep.setHistoryLength(self.maxTimeStep)
|
||||
self.targetReportStep.setHistoryLength(self.maxTimeStep)
|
||||
|
||||
self.targetCaseLabel.setText(data["current_case"])
|
||||
|
||||
if self.toggleScratch.isChecked():
|
||||
self.toggleScratch.emit(QtCore.SIGNAL("toggled(bool)"), True)
|
||||
elif self.toggleInitCopy.isChecked():
|
||||
self.toggleInitCopy.emit(QtCore.SIGNAL("toggled(bool)"), True)
|
||||
else:
|
||||
self.toggleCopy.emit(QtCore.SIGNAL("toggled(bool)"), True)
|
||||
|
||||
|
||||
def initialize(self, ert):
|
||||
self.initialized = True
|
||||
|
||||
|
||||
def getter(self, ert):
|
||||
if not self.initialized:
|
||||
self.initialize(ert)
|
||||
|
||||
#enums from enkf_types.h
|
||||
PARAMETER = 1
|
||||
DYNAMIC_STATE = 2
|
||||
keylist = ert.enkf.ensemble_config_alloc_keylist_from_var_type(ert.ensemble_config, PARAMETER )
|
||||
|
||||
parameters = ert.getStringList(keylist)
|
||||
ert.freeStringList(keylist)
|
||||
|
||||
keylist = ert.enkf.ensemble_config_alloc_keylist_from_var_type(ert.ensemble_config, DYNAMIC_STATE )
|
||||
dynamicParameters = ert.getStringList(keylist)
|
||||
ert.freeStringList(keylist)
|
||||
|
||||
members = ert.enkf.enkf_main_get_ensemble_size(ert.main)
|
||||
|
||||
fs = ert.enkf.enkf_main_get_fs(ert.main)
|
||||
currentCase = "default" #ert.enkf.enkf_fs_get_read_dir(fs)
|
||||
|
||||
#caseList = ert.enkf.enkf_fs_alloc_dirlist(fs)
|
||||
#list = ert.getStringList(caseList)
|
||||
#ert.freeStringList(caseList)
|
||||
list = ["default"]
|
||||
historyLength = ert.enkf.enkf_main_get_history_length(ert.main)
|
||||
|
||||
return {"parameters" : parameters,
|
||||
"dynamic_parameters" : dynamicParameters,
|
||||
"members" : range(members),
|
||||
"current_case" : currentCase,
|
||||
"cases" : list,
|
||||
"history_length" : historyLength}
|
||||
|
||||
|
||||
def setter(self, ert, value):
|
||||
"""The setting of these values are activated by a separate button."""
|
||||
pass
|
||||
|
||||
|
||||
def createCheckPanel(self, list):
|
||||
return ListCheckPanel(list)
|
||||
|
||||
|
||||
def createRadioButtons(self):
|
||||
radioLayout = QtGui.QVBoxLayout()
|
||||
radioLayout.setSpacing(2)
|
||||
self.toggleScratch = QtGui.QRadioButton("Initialize from scratch")
|
||||
radioLayout.addWidget(self.toggleScratch)
|
||||
self.toggleInitCopy = QtGui.QRadioButton("Initialize from existing case")
|
||||
radioLayout.addWidget(self.toggleInitCopy)
|
||||
self.toggleCopy = QtGui.QRadioButton("Copy from existing case")
|
||||
radioLayout.addWidget(self.toggleCopy)
|
||||
|
||||
self.connect(self.toggleScratch, QtCore.SIGNAL('toggled(bool)'), lambda : self.toggleActionState())
|
||||
self.connect(self.toggleInitCopy, QtCore.SIGNAL('toggled(bool)'), lambda : self.toggleActionState(selectSource = True))
|
||||
self.connect(self.toggleCopy, QtCore.SIGNAL('toggled(bool)'), lambda : self.toggleActionState(action = "Copy", selectSource=True, showCopyParameters=True, selectTarget=True))
|
||||
|
||||
return radioLayout
|
||||
|
||||
|
||||
def createParameterMemberPanel(self):
|
||||
self.parametersList = QtGui.QListWidget(self)
|
||||
self.parametersList.setSelectionMode(QtGui.QAbstractItemView.MultiSelection)
|
||||
self.membersList = QtGui.QListWidget(self)
|
||||
self.membersList.setSelectionMode(QtGui.QAbstractItemView.MultiSelection)
|
||||
|
||||
#--- members iconview code ---
|
||||
self.membersList.setViewMode(QtGui.QListView.IconMode)
|
||||
self.membersList.setMovement(QtGui.QListView.Static)
|
||||
self.membersList.setResizeMode(QtGui.QListView.Adjust)
|
||||
#self.membersList.setUniformItemSizes(True)
|
||||
self.membersList.setGridSize(QtCore.QSize(32, 16))
|
||||
self.membersList.setSelectionRectVisible(False)
|
||||
#-----------------------------
|
||||
|
||||
parameterLayout = QtGui.QVBoxLayout()
|
||||
parametersCheckPanel = self.createCheckPanel(self.parametersList)
|
||||
parametersCheckPanel.insertWidget(0, QtGui.QLabel("Parameters"))
|
||||
parameterLayout.addLayout(parametersCheckPanel)
|
||||
parameterLayout.addWidget(self.parametersList)
|
||||
|
||||
memberLayout = QtGui.QVBoxLayout()
|
||||
membersCheckPanel = self.createCheckPanel(self.membersList)
|
||||
membersCheckPanel.insertWidget(0, QtGui.QLabel("Members"))
|
||||
memberLayout.addLayout(membersCheckPanel)
|
||||
memberLayout.addWidget(self.membersList)
|
||||
|
||||
listLayout = QtGui.QHBoxLayout()
|
||||
listLayout.addLayout(parameterLayout)
|
||||
listLayout.addLayout(memberLayout)
|
||||
|
||||
return listLayout
|
||||
|
||||
|
||||
def createActionButton(self):
|
||||
self.actionButton = QtGui.QPushButton("Initialize")
|
||||
|
||||
self.connect(self.actionButton, QtCore.SIGNAL('clicked()'), self.initializeOrCopy)
|
||||
|
||||
actionLayout = QtGui.QHBoxLayout()
|
||||
actionLayout.addStretch(1)
|
||||
actionLayout.addWidget(self.actionButton)
|
||||
actionLayout.addStretch(1)
|
||||
|
||||
return actionLayout
|
||||
|
||||
|
||||
def createSourceTargetLayout(self):
|
||||
self.createSourceTargetWidgets()
|
||||
|
||||
stLayout = QtGui.QGridLayout()
|
||||
stLayout.setColumnStretch(8, 1)
|
||||
stLayout.addWidget(QtGui.QLabel("Case"), 0, 1)
|
||||
stLayout.addWidget(QtGui.QLabel("State"), 0, 3)
|
||||
stLayout.addWidget(QtGui.QLabel("Timestep"), 0, 5)
|
||||
self.sourceLabel = QtGui.QLabel("Source:")
|
||||
stLayout.addWidget(self.sourceLabel, 1, 0)
|
||||
stLayout.addWidget(self.sourceCase, 1, 1)
|
||||
stLayout.addWidget(self.sourceType, 1, 3)
|
||||
stLayout.addWidget(self.sourceReportStep, 1, 5)
|
||||
stLayout.addWidget(self.sourceCompleteEnsembleCheck, 1, 7)
|
||||
|
||||
self.targetCaseLabel = QtGui.QLabel("none?")
|
||||
font = self.targetCaseLabel.font()
|
||||
font.setWeight(QtGui.QFont.Bold)
|
||||
self.targetCaseLabel.setFont(font)
|
||||
|
||||
self.targetLabel = QtGui.QLabel("Target:")
|
||||
|
||||
stLayout.addWidget(self.targetLabel, 2, 0)
|
||||
stLayout.addWidget(self.targetCaseLabel, 2, 1)
|
||||
stLayout.addWidget(self.targetType, 2, 3)
|
||||
stLayout.addWidget(self.targetReportStep, 2, 5)
|
||||
|
||||
return stLayout
|
||||
|
||||
|
||||
def createSourceTargetWidgets(self):
|
||||
self.sourceCase = QtGui.QComboBox(self)
|
||||
self.sourceCase.setMaximumWidth(150)
|
||||
self.sourceCase.setMinimumWidth(150)
|
||||
self.sourceCase.setToolTip("Select source case")
|
||||
self.sourceType = QtGui.QComboBox(self)
|
||||
self.sourceType.setMaximumWidth(100)
|
||||
self.sourceType.setToolTip("Select source state")
|
||||
for state in ert_state_enum.INITIALIZATION_STATES:
|
||||
self.sourceType.addItem(str(state))
|
||||
|
||||
self.sourceReportStep = ValidatedTimestepCombo(self)
|
||||
self.sourceCompleteEnsembleCheck = QtGui.QCheckBox("Complete Ensemble")
|
||||
self.sourceCompleteEnsembleCheck.setChecked(True)
|
||||
|
||||
self.connect(self.sourceCompleteEnsembleCheck, QtCore.SIGNAL('stateChanged(int)'),
|
||||
lambda state : self.toggleCompleteEnsembleState(state == QtCore.Qt.Checked))
|
||||
|
||||
self.targetType = QtGui.QComboBox(self)
|
||||
self.targetType.setMaximumWidth(100)
|
||||
self.targetType.setToolTip("Select target state")
|
||||
for state in ert_state_enum.INITIALIZATION_STATES:
|
||||
self.targetType.addItem(str(state))
|
||||
|
||||
self.targetReportStep = ValidatedTimestepCombo(self)
|
||||
@@ -1,130 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'initpanel.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from ert_gui.widgets.tablewidgets import KeywordList
|
||||
from ert_gui.widgets.validateddialog import ValidatedDialog
|
||||
import ert.ert.ertwrapper as ertwrapper
|
||||
from ert_gui.widgets.combochoice import ComboChoice
|
||||
|
||||
|
||||
from ert_gui.widgets.helpedwidget import HelpedWidget
|
||||
from ert_gui.widgets.util import resourceIcon, createSeparator, may_take_a_long_time
|
||||
|
||||
from initandcopy import *
|
||||
|
||||
|
||||
class InitPanel(QtGui.QFrame):
|
||||
|
||||
def __init__(self, parent):
|
||||
QtGui.QFrame.__init__(self, parent)
|
||||
self.setFrameShape(QtGui.QFrame.Panel)
|
||||
self.setFrameShadow(QtGui.QFrame.Raised)
|
||||
|
||||
initPanelLayout = QtGui.QVBoxLayout()
|
||||
self.setLayout(initPanelLayout)
|
||||
|
||||
casePanel = QtGui.QFormLayout()
|
||||
|
||||
|
||||
def get_case_list(ert):
|
||||
fs = ert.enkf.enkf_main_get_fs(ert.main)
|
||||
caseList = ["default"] #ert.enkf.enkf_fs_alloc_dirlist(fs)
|
||||
|
||||
list = caseList #ert.getStringList(caseList)
|
||||
#ert.freeStringList(caseList)
|
||||
return list
|
||||
|
||||
self.get_case_list = get_case_list # convenience: used by several functions
|
||||
|
||||
|
||||
casePanel.addRow("Current case:", self.createCurrentCaseCombo())
|
||||
casePanel.addRow("Cases:", self.createCaseList())
|
||||
|
||||
|
||||
parametersPanelLayout = QtGui.QHBoxLayout()
|
||||
parametersPanelLayout.addWidget(ParametersAndMembers(self))
|
||||
|
||||
initPanelLayout.addLayout(casePanel)
|
||||
initPanelLayout.addWidget(createSeparator())
|
||||
initPanelLayout.addLayout(parametersPanelLayout)
|
||||
|
||||
def casesUpdated(self):
|
||||
"""Emit to all listeners that the a new case has been added or the current case has changed"""
|
||||
self.currentCase.modelEmit("casesUpdated()")
|
||||
|
||||
def createCaseList(self):
|
||||
"""Creates a list that enables the creation of new cases. Removal has been disabled."""
|
||||
cases = KeywordList(self, "", "init/case_list")
|
||||
|
||||
cases.newKeywordPopup = lambda list : ValidatedDialog(cases, "New case", "Enter name of new case:", list).showAndTell()
|
||||
cases.addRemoveWidget.enableRemoveButton(False) #todo: add support for removal
|
||||
cases.list.setMaximumHeight(150)
|
||||
|
||||
cases.initialize = lambda ert : [ert.prototype("long enkf_main_get_fs(long)"),
|
||||
ert.prototype("void enkf_main_select_case(long , char*)"),
|
||||
ert.prototype("long enkf_fs_alloc_dirlist(long)")]
|
||||
|
||||
def create_case(ert, cases):
|
||||
fs = ert.enkf.enkf_main_get_fs(ert.main)
|
||||
|
||||
for case in cases:
|
||||
if not ert.enkf.enkf_fs_has_dir(fs, case):
|
||||
ert.enkf.enkf_fs_select_write_dir(fs, case, True)
|
||||
break
|
||||
|
||||
self.currentCase.updateList(self.get_case_list(ert))
|
||||
self.currentCase.fetchContent()
|
||||
self.casesUpdated()
|
||||
|
||||
cases.getter = self.get_case_list
|
||||
cases.setter = create_case
|
||||
|
||||
return cases
|
||||
|
||||
|
||||
def createCurrentCaseCombo(self):
|
||||
"""Creates the combo that enables selection of the current case"""
|
||||
self.currentCase = ComboChoice(self, ["none"], help="init/current_case_selection")
|
||||
self.currentCase.combo.setMinimumWidth(150)
|
||||
|
||||
def initialize_cases(ert):
|
||||
ert.prototype("long enkf_main_get_fs(long)")
|
||||
|
||||
self.currentCase.updateList(self.get_case_list(ert))
|
||||
|
||||
self.currentCase.initialize = initialize_cases
|
||||
|
||||
def get_current_case(ert):
|
||||
fs = ert.enkf.enkf_main_get_fs(ert.main)
|
||||
tmp = self.get_case_list(ert)
|
||||
currentCase = tmp[0] #ert.enkf.enkf_fs_get_read_dir(fs)
|
||||
#print "The selected case is: " + currentCase
|
||||
return currentCase
|
||||
|
||||
self.currentCase.getter = get_current_case
|
||||
|
||||
@may_take_a_long_time
|
||||
def select_case(ert, case):
|
||||
case = str(case)
|
||||
if not case == "":
|
||||
ert.enkf.enkf_main_select_case( ert.main , case )
|
||||
self.casesUpdated()
|
||||
|
||||
self.currentCase.setter = select_case
|
||||
|
||||
return self.currentCase
|
||||
@@ -1,17 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file '__init__.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
@@ -1,417 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'ensemblefetcher.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
|
||||
from fetcher import PlotDataFetcherHandler
|
||||
from ert_gui.pages.config.parameters.parametermodels import FieldModel, SummaryModel, KeywordModel, DataModel
|
||||
import ert.ert.ertwrapper as ertwrapper
|
||||
import ert.ert.enums as enums
|
||||
from PyQt4.QtGui import QWidget, QFormLayout, QSpinBox, QComboBox
|
||||
from PyQt4.QtCore import SIGNAL
|
||||
from ert.ert.erttypes import time_t
|
||||
import numpy
|
||||
|
||||
class EnsembleFetcher(PlotDataFetcherHandler):
|
||||
"""A data fetcher for ensemble parameters."""
|
||||
|
||||
def __init__(self):
|
||||
PlotDataFetcherHandler.__init__(self)
|
||||
|
||||
self.field_configuration = FieldConfigurationWidget()
|
||||
self.summary_configuration = SummaryConfigurationWidget()
|
||||
self.keyword_configuration = KeywordConfigurationWidget()
|
||||
self.data_configuration = DataConfigurationWidget()
|
||||
|
||||
def emitter():
|
||||
self.emit(SIGNAL('dataChanged()'))
|
||||
|
||||
self.connect(self.field_configuration, SIGNAL('configurationChanged()'), emitter)
|
||||
self.connect(self.summary_configuration, SIGNAL('configurationChanged()'), emitter)
|
||||
self.connect(self.keyword_configuration, SIGNAL('configurationChanged()'), emitter)
|
||||
self.connect(self.data_configuration, SIGNAL('configurationChanged()'), emitter)
|
||||
|
||||
def initialize(self, ert):
|
||||
|
||||
|
||||
ert.prototype("long enkf_main_get_fs(long)")
|
||||
ert.prototype("int enkf_main_get_ensemble_size(long)")
|
||||
ert.prototype("long enkf_main_iget_member_config(long, int)")
|
||||
ert.prototype("void enkf_main_get_observations(long, char*, int, long*, double*, double*)") #main, user_key, *time, *y, *std
|
||||
ert.prototype("int enkf_main_get_observation_count(long, char*)")
|
||||
|
||||
ert.prototype("bool enkf_fs_has_node(long, long, int, int, int)")
|
||||
ert.prototype("void enkf_fs_fread_node(long, long, int, int, int)")
|
||||
|
||||
ert.prototype("long enkf_node_alloc(long)")
|
||||
ert.prototype("void enkf_node_free(long)")
|
||||
ert.prototype("double enkf_node_user_get(long, char*, bool*)")
|
||||
|
||||
ert.prototype("double member_config_iget_sim_days(long, int, int)")
|
||||
ert.prototype("time_t member_config_iget_sim_time(long, int, int)")
|
||||
ert.prototype("int enkf_main_get_history_length(long)")
|
||||
|
||||
|
||||
ert.prototype("long enkf_config_node_get_ref(long)")
|
||||
ert.prototype("bool field_config_ijk_active(long, int, int, int)")
|
||||
|
||||
ert.prototype("bool ecl_sum_has_general_var(long, char*)", lib=ert.ecl)
|
||||
ert.prototype("int ecl_sum_get_general_var_index(long, char*)", lib=ert.ecl)
|
||||
|
||||
ert.prototype("time_vector ecl_sum_alloc_time_vector(long, bool)", lib=ert.ecl)
|
||||
ert.prototype("double_vector ecl_sum_alloc_data_vector(long, int, bool)", lib=ert.ecl)
|
||||
|
||||
|
||||
def isHandlerFor(self, ert, key):
|
||||
return ert.enkf.ensemble_config_has_key(ert.ensemble_config, key)
|
||||
|
||||
|
||||
def fetch(self, ert, key, parameter, data, comparison_fs):
|
||||
data.x_data_type = "time"
|
||||
|
||||
fs = ert.enkf.enkf_main_get_fs(ert.main)
|
||||
config_node = ert.enkf.ensemble_config_get_node(ert.ensemble_config, key)
|
||||
node = ert.enkf.enkf_node_alloc(config_node)
|
||||
comp_node = ert.enkf.enkf_node_alloc(config_node)
|
||||
num_realizations = ert.enkf.enkf_main_get_ensemble_size(ert.main)
|
||||
|
||||
user_data = parameter.getUserData()
|
||||
|
||||
if user_data is None:
|
||||
return False
|
||||
|
||||
key_index = None
|
||||
if user_data.has_key('key_index'):
|
||||
key_index = user_data['key_index']
|
||||
|
||||
if parameter.getType() == FieldModel.TYPE:
|
||||
field_position = user_data['field_position']
|
||||
field_config = ert.enkf.enkf_config_node_get_ref(config_node)
|
||||
if ert.enkf.field_config_ijk_active(field_config, field_position[0] - 1, field_position[1] - 1, field_position[2] - 1):
|
||||
key_index = "%i,%i,%i" % (field_position[0], field_position[1], field_position[2])
|
||||
data.setKeyIndexIsIndex(True)
|
||||
else:
|
||||
return False
|
||||
elif parameter.getType() == DataModel.TYPE:
|
||||
data_index = user_data['data_index']
|
||||
key_index = "KEY:%d" % data_index
|
||||
data.setKeyIndexIsIndex(True)
|
||||
|
||||
data.setKeyIndex(key_index)
|
||||
|
||||
state_list = [user_data['state']]
|
||||
if state_list[0] == enums.ert_state_enum.BOTH:
|
||||
state_list = [enums.ert_state_enum.FORECAST, enums.ert_state_enum.ANALYZED]
|
||||
|
||||
for member in range(0, num_realizations):
|
||||
data.x_data[member] = []
|
||||
data.y_data[member] = []
|
||||
x_time = data.x_data[member]
|
||||
y = data.y_data[member]
|
||||
|
||||
if not comparison_fs is None:
|
||||
data.x_comp_data[member] = []
|
||||
data.y_comp_data[member] = []
|
||||
x_comp_time = data.x_comp_data[member]
|
||||
y_comp = data.y_comp_data[member]
|
||||
|
||||
member_config = ert.enkf.enkf_main_iget_member_config(ert.main, member)
|
||||
stop_time = ert.enkf.enkf_main_get_history_length( ert.main )
|
||||
|
||||
for step in range(0, stop_time + 1):
|
||||
for state in state_list:
|
||||
if ert.enkf.enkf_fs_has_node(fs, config_node, step, member, state.value()):
|
||||
sim_time = ert.enkf.member_config_iget_sim_time(member_config, step, fs)
|
||||
ert.enkf.enkf_fs_fread_node(fs, node, step, member, state.value())
|
||||
valid = ertwrapper.c_int()
|
||||
value = ert.enkf.enkf_node_user_get(node, key_index, ertwrapper.byref(valid))
|
||||
if valid.value == 1:
|
||||
data.checkMaxMin(sim_time)
|
||||
data.checkMaxMinY(value)
|
||||
x_time.append(sim_time)
|
||||
y.append(value)
|
||||
#else:
|
||||
# print "Not valid: ", key, member, step, key_index
|
||||
|
||||
if not comparison_fs is None:
|
||||
if ert.enkf.enkf_fs_has_node(comparison_fs, config_node, step, member, state.value()):
|
||||
sim_time = ert.enkf.member_config_iget_sim_time(member_config, step, comparison_fs)
|
||||
ert.enkf.enkf_fs_fread_node(comparison_fs, comp_node, step, member, state.value())
|
||||
valid = ertwrapper.c_int()
|
||||
value = ert.enkf.enkf_node_user_get(comp_node, key_index, ertwrapper.byref(valid))
|
||||
if valid.value == 1:
|
||||
#data.checkMaxMin(sim_time)
|
||||
#data.checkMaxMinY(value)
|
||||
x_comp_time.append(sim_time)
|
||||
y_comp.append(value)
|
||||
#else:
|
||||
# print "Not valid: ", key, member, step, key_index
|
||||
|
||||
data.x_data[member] = numpy.array([t.datetime() for t in x_time])
|
||||
data.y_data[member] = numpy.array(y)
|
||||
|
||||
if not comparison_fs is None:
|
||||
data.x_comp_data[member] = numpy.array([t.datetime() for t in x_comp_time])
|
||||
data.y_comp_data[member] = numpy.array(y_comp)
|
||||
|
||||
|
||||
self._getObservations(ert, key, key_index, data)
|
||||
|
||||
self._getRefCase(ert, key, data)
|
||||
|
||||
ert.enkf.enkf_node_free(node)
|
||||
ert.enkf.enkf_node_free(comp_node)
|
||||
|
||||
data.inverted_y_axis = False
|
||||
|
||||
def _getObservations(self, ert, key, key_index, data):
|
||||
if not key_index is None:
|
||||
user_key = "%s:%s" % (key, key_index)
|
||||
else:
|
||||
user_key = key
|
||||
|
||||
obs_count = ert.enkf.enkf_main_get_observation_count(ert.main, user_key)
|
||||
if obs_count > 0:
|
||||
obs_x = (time_t * obs_count)()
|
||||
obs_y = (ertwrapper.c_double * obs_count)()
|
||||
obs_std = (ertwrapper.c_double * obs_count)()
|
||||
ert.enkf.enkf_main_get_observations(ert.main, user_key, obs_count, obs_x, obs_y, obs_std)
|
||||
|
||||
data.obs_x = numpy.array([t.datetime() for t in obs_x])
|
||||
data.obs_y = numpy.array(obs_y)
|
||||
data.obs_std_y = numpy.array(obs_std)
|
||||
data.obs_std_x = None
|
||||
|
||||
data.checkMaxMin(max(obs_x))
|
||||
data.checkMaxMin(min(obs_x))
|
||||
|
||||
data.checkMaxMinY(max(obs_y))
|
||||
data.checkMaxMinY(min(obs_y))
|
||||
|
||||
|
||||
def _getRefCase(self, ert, key, data):
|
||||
ecl_sum = ert.enkf.ecl_config_get_refcase(ert.ecl_config)
|
||||
|
||||
if(ert.ecl.ecl_sum_has_general_var(ecl_sum, key)):
|
||||
ki = ert.ecl.ecl_sum_get_general_var_index(ecl_sum, key)
|
||||
x_data = ert.ecl.ecl_sum_alloc_time_vector(ecl_sum, True)
|
||||
y_data = ert.ecl.ecl_sum_alloc_data_vector(ecl_sum, ki, True)
|
||||
|
||||
data.refcase_x = []
|
||||
data.refcase_y = []
|
||||
first = True
|
||||
for x in x_data:
|
||||
if not first:
|
||||
data.refcase_x.append(x)
|
||||
data.checkMaxMin(x)
|
||||
else:
|
||||
first = False #skip first element because of eclipse behavior
|
||||
|
||||
first = True
|
||||
for y in y_data:
|
||||
if not first:
|
||||
data.refcase_y.append(y)
|
||||
data.checkMaxMinY(y)
|
||||
else:
|
||||
first = False #skip first element because of eclipse behavior
|
||||
|
||||
data.refcase_x = numpy.array([t.datetime() for t in data.refcase_x])
|
||||
data.refcase_y = numpy.array(data.refcase_y)
|
||||
|
||||
def configure(self, parameter, context_data):
|
||||
self.parameter = parameter
|
||||
|
||||
cw = self.getConfigurationWidget(context_data)
|
||||
if not cw is None:
|
||||
cw.setParameter(parameter)
|
||||
|
||||
def getConfigurationWidget(self, context_data):
|
||||
if self.parameter.getType() == SummaryModel.TYPE:
|
||||
return self.summary_configuration
|
||||
elif self.parameter.getType() == KeywordModel.TYPE:
|
||||
key_index_list = context_data.getKeyIndexList(self.parameter.getName())
|
||||
self.keyword_configuration.setKeyIndexList(key_index_list)
|
||||
return self.keyword_configuration
|
||||
elif self.parameter.getType() == FieldModel.TYPE:
|
||||
bounds = context_data.field_bounds
|
||||
self.field_configuration.setFieldBounds(*bounds)
|
||||
return self.field_configuration
|
||||
elif self.parameter.getType() == DataModel.TYPE:
|
||||
index = context_data.gen_data_size
|
||||
self.data_configuration.setIndexBounds(index)
|
||||
return self.data_configuration
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
#---------------------------------------------------------
|
||||
# The following widgets are used to configure the
|
||||
# different parameter types.
|
||||
#---------------------------------------------------------
|
||||
|
||||
class ConfigurationWidget(QWidget):
|
||||
"""An abstract configuration widget."""
|
||||
def __init__(self):
|
||||
QWidget.__init__(self)
|
||||
self.layout = QFormLayout()
|
||||
self.layout.setRowWrapPolicy(QFormLayout.WrapLongRows)
|
||||
|
||||
self.stateCombo = QComboBox()
|
||||
|
||||
for state in enums.ert_state_enum.values():
|
||||
self.stateCombo.addItem(state.name)
|
||||
|
||||
self.stateCombo.setCurrentIndex(0)
|
||||
|
||||
self.layout.addRow("State:", self.stateCombo)
|
||||
|
||||
self.setLayout(self.layout)
|
||||
|
||||
self.connect(self.stateCombo, SIGNAL('currentIndexChanged(QString)'), self.applyConfiguration)
|
||||
|
||||
def addRow(self, label, widget):
|
||||
"""Add another item to this widget."""
|
||||
self.layout.addRow(label, widget)
|
||||
|
||||
def setParameter(self, parameter):
|
||||
"""Set the parameter to configure."""
|
||||
self.parameter = parameter
|
||||
self.applyConfiguration(False)
|
||||
|
||||
def getState(self):
|
||||
"""State is common for all parameters."""
|
||||
selectedName = str(self.stateCombo.currentText())
|
||||
return enums.ert_state_enum.resolveName(selectedName)
|
||||
|
||||
def emitConfigurationChanged(self, emit=True):
|
||||
"""Emitted when a sub widget changes the state of the parameter."""
|
||||
if emit:
|
||||
self.emit(SIGNAL('configurationChanged()'))
|
||||
|
||||
def applyConfiguration(self, emit=True):
|
||||
"""Override! Set the user_data of self.paramater and optionally: emitConfigurationChanged()"""
|
||||
pass
|
||||
|
||||
|
||||
class SummaryConfigurationWidget(ConfigurationWidget):
|
||||
def __init__(self):
|
||||
ConfigurationWidget.__init__(self)
|
||||
|
||||
|
||||
def applyConfiguration(self, emit=True):
|
||||
user_data = {'state': self.getState()}
|
||||
self.parameter.setUserData(user_data)
|
||||
self.emitConfigurationChanged(emit)
|
||||
|
||||
|
||||
class FieldConfigurationWidget(ConfigurationWidget):
|
||||
def __init__(self):
|
||||
ConfigurationWidget.__init__(self)
|
||||
|
||||
self.keyIndexI = QSpinBox()
|
||||
self.keyIndexI.setMinimum(1)
|
||||
|
||||
self.addRow("i:", self.keyIndexI)
|
||||
|
||||
self.keyIndexJ = QSpinBox()
|
||||
self.keyIndexJ.setMinimum(1)
|
||||
self.addRow("j:", self.keyIndexJ)
|
||||
|
||||
self.keyIndexK = QSpinBox()
|
||||
self.keyIndexK.setMinimum(1)
|
||||
self.addRow("k:", self.keyIndexK)
|
||||
|
||||
self.setFieldBounds(1, 1, 1)
|
||||
|
||||
self.connect(self.keyIndexI, SIGNAL('valueChanged(int)'), self.applyConfiguration)
|
||||
self.connect(self.keyIndexJ, SIGNAL('valueChanged(int)'), self.applyConfiguration)
|
||||
self.connect(self.keyIndexK, SIGNAL('valueChanged(int)'), self.applyConfiguration)
|
||||
|
||||
def setFieldBounds(self, i, j, k):
|
||||
self.keyIndexI.setMaximum(i)
|
||||
self.keyIndexJ.setMaximum(j)
|
||||
self.keyIndexK.setMaximum(k)
|
||||
|
||||
def getFieldPosition(self):
|
||||
return (self.keyIndexI.value(), self.keyIndexJ.value(), self.keyIndexK.value())
|
||||
|
||||
def setParameter(self, parameter):
|
||||
self.parameter = parameter
|
||||
self.applyConfiguration(False)
|
||||
|
||||
def applyConfiguration(self, emit=True):
|
||||
user_data = {'state': self.getState(), 'field_position': self.getFieldPosition()}
|
||||
self.parameter.setUserData(user_data)
|
||||
self.emitConfigurationChanged(emit)
|
||||
|
||||
|
||||
class KeywordConfigurationWidget(ConfigurationWidget):
|
||||
def __init__(self):
|
||||
ConfigurationWidget.__init__(self)
|
||||
self.keyIndexCombo = QComboBox()
|
||||
self.addRow("Key index:", self.keyIndexCombo)
|
||||
|
||||
self.connect(self.keyIndexCombo, SIGNAL('currentIndexChanged(QString)'), self.applyConfiguration)
|
||||
|
||||
def setKeyIndexList(self, list):
|
||||
self.disconnect(self.keyIndexCombo, SIGNAL('currentIndexChanged(QString)'), self.applyConfiguration)
|
||||
self.keyIndexCombo.clear()
|
||||
self.keyIndexCombo.addItems(list)
|
||||
self.connect(self.keyIndexCombo, SIGNAL('currentIndexChanged(QString)'), self.applyConfiguration)
|
||||
|
||||
def setParameter(self, parameter):
|
||||
self.parameter = parameter
|
||||
self.applyConfiguration(False)
|
||||
|
||||
def applyConfiguration(self, emit=True):
|
||||
user_data = {'state': self.getState(), 'key_index' : self.getKeyIndex()}
|
||||
self.parameter.setUserData(user_data)
|
||||
self.emitConfigurationChanged(emit)
|
||||
|
||||
def getKeyIndex(self):
|
||||
return str(self.keyIndexCombo.currentText())
|
||||
|
||||
class DataConfigurationWidget(ConfigurationWidget):
|
||||
def __init__(self):
|
||||
ConfigurationWidget.__init__(self)
|
||||
|
||||
self.keyIndex = QSpinBox()
|
||||
self.keyIndex.setMinimum(0)
|
||||
|
||||
self.addRow("index:", self.keyIndex)
|
||||
|
||||
self.setIndexBounds(0)
|
||||
|
||||
self.connect(self.keyIndex, SIGNAL('valueChanged(int)'), self.applyConfiguration)
|
||||
|
||||
def setIndexBounds(self, i):
|
||||
self.keyIndex.setMaximum(i)
|
||||
|
||||
def getIndex(self):
|
||||
return self.keyIndex.value()
|
||||
|
||||
def setParameter(self, parameter):
|
||||
self.parameter = parameter
|
||||
self.applyConfiguration(False)
|
||||
|
||||
def applyConfiguration(self, emit=True):
|
||||
user_data = {'state': self.getState(), 'data_index': self.getIndex()}
|
||||
self.parameter.setUserData(user_data)
|
||||
self.emitConfigurationChanged(emit)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'fetcher.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4.QtCore import QObject
|
||||
|
||||
class PlotDataFetcherHandler(QObject):
|
||||
"""An interface for data fetchers."""
|
||||
|
||||
def __init__(self):
|
||||
QObject.__init__(self)
|
||||
|
||||
def isHandlerFor(self, ert, key):
|
||||
"""Retrun True if this handler can handle key."""
|
||||
return False
|
||||
|
||||
def initialize(self, ert):
|
||||
"""Prototype functions and types."""
|
||||
pass
|
||||
|
||||
def fetch(self, ert, key, parameter, data, comparison_fs):
|
||||
"""
|
||||
Fetch data from ert by key. Key has already been tested with isHandlerFor()
|
||||
Parameter contains configuration data. data is the target.
|
||||
comparison_fs is the fs to the case which the plotter should use for comparison plot data
|
||||
"""
|
||||
pass
|
||||
|
||||
def getConfigurationWidget(self, context_data):
|
||||
"""Return a widget to configure this handler."""
|
||||
pass
|
||||
|
||||
def configure(self, parameter, context_data):
|
||||
"""
|
||||
Set the current parameter to configure.
|
||||
Should always be called before getConfigurationWidget().
|
||||
"""
|
||||
pass
|
||||
@@ -1,259 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'plotconfig.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4.QtCore import QObject, QSize
|
||||
from PyQt4.Qt import SIGNAL
|
||||
from PyQt4.QtGui import QFormLayout, QFrame, QComboBox, QHBoxLayout, QDoubleSpinBox, QWidget, QPainter, QColor, QColorDialog
|
||||
from PyQt4.QtGui import QCheckBox, QDialog
|
||||
|
||||
class PlotConfig(object):
|
||||
"""
|
||||
Plot config represents settings information relating to plot lines.
|
||||
All values are available as properties.
|
||||
"""
|
||||
|
||||
def __init__(self, name, linestyle="-", marker="", color=(0.0, 0.0, 0.0), alpha=0.75, zorder=1, picker=None, visible=True):
|
||||
self._name = name
|
||||
self._linestyle = linestyle
|
||||
self._marker = marker
|
||||
self._color = color
|
||||
self._alpha = alpha
|
||||
self._is_visible = visible
|
||||
self._z_order = zorder
|
||||
self._picker = picker
|
||||
|
||||
self.signal_handler = QObject()
|
||||
|
||||
def notify(self):
|
||||
"""Tell all listeners that something has changed. Automatically called by setters."""
|
||||
self.signal_handler.emit(SIGNAL('plotConfigChanged(PlotConfig)'), self)
|
||||
|
||||
def get_name(self):
|
||||
return self._name
|
||||
|
||||
name = property(get_name, doc="The name of this plot.")
|
||||
|
||||
def hasStyle(self):
|
||||
return not self.style == ""
|
||||
|
||||
def get_style(self):
|
||||
return (str(self._marker) + str(self._linestyle)).strip()
|
||||
|
||||
style = property(get_style, doc="Returns the combined style of line style and marker style.")
|
||||
|
||||
def setLinestyle(self, linestyle):
|
||||
self._linestyle = linestyle
|
||||
self.notify()
|
||||
|
||||
def getLinestyle(self):
|
||||
return self._linestyle
|
||||
|
||||
linestyle = property(getLinestyle, setLinestyle, doc="Line style")
|
||||
|
||||
def setMarker(self, marker):
|
||||
self._marker = marker
|
||||
self.notify()
|
||||
|
||||
def getMarker(self):
|
||||
return self._marker
|
||||
|
||||
marker = property(getMarker, setMarker, doc="Marker style")
|
||||
|
||||
def setAlpha(self, alpha):
|
||||
self._alpha = alpha
|
||||
self.notify()
|
||||
|
||||
def getAlpha(self):
|
||||
return self._alpha
|
||||
|
||||
alpha = property(getAlpha, setAlpha, doc="Transparency of the line. 1 = Opaque ... 0 transparent.")
|
||||
|
||||
def setColor(self, color):
|
||||
self._color = color
|
||||
self.notify()
|
||||
|
||||
def getColor(self):
|
||||
return self._color
|
||||
|
||||
color = property(getColor, setColor, doc="Color of the line.")
|
||||
|
||||
|
||||
def set_is_visible(self, is_visible):
|
||||
self._is_visible = is_visible
|
||||
self.notify()
|
||||
|
||||
def is_visible(self):
|
||||
return self._is_visible
|
||||
|
||||
is_visible = property(is_visible, set_is_visible, doc="Hide or show the plotline.")
|
||||
|
||||
def set_z_order(self, z_order):
|
||||
self._z_order = z_order
|
||||
self.notify()
|
||||
|
||||
def get_z_order(self):
|
||||
return self._z_order
|
||||
|
||||
z_order = property(get_z_order, set_z_order, doc="Z drawing order. 10 = top ... 1 = bottom.")
|
||||
|
||||
def setPicker(self, picker):
|
||||
self._picker = picker
|
||||
self.notify()
|
||||
|
||||
def getPicker(self):
|
||||
return self._picker
|
||||
|
||||
picker = property(getPicker, setPicker, doc="Picker radius")
|
||||
|
||||
|
||||
|
||||
class PlotConfigPanel(QFrame):
|
||||
"""A panel to interact with PlotConfig instances."""
|
||||
plot_marker_styles = ["", ".", ",", "o", "*", "s", "+", "x", "p", "h", "H", "D", "d"]
|
||||
plot_line_styles = ["", "-", "--", "-.", ":"]
|
||||
|
||||
def __init__(self, plot_config):
|
||||
QFrame.__init__(self)
|
||||
self.plot_config = plot_config
|
||||
self.connect(plot_config.signal_handler, SIGNAL('plotConfigChanged(PlotConfig)'), self._fetchValues)
|
||||
|
||||
layout = QFormLayout()
|
||||
layout.setRowWrapPolicy(QFormLayout.WrapLongRows)
|
||||
|
||||
self.chk_visible = QCheckBox()
|
||||
layout.addRow("Visible:", self.chk_visible)
|
||||
self.connect(self.chk_visible, SIGNAL('stateChanged(int)'), self._setVisibleState)
|
||||
|
||||
self.plot_linestyle = QComboBox()
|
||||
self.plot_linestyle.addItems(self.plot_line_styles)
|
||||
self.connect(self.plot_linestyle, SIGNAL("currentIndexChanged(QString)"), self._setLineStyle)
|
||||
layout.addRow("Line style:", self.plot_linestyle)
|
||||
|
||||
self.plot_marker_style = QComboBox()
|
||||
self.plot_marker_style.addItems(self.plot_marker_styles)
|
||||
self.connect(self.plot_marker_style, SIGNAL("currentIndexChanged(QString)"), self._setMarker)
|
||||
layout.addRow("Marker style:", self.plot_marker_style)
|
||||
|
||||
|
||||
|
||||
self.alpha_spinner = QDoubleSpinBox(self)
|
||||
self.alpha_spinner.setMinimum(0.0)
|
||||
self.alpha_spinner.setMaximum(1.0)
|
||||
self.alpha_spinner.setDecimals(3)
|
||||
self.alpha_spinner.setSingleStep(0.01)
|
||||
|
||||
self.connect(self.alpha_spinner, SIGNAL('valueChanged(double)'), self._setAlpha)
|
||||
layout.addRow("Blend factor:", self.alpha_spinner)
|
||||
|
||||
self.color_picker = ColorPicker(plot_config)
|
||||
layout.addRow("Color:", self.color_picker)
|
||||
|
||||
self.setLayout(layout)
|
||||
self._fetchValues(plot_config)
|
||||
|
||||
def _fetchValues(self, plot_config):
|
||||
"""Fetch values from a PlotConfig and insert into the panel."""
|
||||
self.plot_config = plot_config
|
||||
|
||||
#block signals to avoid updating the incoming plot_config
|
||||
|
||||
state = self.plot_linestyle.blockSignals(True)
|
||||
linestyle_index = self.plot_line_styles.index(self.plot_config.linestyle)
|
||||
self.plot_linestyle.setCurrentIndex(linestyle_index)
|
||||
self.plot_linestyle.blockSignals(state)
|
||||
|
||||
state = self.plot_marker_style.blockSignals(True)
|
||||
marker_index = self.plot_marker_styles.index(self.plot_config.marker)
|
||||
self.plot_marker_style.setCurrentIndex(marker_index)
|
||||
self.plot_marker_style.blockSignals(state)
|
||||
|
||||
state = self.alpha_spinner.blockSignals(True)
|
||||
self.alpha_spinner.setValue(self.plot_config.alpha)
|
||||
self.alpha_spinner.blockSignals(state)
|
||||
|
||||
state = self.chk_visible.blockSignals(True)
|
||||
self.chk_visible.setChecked(self.plot_config.is_visible)
|
||||
self.chk_visible.blockSignals(state)
|
||||
|
||||
self.color_picker.update()
|
||||
|
||||
#-------------------------------------------
|
||||
# update plot config from widgets
|
||||
#-------------------------------------------
|
||||
def _setLineStyle(self, linestyle):
|
||||
self.plot_config.linestyle = linestyle
|
||||
|
||||
def _setMarker(self, marker):
|
||||
self.plot_config.marker = marker
|
||||
|
||||
def _setAlpha(self, alpha):
|
||||
self.plot_config.alpha = alpha
|
||||
|
||||
def _setVisibleState(self, state):
|
||||
self.plot_config.is_visible = state == 2
|
||||
|
||||
|
||||
|
||||
class ColorPicker(QWidget):
|
||||
"""A widget that shows a colored box and pops up a color dialog."""
|
||||
color_dialog = QColorDialog()
|
||||
|
||||
def __init__(self, plot_config):
|
||||
QWidget.__init__(self)
|
||||
|
||||
self.plot_config = plot_config
|
||||
|
||||
size = 20
|
||||
self.setMaximumSize(QSize(size, size))
|
||||
self.setMinimumSize(QSize(size, size))
|
||||
self.setToolTip("Click to change color!")
|
||||
|
||||
def paintEvent(self, paintevent):
|
||||
"""Paints the box"""
|
||||
painter = QPainter(self)
|
||||
|
||||
rect = self.contentsRect()
|
||||
rect.setWidth(rect.width() - 1)
|
||||
rect.setHeight(rect.height() - 1)
|
||||
painter.drawRect(rect)
|
||||
|
||||
rect.setX(rect.x() + 1)
|
||||
rect.setY(rect.y() + 1)
|
||||
painter.fillRect(rect, self._getColor())
|
||||
|
||||
def _setColor(self, color):
|
||||
"""Set the color of this picker."""
|
||||
self.plot_config.color = (color.redF(), color.greenF(), color.blueF())
|
||||
self.update()
|
||||
|
||||
def _getColor(self):
|
||||
"""Return the color of this picker as QColor."""
|
||||
color = self.plot_config.color
|
||||
return QColor(int(color[0] * 255), int(color[1] * 255), int(color[2] * 255))
|
||||
|
||||
def mouseDoubleClickEvent(self, event):
|
||||
self.color_dialog.setCurrentColor(self._getColor())
|
||||
status = self.color_dialog.exec_()
|
||||
if status == QDialog.Accepted:
|
||||
self._setColor(self.color_dialog.selectedColor())
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
self.color_dialog.setCurrentColor(self._getColor())
|
||||
status = self.color_dialog.exec_()
|
||||
if status == QDialog.Accepted:
|
||||
self._setColor(self.color_dialog.selectedColor())
|
||||
|
||||
@@ -1,356 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'plotdata.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from ert.ert.erttypes import time_t
|
||||
from ert_gui.widgets.helpedwidget import ContentModel
|
||||
from ert_gui.widgets.util import print_timing, resourceIcon
|
||||
from ert_gui.pages.config.parameters.parametermodels import DataModel, KeywordModel, FieldModel, SummaryModel
|
||||
from ert_gui.pages.config.parameters.parameterpanel import Parameter
|
||||
import ert.ert.enums as enums
|
||||
import sys
|
||||
from ert.ert.enums import obs_impl_type
|
||||
|
||||
from ensemblefetcher import EnsembleFetcher
|
||||
from rftfetcher import RFTFetcher
|
||||
from PyQt4.QtGui import QFrame
|
||||
from PyQt4.QtCore import SIGNAL, QObject
|
||||
import ert_gui.widgets as widgets
|
||||
|
||||
|
||||
|
||||
|
||||
class PlotDataFetcher(ContentModel, QObject):
|
||||
|
||||
def __init__(self):
|
||||
ContentModel.__init__(self)
|
||||
QObject.__init__(self)
|
||||
self.parameter = None
|
||||
|
||||
# the order of these handlers depend on ERT's way of keeping track of the keys
|
||||
self.handlers = [RFTFetcher(), EnsembleFetcher()]
|
||||
self.current_handler = None
|
||||
self.empty_panel = QFrame()
|
||||
|
||||
self.fs_for_comparison_plots = None
|
||||
self.comparison_fs_name = "None"
|
||||
self.data = None
|
||||
|
||||
def initialize(self, ert):
|
||||
for handler in self.handlers:
|
||||
handler.initialize(ert)
|
||||
self.connect(handler, SIGNAL('dataChanged()'), self.__dataChanged)
|
||||
|
||||
ert.prototype("long enkf_main_mount_extra_fs(long, char*)")
|
||||
ert.prototype("void enkf_fs_free(long)")
|
||||
|
||||
|
||||
#@print_timing
|
||||
@widgets.util.may_take_a_long_time
|
||||
def getter(self, ert):
|
||||
data = PlotData()
|
||||
if not self.parameter is None:
|
||||
key = self.parameter.getName()
|
||||
data.setName(key)
|
||||
|
||||
for handler in self.handlers:
|
||||
if handler.isHandlerFor(ert, key):
|
||||
handler.fetch(ert, key, self.parameter, data, self.fs_for_comparison_plots)
|
||||
self.current_handler = handler
|
||||
break
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def __dataChanged(self):
|
||||
self.fetchContent()
|
||||
self.emit(SIGNAL('dataChanged()'))
|
||||
|
||||
def fetchContent(self):
|
||||
self.data = self.getFromModel()
|
||||
|
||||
def setParameter(self, parameter, context_data):
|
||||
self.findHandler(parameter.getName())
|
||||
if not self.current_handler is None:
|
||||
self.parameter = parameter
|
||||
self.current_handler.configure(parameter, context_data)
|
||||
|
||||
def getParameter(self):
|
||||
return self.parameter
|
||||
|
||||
def getConfigurationWidget(self, context_data):
|
||||
if self.current_handler is None:
|
||||
return self.empty_panel
|
||||
else:
|
||||
cw = self.current_handler.getConfigurationWidget(context_data)
|
||||
if cw is None:
|
||||
cw = self.empty_panel
|
||||
return cw
|
||||
|
||||
def findHandler(self, key):
|
||||
ert = self.getModel()
|
||||
self.current_handler = None
|
||||
for handler in self.handlers:
|
||||
if handler.isHandlerFor(ert, key): #todo: what about multiple hits?
|
||||
self.current_handler = handler
|
||||
break
|
||||
|
||||
def updateComparisonFS(self, new_fs):
|
||||
if not new_fs == self.comparison_fs_name:
|
||||
ert = self.getModel()
|
||||
|
||||
if self.fs_for_comparison_plots:
|
||||
ert.enkf.enkf_fs_free(self.fs_for_comparison_plots)
|
||||
self.fs_for_comparison_plots = None
|
||||
self.comparison_fs_name = "None"
|
||||
|
||||
if not new_fs == "None":
|
||||
self.fs_for_comparison_plots = ert.enkf.enkf_main_mount_extra_fs(ert.main, new_fs)
|
||||
self.comparison_fs_name = new_fs
|
||||
|
||||
self.__dataChanged()
|
||||
|
||||
|
||||
|
||||
class PlotData:
|
||||
def __init__(self, name="undefined"):
|
||||
self.name = name
|
||||
self.key_index = None
|
||||
|
||||
self.x_data = {}
|
||||
self.y_data = {}
|
||||
|
||||
self.x_comp_data = {}
|
||||
self.y_comp_data = {}
|
||||
|
||||
self.obs_x = None
|
||||
self.obs_y = None
|
||||
self.obs_std_x = None
|
||||
self.obs_std_y = None
|
||||
|
||||
self.refcase_x = None
|
||||
self.refcase_y = None
|
||||
|
||||
|
||||
self.x_min = None
|
||||
self.x_max = None
|
||||
|
||||
self.y_min = None
|
||||
self.y_max = None
|
||||
|
||||
self.y_data_type = "number"
|
||||
self.x_data_type = "time"
|
||||
|
||||
self.inverted_y_axis = False
|
||||
|
||||
self.valid = True
|
||||
self.key_index_is_index = False
|
||||
|
||||
def checkMaxMin(self, value):
|
||||
if self.x_min is None or self.x_max is None:
|
||||
self.x_min = value
|
||||
self.x_max = value
|
||||
|
||||
self.x_min = min(value, self.x_min)
|
||||
self.x_max = max(value, self.x_max)
|
||||
|
||||
def checkMaxMinY(self, value):
|
||||
if self.y_min is None or self.y_max is None:
|
||||
self.y_min = value
|
||||
self.y_max = value
|
||||
|
||||
self.y_min = min(value, self.y_min)
|
||||
self.y_max = max(value, self.y_max)
|
||||
|
||||
def getName(self):
|
||||
return self.name
|
||||
|
||||
def setName(self, name):
|
||||
self.name = name
|
||||
|
||||
def setKeyIndex(self, key_index):
|
||||
self.key_index = key_index
|
||||
|
||||
def getKeyIndex(self):
|
||||
return self.key_index
|
||||
|
||||
def getXDataType(self):
|
||||
return self.x_data_type
|
||||
|
||||
def getYDataType(self):
|
||||
return self.y_data_type
|
||||
|
||||
def hasInvertedYAxis(self):
|
||||
return self.inverted_y_axis
|
||||
|
||||
def getTitle(self):
|
||||
name = self.getName()
|
||||
key_index = self.getKeyIndex()
|
||||
|
||||
title = name
|
||||
if not key_index is None:
|
||||
title = "%s (%s)" % (name, key_index)
|
||||
|
||||
return title
|
||||
|
||||
def isValid(self):
|
||||
return self.valid
|
||||
|
||||
def setValid(self, valid):
|
||||
self.valid = valid
|
||||
|
||||
def setKeyIndexIsIndex(self, bool):
|
||||
self.key_index_is_index = bool
|
||||
|
||||
def getSaveName(self):
|
||||
if self.key_index_is_index or self.getKeyIndex() is None:
|
||||
return self.getName()
|
||||
else:
|
||||
return ("%s.%s" % (self.getName(), self.getKeyIndex()))
|
||||
|
||||
|
||||
|
||||
class PlotContextDataFetcher(ContentModel):
|
||||
|
||||
observation_icon = resourceIcon("observation")
|
||||
|
||||
def __init__(self):
|
||||
ContentModel.__init__(self)
|
||||
|
||||
def initialize(self, ert):
|
||||
|
||||
ert.prototype("long enkf_config_node_get_impl_type(long)")
|
||||
ert.prototype("long enkf_config_node_get_ref(long)")
|
||||
|
||||
ert.prototype("long gen_kw_config_alloc_name_list(long)")
|
||||
|
||||
ert.prototype("long gen_data_config_get_initial_size(long)")
|
||||
|
||||
ert.prototype("int field_config_get_nx(long)")
|
||||
ert.prototype("int field_config_get_ny(long)")
|
||||
ert.prototype("int field_config_get_nz(long)")
|
||||
|
||||
ert.prototype("long enkf_main_get_fs(long)")
|
||||
ert.prototype("char* enkf_fs_get_read_dir(long)")
|
||||
ert.prototype("long enkf_fs_alloc_dirlist(long)")
|
||||
|
||||
ert.prototype("int plot_config_get_errorbar_max(long)")
|
||||
ert.prototype("char* plot_config_get_path(long)")
|
||||
|
||||
ert.prototype("long enkf_main_get_obs(long)")
|
||||
ert.prototype("long enkf_obs_alloc_typed_keylist(long, int)")
|
||||
|
||||
self.modelConnect("casesUpdated()", self.fetchContent)
|
||||
|
||||
|
||||
#@print_timing
|
||||
def getter(self, ert):
|
||||
data = PlotContextData()
|
||||
|
||||
keys = ert.getStringList(ert.enkf.ensemble_config_alloc_keylist(ert.ensemble_config), free_after_use=True)
|
||||
data.keys = keys
|
||||
data.parameters = []
|
||||
|
||||
for key in keys:
|
||||
config_node = ert.enkf.ensemble_config_get_node(ert.ensemble_config, key)
|
||||
type = ert.enkf.enkf_config_node_get_impl_type(config_node)
|
||||
node_ref = ert.enkf.enkf_config_node_get_ref(config_node)
|
||||
|
||||
if type == SummaryModel.TYPE:
|
||||
p = Parameter(key, SummaryModel.TYPE)
|
||||
data.parameters.append(p)
|
||||
|
||||
elif type == FieldModel.TYPE:
|
||||
p = Parameter(key, FieldModel.TYPE)
|
||||
data.parameters.append(p)
|
||||
|
||||
if data.field_bounds is None:
|
||||
x = ert.enkf.field_config_get_nx(node_ref)
|
||||
y = ert.enkf.field_config_get_ny(node_ref)
|
||||
z = ert.enkf.field_config_get_nz(node_ref)
|
||||
data.field_bounds = (x,y,z)
|
||||
|
||||
elif type == DataModel.TYPE:
|
||||
data.parameters.append(Parameter(key, DataModel.TYPE))
|
||||
data.gen_data_size = ert.enkf.gen_data_config_get_initial_size(node_ref)
|
||||
|
||||
elif type == KeywordModel.TYPE:
|
||||
p = Parameter(key, KeywordModel.TYPE)
|
||||
data.parameters.append(p)
|
||||
s = ert.enkf.gen_kw_config_alloc_name_list(node_ref)
|
||||
data.key_index_list[key] = ert.getStringList(s, free_after_use=True)
|
||||
|
||||
data.errorbar_max = ert.enkf.plot_config_get_errorbar_max(ert.plot_config)
|
||||
|
||||
fs = ert.enkf.enkf_main_get_fs(ert.main)
|
||||
current_case = "default" #ert.enkf.enkf_fs_get_read_dir(fs)
|
||||
|
||||
data.plot_config_path = ert.enkf.plot_config_get_path(ert.plot_config)
|
||||
#data.plot_path = ert.enkf.plot_config_get_path(ert.plot_config) + "/" + current_case
|
||||
data.plot_path = "PLOTXXX"
|
||||
|
||||
enkf_obs = ert.enkf.enkf_main_get_obs(ert.main)
|
||||
key_list = ert.enkf.enkf_obs_alloc_typed_keylist(enkf_obs, obs_impl_type.FIELD_OBS.value())
|
||||
field_obs = ert.getStringList(key_list, free_after_use=True)
|
||||
|
||||
for obs in field_obs:
|
||||
p = Parameter(obs, obs_impl_type.FIELD_OBS, PlotContextDataFetcher.observation_icon)
|
||||
data.parameters.append(p)
|
||||
|
||||
|
||||
#case_list_pointer = ert.enkf.enkf_fs_alloc_dirlist(fs)
|
||||
#case_list = ert.getStringList(case_list_pointer)
|
||||
case_list = ["default"]
|
||||
data.current_case = current_case
|
||||
#ert.freeStringList(case_list_pointer)
|
||||
|
||||
for case in case_list:
|
||||
data.case_list.append(case)
|
||||
|
||||
return data
|
||||
|
||||
def fetchContent(self):
|
||||
self.data = self.getFromModel()
|
||||
|
||||
|
||||
class PlotContextData:
|
||||
def __init__(self):
|
||||
self.keys = None
|
||||
self.parameters = None
|
||||
self.key_index_list = {}
|
||||
self.errorbar_max = 0
|
||||
self.plot_path = ""
|
||||
self.plot_config_path = ""
|
||||
self.field_bounds = None
|
||||
self.gen_data_size = 0
|
||||
self.case_list = ["None"]
|
||||
self.current_case = None
|
||||
|
||||
def getKeyIndexList(self, key):
|
||||
if self.key_index_list.has_key(key):
|
||||
return self.key_index_list[key]
|
||||
else:
|
||||
return []
|
||||
|
||||
def getComparableCases(self):
|
||||
cases = []
|
||||
|
||||
for case in self.case_list:
|
||||
if not case == self.current_case:
|
||||
cases.append(case)
|
||||
|
||||
return cases
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'plotfigure.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from matplotlib.figure import Figure
|
||||
import matplotlib.lines
|
||||
import matplotlib.text
|
||||
|
||||
import numpy
|
||||
import ert.ert.erttypes as erttypes
|
||||
import plotsettings
|
||||
from plotrenderer import DefaultPlotRenderer
|
||||
|
||||
class PlotFigure:
|
||||
"""A simple wrapper for a matplotlib Figure. Associated with a specified renderer."""
|
||||
def __init__(self):
|
||||
self.fig = Figure(dpi=100)
|
||||
self.axes = self.fig.add_subplot(111)
|
||||
self.fig.subplots_adjust(left=0.15)
|
||||
self.axes.set_xlim()
|
||||
self.plot_renderer = DefaultPlotRenderer()
|
||||
|
||||
def getFigure(self):
|
||||
"""Return the matplotlib figure."""
|
||||
return self.fig
|
||||
|
||||
def drawPlot(self, plot_data, plot_settings):
|
||||
"""Draw a plot based on the specified data and settings."""
|
||||
self.axes.cla()
|
||||
|
||||
self.plot_renderer.drawPlot(self.axes, plot_data, plot_settings)
|
||||
|
||||
if plot_data.getXDataType() == "time":
|
||||
self.fig.autofmt_xdate()
|
||||
|
||||
|
||||
|
||||
@@ -1,172 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'plotgenerator.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
import os
|
||||
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
|
||||
from PyQt4.QtGui import QFrame, QSizePolicy, QVBoxLayout, QCursor, QDialog, QDialogButtonBox
|
||||
from plotfigure import PlotFigure
|
||||
from PyQt4.QtCore import Qt, QPoint, QSize, SIGNAL
|
||||
from PyQt4.QtGui import QProgressBar, QApplication
|
||||
import threading
|
||||
from plotsettingsxml import PlotSettingsLoader
|
||||
from plotsettings import PlotSettings
|
||||
from plotdata import PlotContextDataFetcher, PlotDataFetcher
|
||||
from ert_gui.pages.config.parameters.parametermodels import SummaryModel, KeywordModel
|
||||
import ert.ert.enums as enums
|
||||
|
||||
class PlotGenerator(QFrame):
|
||||
|
||||
def __init__(self, plot_path, plot_config_path):
|
||||
QFrame.__init__(self)
|
||||
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||
|
||||
self.plot_figure = PlotFigure()
|
||||
self.canvas = FigureCanvas(self.plot_figure.getFigure())
|
||||
self.canvas.setParent(self)
|
||||
self.canvas.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
|
||||
|
||||
size = QSize(297*2, 210*2) # A4 aspectratio
|
||||
self.canvas.setMaximumSize(size)
|
||||
self.canvas.setMinimumSize(size)
|
||||
self.setMaximumSize(size)
|
||||
self.setMinimumSize(size)
|
||||
|
||||
self.popup = Popup(self)
|
||||
self.plot_config_loader = PlotSettingsLoader()
|
||||
self.plot_settings = PlotSettings()
|
||||
self.plot_settings.setPlotPath(plot_path)
|
||||
self.plot_settings.setPlotConfigPath(plot_config_path)
|
||||
self.connect(self.popup, SIGNAL('updateProgress(int)'), self.updateProgress)
|
||||
|
||||
|
||||
self.plot_context_data_fetcher = PlotContextDataFetcher()
|
||||
self.plot_context_data_fetcher.initialize(self.plot_context_data_fetcher.getModel())
|
||||
self.plot_data_fetcher = PlotDataFetcher()
|
||||
self.plot_data_fetcher.initialize(self.plot_data_fetcher.getModel())
|
||||
|
||||
def updateProgress(self, progress = 1):
|
||||
value = self.popup.progress_bar.value()
|
||||
self.popup.progress_bar.setValue(value + progress)
|
||||
|
||||
def saveAll(self):
|
||||
self.popup.show()
|
||||
|
||||
context_data = self.plot_context_data_fetcher.getFromModel()
|
||||
|
||||
save_list = []
|
||||
count = 0
|
||||
for parameter in context_data.parameters:
|
||||
pt = parameter.type
|
||||
|
||||
if pt == SummaryModel.TYPE or pt == KeywordModel.TYPE or pt == enums.obs_impl_type.FIELD_OBS:
|
||||
save_list.append(parameter)
|
||||
parameter.setUserData({'state' : enums.ert_state_enum.FORECAST})
|
||||
|
||||
if pt == KeywordModel.TYPE:
|
||||
choices = context_data.key_index_list[parameter.name]
|
||||
parameter.getUserData()['key_index_choices'] = choices
|
||||
count += len(choices)
|
||||
else:
|
||||
count += 1
|
||||
|
||||
|
||||
self.popup.progress_bar.setMaximum(count)
|
||||
|
||||
for parameter in save_list:
|
||||
if parameter.type == KeywordModel.TYPE:
|
||||
for choice in parameter.getUserData()['key_index_choices']:
|
||||
self.plot_data_fetcher.setParameter(parameter, context_data)
|
||||
parameter.getUserData()['key_index'] = choice # because setParameter overwrites this value
|
||||
self.plot_data_fetcher.fetchContent()
|
||||
self.savePlot(self.plot_data_fetcher.data)
|
||||
else:
|
||||
self.plot_data_fetcher.setParameter(parameter, context_data)
|
||||
self.plot_data_fetcher.fetchContent()
|
||||
self.savePlot(self.plot_data_fetcher.data)
|
||||
|
||||
self.popup.ok_button.setEnabled(True)
|
||||
|
||||
def save(self, plot_data):
|
||||
self.popup.show()
|
||||
|
||||
self.popup.progress_bar.setMaximum(1)
|
||||
|
||||
self.savePlot(plot_data)
|
||||
self.popup.ok_button.setEnabled(True)
|
||||
|
||||
|
||||
def savePlot(self, plot_data):
|
||||
generated_plot = self.generatePlot(plot_data)
|
||||
if generated_plot:
|
||||
self.savePlotToFile(plot_data.getSaveName())
|
||||
self.popup.emit(SIGNAL('updateProgress(int)'), 1)
|
||||
|
||||
def generatePlot(self, plot_data):
|
||||
name = plot_data.getSaveName()
|
||||
load_success = self.plot_config_loader.load(name, self.plot_settings)
|
||||
|
||||
if load_success:
|
||||
self.plot_figure.drawPlot(plot_data, self.plot_settings)
|
||||
self.canvas.draw()
|
||||
|
||||
return load_success
|
||||
|
||||
def savePlotToFile(self, filename):
|
||||
"""Save the plot visible in the figure."""
|
||||
plot_path = self.plot_settings.getPlotPath()
|
||||
if not os.path.exists(plot_path):
|
||||
os.makedirs(plot_path)
|
||||
|
||||
path = plot_path + "/" + filename
|
||||
self.plot_figure.getFigure().savefig(path + ".png", dpi=400, format="png")
|
||||
self.plot_figure.getFigure().savefig(path + ".pdf", dpi=400, format="pdf")
|
||||
|
||||
|
||||
class Popup(QDialog):
|
||||
def __init__(self, widget, parent = None):
|
||||
QDialog.__init__(self, parent)
|
||||
self.setModal(True)
|
||||
self.setWindowTitle("Plot save progress")
|
||||
|
||||
layout = QVBoxLayout()
|
||||
layout.addWidget(widget)
|
||||
|
||||
self.progress_bar = QProgressBar()
|
||||
self.progress_bar.setMinimum(0)
|
||||
self.progress_bar.setMaximum(1)
|
||||
self.progress_bar.setValue(0)
|
||||
layout.addWidget(self.progress_bar)
|
||||
|
||||
buttons = QDialogButtonBox(QDialogButtonBox.Ok, Qt.Horizontal, self)
|
||||
layout.addWidget(buttons)
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
self.connect(buttons, SIGNAL('accepted()'), self.accept)
|
||||
|
||||
self.ok_button = buttons.button(QDialogButtonBox.Ok)
|
||||
self.ok_button.setEnabled(False)
|
||||
|
||||
def closeEvent(self, event):
|
||||
"""Ignore clicking of the x in the top right corner"""
|
||||
event.ignore()
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
"""Ignore ESC keystrokes"""
|
||||
if not event.key() == Qt.Key_Escape:
|
||||
QDialog.keyPressEvent(self, event)
|
||||
|
||||
@@ -1,436 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'plotpanel.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from ert_gui.pages.config.parameters.parameterpanel import Parameter
|
||||
from ert_gui.pages.plot.plotview import PlotView
|
||||
import ert_gui.pages.config.parameters.parameterpanel
|
||||
import ert_gui.widgets.helpedwidget
|
||||
from ert_gui.widgets.helpedwidget import ContentModel
|
||||
from ert_gui.pages.config.parameters.parametermodels import DataModel, FieldModel, KeywordModel, SummaryModel
|
||||
from ert_gui.pages.plot.plotdata import PlotContextDataFetcher, PlotDataFetcher, enums
|
||||
import ert_gui.widgets.util
|
||||
import datetime
|
||||
import time
|
||||
import matplotlib.dates
|
||||
from zoomslider import ZoomSlider
|
||||
from ert_gui.widgets.configpanel import ConfigPanel
|
||||
from PyQt4.Qt import SIGNAL
|
||||
from PyQt4.QtCore import QDate, Qt, QPoint
|
||||
from plotconfig import PlotConfigPanel
|
||||
from PyQt4.QtGui import QTabWidget, QFormLayout, QFrame, QVBoxLayout, QHBoxLayout, QCheckBox, QPushButton, QToolButton, QMainWindow
|
||||
from PyQt4.QtGui import QCalendarWidget
|
||||
import plotsettings
|
||||
import ert.ert.erttypes as erttypes
|
||||
|
||||
class PlotPanel(QtGui.QWidget):
|
||||
def __init__(self):
|
||||
QtGui.QWidget.__init__(self)
|
||||
|
||||
plotLayout = QtGui.QHBoxLayout()
|
||||
|
||||
self.plot = PlotView()
|
||||
|
||||
parameterLayout = QtGui.QVBoxLayout()
|
||||
self.plotList = QtGui.QListWidget(self)
|
||||
self.plotList.setMaximumWidth(150)
|
||||
self.plotList.setMinimumWidth(150)
|
||||
|
||||
self.plotDataPanel = PlotParameterConfigurationPanel(self, 150)
|
||||
parameterLayout.addWidget(self.plotList)
|
||||
parameterLayout.addWidget(self.plotDataPanel)
|
||||
|
||||
self.connect(self.plotList, QtCore.SIGNAL('currentItemChanged(QListWidgetItem *, QListWidgetItem *)'),
|
||||
self.select)
|
||||
ContentModel.modelConnect('initialized()', self.updateList)
|
||||
|
||||
#todo: listen to ensemble changes!
|
||||
|
||||
|
||||
self.plotDataFetcher = PlotDataFetcher()
|
||||
self.connect(self.plotDataFetcher, QtCore.SIGNAL('dataChanged()'), self.drawPlot)
|
||||
self.plotContextDataFetcher = PlotContextDataFetcher()
|
||||
|
||||
plot_view_layout = QtGui.QGridLayout()
|
||||
|
||||
plot_view_layout.addWidget(self.plot, 0, 0, 1, 1)
|
||||
|
||||
self.h_zoom_slider = ZoomSlider()
|
||||
self.connect(self.h_zoom_slider, QtCore.SIGNAL('zoomValueChanged(float, float)'), self.plot.setXZoomFactors)
|
||||
|
||||
self.v_zoom_slider = ZoomSlider(horizontal=False)
|
||||
self.connect(self.v_zoom_slider, QtCore.SIGNAL('zoomValueChanged(float, float)'), self.plot.setYZoomFactors)
|
||||
|
||||
plot_view_layout.addWidget(self.h_zoom_slider, 1, 0, 1, 1)
|
||||
plot_view_layout.addWidget(self.v_zoom_slider, 0, 1, 1, 1)
|
||||
|
||||
plotLayout.addLayout(parameterLayout)
|
||||
plotLayout.addLayout(plot_view_layout)
|
||||
|
||||
self.plotViewSettings = PlotViewSettingsPanel(plotView=self.plot, width=250)
|
||||
self.connect(self.plotViewSettings, QtCore.SIGNAL('comparisonCaseSelected(String)'), self.plotDataFetcher.updateComparisonFS)
|
||||
plotLayout.addWidget(self.plotViewSettings)
|
||||
|
||||
self.setLayout(plotLayout)
|
||||
|
||||
self.connect(self.plot.plot_settings, QtCore.SIGNAL('plotSettingsChanged(PlotSettings)'), self.fetchSettings)
|
||||
|
||||
ContentModel.modelConnect('casesUpdated()', self.updateList)
|
||||
|
||||
def drawPlot(self):
|
||||
self.plot.setData(self.plotDataFetcher.data)
|
||||
|
||||
def fetchSettings(self, plot_settings):
|
||||
if self.plotDataFetcher.data:
|
||||
data = self.plotDataFetcher.data
|
||||
x_min = plot_settings.getMinXLimit(data.x_min, data.getXDataType())
|
||||
x_max = plot_settings.getMaxXLimit(data.x_max, data.getXDataType())
|
||||
y_min = plot_settings.getMinYLimit(data.y_min, data.getYDataType())
|
||||
y_max = plot_settings.getMaxYLimit(data.y_max, data.getYDataType())
|
||||
|
||||
state = self.h_zoom_slider.blockSignals(True)
|
||||
self.h_zoom_slider.setMinValue(plot_settings.getMinXZoom())
|
||||
self.h_zoom_slider.setMaxValue(plot_settings.getMaxXZoom())
|
||||
self.h_zoom_slider.blockSignals(state)
|
||||
|
||||
state = self.v_zoom_slider.blockSignals(True)
|
||||
self.v_zoom_slider.setMinValue(plot_settings.getMinYZoom())
|
||||
self.v_zoom_slider.setMaxValue(plot_settings.getMaxYZoom())
|
||||
self.v_zoom_slider.blockSignals(state)
|
||||
|
||||
if isinstance(x_min, erttypes.time_t):
|
||||
x_min = x_min.value
|
||||
|
||||
if isinstance(x_max, erttypes.time_t):
|
||||
x_max = x_max.value
|
||||
|
||||
#todo: time data on y-axis
|
||||
|
||||
state = plot_settings.blockSignals(True)
|
||||
|
||||
self.plotViewSettings.setDataTypes(data.getXDataType(), data.getYDataType())
|
||||
self.plotViewSettings.setLimits(x_min, x_max, y_min, y_max)
|
||||
self.plotViewSettings.setLimitStates(*plot_settings.getLimitStates())
|
||||
self.plotViewSettings.plotSelectionChanged(plot_settings.getSelectedMembers())
|
||||
|
||||
plot_settings.blockSignals(state)
|
||||
|
||||
self.plot.drawPlot()
|
||||
|
||||
@ert_gui.widgets.util.may_take_a_long_time
|
||||
def select(self, current, previous):
|
||||
if current:
|
||||
self.plotDataFetcher.setParameter(current, self.plotContextDataFetcher.data)
|
||||
cw = self.plotDataFetcher.getConfigurationWidget(self.plotContextDataFetcher.data)
|
||||
self.plotDataPanel.setConfigurationWidget(cw)
|
||||
self.plotDataFetcher.fetchContent()
|
||||
self.drawPlot()
|
||||
|
||||
def updateList(self):
|
||||
self.plotContextDataFetcher.fetchContent()
|
||||
self.plotList.clear()
|
||||
for parameter in self.plotContextDataFetcher.data.parameters:
|
||||
self.plotList.addItem(parameter)
|
||||
|
||||
self.plotList.sortItems()
|
||||
|
||||
self.plot.setPlotPath(self.plotContextDataFetcher.data.plot_path)
|
||||
self.plot.setPlotConfigPath(self.plotContextDataFetcher.data.plot_config_path)
|
||||
|
||||
self.plotViewSettings.setCases(self.plotContextDataFetcher.data.getComparableCases())
|
||||
|
||||
|
||||
class PlotViewSettingsPanel(QtGui.QFrame):
|
||||
|
||||
def __init__(self, parent=None, plotView=None, width=100):
|
||||
QtGui.QFrame.__init__(self, parent)
|
||||
self.setFrameShape(QtGui.QFrame.StyledPanel)
|
||||
self.setFrameShadow(QtGui.QFrame.Plain)
|
||||
self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
|
||||
|
||||
self.setMinimumWidth(width)
|
||||
self.setMaximumWidth(width)
|
||||
|
||||
self.plotView = plotView
|
||||
|
||||
layout = QtGui.QVBoxLayout()
|
||||
|
||||
plot_configs = self.plotView.getPlotConfigList()
|
||||
tabbed_panel = QTabWidget()
|
||||
tabbed_panel.setTabPosition(QTabWidget.West)
|
||||
for plot_config in plot_configs:
|
||||
config_panel = PlotConfigPanel(plot_config)
|
||||
tabbed_panel.addTab(config_panel, plot_config.name)
|
||||
#self.connect(config_panel, SIGNAL('plotConfigChanged()'), self.plotView.drawPlot)
|
||||
|
||||
layout.addWidget(tabbed_panel)
|
||||
|
||||
tabbed_panel = QTabWidget()
|
||||
#tabbed_panel.setTabPosition(QTabWidget.West)
|
||||
|
||||
tabbed_panel.addTab(self.createMemberSelectionPanel(), "Members")
|
||||
tabbed_panel.addTab(self.createPlotRangePanel(), "Plot")
|
||||
tabbed_panel.addTab(self.createButtonLayout(), "Production")
|
||||
tabbed_panel.setMaximumHeight(250)
|
||||
|
||||
layout.addWidget(tabbed_panel)
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
def setDataTypes(self, x_data_type, y_data_type):
|
||||
self.x_min.showDate(x_data_type == "time")
|
||||
self.x_max.showDate(x_data_type == "time")
|
||||
self.y_min.showDate(y_data_type == "time")
|
||||
self.y_max.showDate(y_data_type == "time")
|
||||
|
||||
|
||||
def setLimits(self, x_min, x_max, y_min, y_max):
|
||||
self.x_min.setValue(x_min)
|
||||
self.x_max.setValue(x_max)
|
||||
self.y_min.setValue(y_min)
|
||||
self.y_max.setValue(y_max)
|
||||
|
||||
def setLimitStates(self, x_min_state, x_max_state, y_min_state, y_max_state):
|
||||
self.x_min.setChecked(x_min_state)
|
||||
self.x_max.setChecked(x_max_state)
|
||||
self.y_min.setChecked(y_min_state)
|
||||
self.y_max.setChecked(y_max_state)
|
||||
|
||||
def createPlotRangePanel(self):
|
||||
frame = QFrame()
|
||||
#frame.setMaximumHeight(150)
|
||||
#frame.setFrameShape(QFrame.StyledPanel)
|
||||
#frame.setFrameShadow(QFrame.Plain)
|
||||
|
||||
layout = QFormLayout()
|
||||
|
||||
self.x_min = DisableableSpinner(self.plotView.setMinXLimit)
|
||||
self.x_max = DisableableSpinner(self.plotView.setMaxXLimit)
|
||||
|
||||
layout.addRow("X min:", self.x_min)
|
||||
layout.addRow("X max:", self.x_max)
|
||||
|
||||
self.y_min = DisableableSpinner(self.plotView.setMinYLimit)
|
||||
self.y_max = DisableableSpinner(self.plotView.setMaxYLimit)
|
||||
|
||||
layout.addRow("Y min:", self.y_min)
|
||||
layout.addRow("Y max:", self.y_max)
|
||||
|
||||
|
||||
layout.addWidget(ert_gui.widgets.util.createSeparator())
|
||||
|
||||
self.plot_compare_to_case = QtGui.QComboBox()
|
||||
self.plot_compare_to_case.setToolTip("Select case to compare members against.")
|
||||
|
||||
|
||||
self.connect(self.plot_compare_to_case, SIGNAL("currentIndexChanged(QString)"), self.select_case)
|
||||
layout.addRow("Case:", self.plot_compare_to_case)
|
||||
|
||||
frame.setLayout(layout)
|
||||
return frame
|
||||
|
||||
def select_case(self, case):
|
||||
self.emit(SIGNAL('comparisonCaseSelected(String)'), str(case))
|
||||
|
||||
def createButtonLayout(self):
|
||||
frame = QFrame()
|
||||
#frame.setMaximumHeight(150)
|
||||
#frame.setFrameShape(QFrame.StyledPanel)
|
||||
#frame.setFrameShadow(QFrame.Plain)
|
||||
|
||||
button_layout = QHBoxLayout()
|
||||
|
||||
self.import_button = QtGui.QPushButton()
|
||||
self.import_button.setIcon(ert_gui.widgets.util.resourceIcon("plugin"))
|
||||
self.import_button.setIconSize(QtCore.QSize(16, 16))
|
||||
self.import_button.setToolTip("Copy settings from another plot.")
|
||||
|
||||
self.save_button = QtGui.QPushButton()
|
||||
self.save_button.setIcon(ert_gui.widgets.util.resourceIcon("disk"))
|
||||
self.save_button.setIconSize(QtCore.QSize(16, 16))
|
||||
self.save_button.setToolTip("Save a plot.")
|
||||
|
||||
self.save_many_button = QtGui.QPushButton()
|
||||
self.save_many_button.setIcon(ert_gui.widgets.util.resourceIcon("save_plots"))
|
||||
self.save_many_button.setIconSize(QtCore.QSize(16, 16))
|
||||
self.save_many_button.setToolTip("Save all configured plots.")
|
||||
|
||||
button_layout.addWidget(self.import_button)
|
||||
button_layout.addWidget(self.save_button)
|
||||
button_layout.addWidget(self.save_many_button)
|
||||
|
||||
self.connect(self.save_button, QtCore.SIGNAL('clicked()'), self.plotView.save)
|
||||
self.connect(self.save_many_button, QtCore.SIGNAL('clicked()'), self.plotView.saveAll)
|
||||
self.connect(self.import_button, QtCore.SIGNAL('clicked()'), self.plotView.copyPlotSettings)
|
||||
|
||||
vertical_layout = QVBoxLayout()
|
||||
vertical_layout.addLayout(button_layout)
|
||||
vertical_layout.addStretch(1)
|
||||
frame.setLayout(vertical_layout)
|
||||
|
||||
return frame
|
||||
|
||||
def createMemberSelectionPanel(self):
|
||||
frame = QFrame()
|
||||
#frame.setMinimumHeight(100)
|
||||
#frame.setMaximumHeight(100)
|
||||
#frame.setFrameShape(QFrame.StyledPanel)
|
||||
#frame.setFrameShadow(QFrame.Plain)
|
||||
|
||||
layout = QVBoxLayout()
|
||||
|
||||
self.selected_member_label = QtGui.QLabel()
|
||||
self.selected_member_label.setWordWrap(True)
|
||||
|
||||
layout.addWidget(QtGui.QLabel("Selected members:"))
|
||||
layout.addWidget(self.selected_member_label)
|
||||
|
||||
layout.addStretch(1)
|
||||
|
||||
self.clear_button = QtGui.QPushButton()
|
||||
self.clear_button.setText("Clear selection")
|
||||
layout.addWidget(self.clear_button)
|
||||
self.connect(self.clear_button, QtCore.SIGNAL('clicked()'), self.plotView.clearSelection)
|
||||
|
||||
layout.addStretch(1)
|
||||
frame.setLayout(layout)
|
||||
|
||||
return frame
|
||||
|
||||
def plotSelectionChanged(self, selected_members):
|
||||
if isinstance(selected_members, plotsettings.PlotSettings):
|
||||
selected_members = selected_members.getSelectedMembers()
|
||||
text = ""
|
||||
for member in selected_members:
|
||||
text = text + " " + str(member)
|
||||
self.selected_member_label.setText(text)
|
||||
|
||||
def setCases(self, cases):
|
||||
state = self.plot_compare_to_case.blockSignals(True)
|
||||
self.plot_compare_to_case.clear()
|
||||
self.plot_compare_to_case.addItems(cases)
|
||||
self.plot_compare_to_case.blockSignals(state)
|
||||
self.select_case("None")
|
||||
|
||||
class DisableableSpinner(QFrame):
|
||||
|
||||
def __init__(self, func):
|
||||
QFrame.__init__(self)
|
||||
self.func = func
|
||||
|
||||
layout = QHBoxLayout()
|
||||
layout.setMargin(0)
|
||||
|
||||
self.check = QCheckBox()
|
||||
|
||||
self.spinner = QtGui.QDoubleSpinBox()
|
||||
self.spinner.setSingleStep(1)
|
||||
self.spinner.setDisabled(True)
|
||||
self.spinner.setMinimum(-10000000000)
|
||||
self.spinner.setMaximum(10000000000)
|
||||
self.spinner.setMaximumWidth(100)
|
||||
self.connect(self.spinner, QtCore.SIGNAL('valueChanged(double)'), self.update)
|
||||
|
||||
self.date_spinner = QtGui.QDateEdit()
|
||||
self.date_spinner.setDisabled(True)
|
||||
self.date_spinner.setDisplayFormat("dd/MM-yyyy")
|
||||
self.date_spinner.setMaximumWidth(100)
|
||||
self.date_spinner.setCalendarPopup(True)
|
||||
self.connect(self.date_spinner, QtCore.SIGNAL('dateChanged(QDate)'), self.update)
|
||||
|
||||
self.connect(self.check, SIGNAL('stateChanged(int)'), self.disabler)
|
||||
|
||||
layout.addWidget(self.check)
|
||||
layout.addWidget(self.spinner)
|
||||
layout.addWidget(self.date_spinner)
|
||||
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
self.showDate(False)
|
||||
|
||||
def update(self, value):
|
||||
if self.show_date:
|
||||
seconds = self.qDateToSeconds(value)
|
||||
self.func(seconds)
|
||||
else:
|
||||
self.func(value)
|
||||
|
||||
def disabler(self, state):
|
||||
disabled = not state == 2
|
||||
self.spinner.setDisabled(disabled)
|
||||
self.date_spinner.setDisabled(disabled)
|
||||
|
||||
if not disabled:
|
||||
if self.show_date:
|
||||
seconds = self.qDateToSeconds(self.date_spinner.date())
|
||||
self.func(seconds)
|
||||
else:
|
||||
self.func(self.spinner.value())
|
||||
else:
|
||||
self.func(None)
|
||||
|
||||
def setChecked(self, state):
|
||||
self.check.setChecked(state)
|
||||
|
||||
def setValue(self, value):
|
||||
if not value is None:
|
||||
if self.show_date:
|
||||
state = self.date_spinner.blockSignals(True)
|
||||
self.date_spinner.setDate(self.qDateFromSeconds(value))
|
||||
self.date_spinner.blockSignals(state)
|
||||
else:
|
||||
state = self.spinner.blockSignals(True)
|
||||
self.spinner.setValue(value)
|
||||
self.spinner.blockSignals(state)
|
||||
|
||||
def showDate(self, bool):
|
||||
self.show_date = bool
|
||||
self.spinner.setHidden(bool)
|
||||
self.date_spinner.setHidden(not bool)
|
||||
|
||||
def qDateFromSeconds(self, seconds):
|
||||
t = time.localtime(seconds)
|
||||
return QDate(*t[0:3])
|
||||
|
||||
def qDateToSeconds(self, qdate):
|
||||
date = qdate.toPyDate()
|
||||
seconds = int(time.mktime(date.timetuple()))
|
||||
return seconds
|
||||
|
||||
|
||||
class PlotParameterConfigurationPanel(QtGui.QFrame):
|
||||
def __init__(self, parent=None, width=100):
|
||||
QtGui.QFrame.__init__(self, parent)
|
||||
self.setFrameShape(QtGui.QFrame.StyledPanel)
|
||||
self.setFrameShadow(QtGui.QFrame.Plain)
|
||||
self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
|
||||
|
||||
self.setMinimumWidth(width)
|
||||
self.setMaximumWidth(width)
|
||||
self.setMaximumHeight(200)
|
||||
|
||||
self.layout = QtGui.QStackedLayout()
|
||||
self.setLayout(self.layout)
|
||||
|
||||
def setConfigurationWidget(self, widget):
|
||||
if self.layout.indexOf(widget) == -1:
|
||||
self.layout.addWidget(widget)
|
||||
self.layout.setCurrentWidget(widget)
|
||||
|
||||
|
||||
|
||||
@@ -1,233 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'plotrenderer.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from matplotlib.dates import AutoDateLocator, datetime, matplotlib
|
||||
import ert.ert.erttypes as erttypes
|
||||
|
||||
class PlotRenderer:
|
||||
"""An abstract plotter that plots data"""
|
||||
|
||||
def drawPlot(self, axes, data, plot_settings):
|
||||
"""
|
||||
Override this method in a subclass to create your own plot renderer.
|
||||
Call PlotRenderer.drawPlot(...) as your last function call.
|
||||
"""
|
||||
self._updateLimitsAndZoom(axes, plot_settings, data)
|
||||
|
||||
def _updateLimitsAndZoom(self, axes, plot_settings, data):
|
||||
"""
|
||||
Sets the figure so that it shows the correct limits.
|
||||
This is dependent on limits AND zoom factor.
|
||||
"""
|
||||
self._setXViewFactors(axes, plot_settings, data)
|
||||
self._setYViewFactors(axes, plot_settings, data)
|
||||
|
||||
def __convertDate(self, ert_time):
|
||||
"""Convert normal dates to matplotlib dates."""
|
||||
if ert_time is None:
|
||||
ert_time = erttypes.time_t(0)
|
||||
|
||||
if isinstance(ert_time, datetime.date):
|
||||
return matplotlib.dates.date2num(ert_time)
|
||||
else:
|
||||
return matplotlib.dates.date2num(ert_time.datetime())
|
||||
|
||||
def _setXViewFactors(self, axes, plot_settings, data):
|
||||
xminf = plot_settings.getMinXZoom()
|
||||
xmaxf = plot_settings.getMaxXZoom()
|
||||
|
||||
x_min = plot_settings.getMinXLimit(data.x_min, data.getXDataType())
|
||||
x_max = plot_settings.getMaxXLimit(data.x_max, data.getXDataType())
|
||||
|
||||
if data.getXDataType() == "time":
|
||||
x_min = self.__convertDate(x_min)
|
||||
x_max = self.__convertDate(x_max)
|
||||
|
||||
if not x_min is None and not x_max is None:
|
||||
range = x_max - x_min
|
||||
axes.set_xlim(x_min + xminf * range - range*0.0, x_min + xmaxf * range + range*0.0)
|
||||
|
||||
def _setYViewFactors(self, axes, plot_settings, data):
|
||||
yminf = plot_settings.getMinYZoom()
|
||||
ymaxf = plot_settings.getMaxYZoom()
|
||||
|
||||
y_min = plot_settings.getMinYLimit(data.y_min, data.getYDataType())
|
||||
y_max = plot_settings.getMaxYLimit(data.y_max, data.getYDataType())
|
||||
|
||||
|
||||
if not y_min is None and not y_max is None:
|
||||
range = y_max - y_min
|
||||
axes.set_ylim(y_min + yminf * range - range*0.0, y_min + ymaxf * range + range*0.0)
|
||||
|
||||
def plot(self, axes, plot_config, x, y):
|
||||
"""Plots a line where x and y are numbers."""
|
||||
line = axes.plot(x,
|
||||
y,
|
||||
plot_config.style,
|
||||
color=plot_config.color,
|
||||
alpha=plot_config.alpha,
|
||||
zorder=plot_config.z_order,
|
||||
picker = plot_config.picker,
|
||||
visible = plot_config.is_visible and plot_config.hasStyle())
|
||||
|
||||
return line[0]
|
||||
|
||||
def plot_date(self, axes, plot_config, x, y):
|
||||
"""Plots a line where x are dates and y are numbers."""
|
||||
line = axes.plot_date(x,
|
||||
y,
|
||||
plot_config.style,
|
||||
color=plot_config.color,
|
||||
alpha=plot_config.alpha,
|
||||
zorder=plot_config.z_order,
|
||||
picker = plot_config.picker,
|
||||
visible = plot_config.is_visible and plot_config.hasStyle())
|
||||
|
||||
return line[0]
|
||||
|
||||
def plot_errorbar(self, axes, plot_config, x, y, std_x, std_y):
|
||||
"""Plots errorbars."""
|
||||
axes.errorbar(x,
|
||||
y,
|
||||
yerr = std_y,
|
||||
xerr = std_x,
|
||||
fmt=None,
|
||||
ecolor=plot_config.color,
|
||||
alpha=plot_config.alpha,
|
||||
zorder=plot_config.z_order,
|
||||
visible = plot_config.is_visible)
|
||||
|
||||
|
||||
class DefaultPlotRenderer(PlotRenderer):
|
||||
def drawPlot(self, axes, data, plot_settings):
|
||||
axes.set_title(data.getTitle())
|
||||
|
||||
if data.hasInvertedYAxis() and not axes.yaxis_inverted():
|
||||
axes.invert_yaxis()
|
||||
elif not data.hasInvertedYAxis() and axes.yaxis_inverted():
|
||||
axes.invert_yaxis()
|
||||
|
||||
|
||||
annotations = plot_settings.getAnnotations()
|
||||
for annotation in annotations:
|
||||
coord = (annotation.x, annotation.y)
|
||||
xytext = None
|
||||
if not annotation.xt is None and not annotation.yt is None:
|
||||
xytext = (annotation.xt, annotation.yt)
|
||||
arrow = dict(arrowstyle="->")
|
||||
label = str(annotation.label)
|
||||
annotation_artist = axes.annotate(label, coord, xytext=xytext, xycoords='data', textcoords='data', arrowprops=arrow, picker=1)
|
||||
annotation.setUserData(annotation_artist)
|
||||
|
||||
self._plotMembers(axes, data, plot_settings)
|
||||
self._plotComparisonData(axes, data, plot_settings)
|
||||
|
||||
if not data.obs_x is None and not data.obs_y is None:
|
||||
self._plotObservations(axes, data, plot_settings)
|
||||
|
||||
if not data.obs_std_x is None or not data.obs_std_y is None:
|
||||
self._plotError(axes, data, plot_settings)
|
||||
|
||||
if not data.refcase_x is None and not data.refcase_y is None and plot_settings.refcase_plot_config.is_visible:
|
||||
self._plotRefCase(axes, data, plot_settings)
|
||||
|
||||
if data.getXDataType() == "time":
|
||||
yearsFmt = matplotlib.dates.DateFormatter('%b \'%Y')
|
||||
axes.xaxis.set_major_formatter(yearsFmt)
|
||||
# labels = axes.get_xticklabels()
|
||||
# for label in labels:
|
||||
# label.set_rotation(30)
|
||||
|
||||
|
||||
number_formatter = matplotlib.ticker.ScalarFormatter(useOffset=False)
|
||||
number_formatter.set_scientific(True)
|
||||
axes.yaxis.set_major_formatter(number_formatter)
|
||||
|
||||
PlotRenderer.drawPlot(self, axes, data, plot_settings)
|
||||
|
||||
|
||||
|
||||
def _plotMembers(self, axes, data, plot_settings):
|
||||
selected_members = plot_settings.getSelectedMembers()
|
||||
for member in data.x_data.keys():
|
||||
x = data.x_data[member]
|
||||
y = data.y_data[member]
|
||||
if member in selected_members:
|
||||
plot_config = plot_settings.selected_plot_config
|
||||
else:
|
||||
plot_config = plot_settings.plot_config
|
||||
if data.getXDataType() == "time":
|
||||
line = self.plot_date(axes, plot_config, x, y)
|
||||
else:
|
||||
line = self.plot(axes, plot_config, x, y)
|
||||
line.set_gid(member) # to more easily identify the line later (i.e.: picking)
|
||||
|
||||
def _plotComparisonData(self, axes, data, plot_settings):
|
||||
#selected_members = plot_settings.getSelectedMembers()
|
||||
for member in data.x_comp_data.keys():
|
||||
x = data.x_comp_data[member]
|
||||
y = data.y_comp_data[member]
|
||||
#if member in selected_members:
|
||||
# plot_config = plot_settings.selected_plot_config
|
||||
#else:
|
||||
plot_config = plot_settings.comparison_plot_config
|
||||
if data.getXDataType() == "time":
|
||||
line = self.plot_date(axes, plot_config, x, y)
|
||||
else:
|
||||
line = self.plot(axes, plot_config, x, y)
|
||||
line.set_gid(member + 10000) # to more easily identify the line later (i.e.: picking)
|
||||
|
||||
|
||||
def _plotError(self, axes, data, plot_settings):
|
||||
x = data.obs_x
|
||||
y = data.obs_y
|
||||
x_std = data.obs_std_x
|
||||
y_std = data.obs_std_y
|
||||
|
||||
if plot_settings.std_plot_config.is_visible:
|
||||
if data.getXDataType() == "time":
|
||||
if not y_std is None:
|
||||
self.plot_date(axes, plot_settings.std_plot_config, x, y - y_std)
|
||||
self.plot_date(axes, plot_settings.std_plot_config, x, y + y_std)
|
||||
elif not x_std is None:
|
||||
self.plot_date(axes, plot_settings.std_plot_config, x - x_std, y)
|
||||
self.plot_date(axes, plot_settings.std_plot_config, x + x_std, y)
|
||||
else:
|
||||
if not y_std is None:
|
||||
self.plot(axes, plot_settings.std_plot_config, x, y - y_std)
|
||||
self.plot(axes, plot_settings.std_plot_config, x, y + y_std)
|
||||
elif not x_std is None:
|
||||
self.plot(axes, plot_settings.std_plot_config, x - x_std, y)
|
||||
self.plot(axes, plot_settings.std_plot_config, x + x_std, y)
|
||||
|
||||
if plot_settings.errorbar_plot_config.is_visible:
|
||||
self.plot_errorbar(axes, plot_settings.errorbar_plot_config, x, y, x_std, y_std)
|
||||
|
||||
def _plotObservations(self, axes, data, plot_settings):
|
||||
x = data.obs_x
|
||||
y = data.obs_y
|
||||
|
||||
if data.getXDataType() == "time":
|
||||
self.plot_date(axes, plot_settings.observation_plot_config, x, y)
|
||||
else:
|
||||
self.plot(axes, plot_settings.observation_plot_config, x, y)
|
||||
|
||||
def _plotRefCase(self, axes, data, plot_settings):
|
||||
x = data.refcase_x
|
||||
y = data.refcase_y
|
||||
if data.getXDataType() == "time":
|
||||
self.plot_date(axes, plot_settings.refcase_plot_config, x, y)
|
||||
@@ -1,306 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'plotsettings.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from plotconfig import PlotConfig
|
||||
import matplotlib
|
||||
from ert.ert.erttypes import time_t
|
||||
import datetime
|
||||
from PyQt4.QtCore import QObject, SIGNAL
|
||||
|
||||
class PlotSettings(QObject):
|
||||
"""
|
||||
PlotSettings are the settings used for plotting.
|
||||
Such as color, transparency, x and y limits, annotations.
|
||||
"""
|
||||
|
||||
plot_color = (55/255.0, 126/255.0, 200/255.0) # bluish
|
||||
selected_color = (152/255.0, 78/255.0, 163/255.0) # purple
|
||||
history_color = (255/255.0, 0/255.0, 0/255.0) # red
|
||||
refcase_color = (0/255.0, 200/255.0, 0/255.0) # green
|
||||
comparison_color = (199/255.0, 63/255.0, 0/255.0) # orange
|
||||
|
||||
def __init__(self):
|
||||
QObject.__init__(self)
|
||||
|
||||
self._xminf = 0.0
|
||||
self._xmaxf = 1.0
|
||||
self._x_limits = (None, None)
|
||||
|
||||
self._yminf = 0.0
|
||||
self._ymaxf = 1.0
|
||||
self._y_limits = (None, None)
|
||||
|
||||
self._plot_path = "."
|
||||
self._plot_config_path = "."
|
||||
|
||||
self.observation_plot_config = PlotConfig("Observation", color = self.history_color, zorder=10)
|
||||
self.refcase_plot_config = PlotConfig("Refcase", visible=False, color = self.refcase_color, zorder=10)
|
||||
self.std_plot_config = PlotConfig("Error", linestyle=":", visible=False, color = self.history_color, zorder=10)
|
||||
self.plot_config = PlotConfig("Members", color = self.plot_color, alpha=0.125, zorder=2, picker=2)
|
||||
self.selected_plot_config = PlotConfig("Selected members", color = self.selected_color, alpha=0.5, zorder=8,
|
||||
picker=2)
|
||||
self.errorbar_plot_config = PlotConfig("Errorbars", visible=False, color = self.history_color, alpha=0.5,
|
||||
zorder=10)
|
||||
self.comparison_plot_config = PlotConfig("Comparison", color = self.comparison_color, alpha=0.125, zorder=1, visible=True, linestyle="-")
|
||||
|
||||
self._plot_configs = [self.plot_config,
|
||||
self.selected_plot_config,
|
||||
self.refcase_plot_config,
|
||||
self.observation_plot_config,
|
||||
self.std_plot_config,
|
||||
self.errorbar_plot_config,
|
||||
self.comparison_plot_config]
|
||||
|
||||
for pc in self._plot_configs:
|
||||
self.connect(pc.signal_handler, SIGNAL('plotConfigChanged(PlotConfig)'), self.notify)
|
||||
|
||||
self._plot_config_dict = {}
|
||||
for pc in self._plot_configs:
|
||||
self._plot_config_dict[pc.name] = pc
|
||||
|
||||
self._selected_members = []
|
||||
|
||||
self._annotations = []
|
||||
|
||||
def notify(self, *args):
|
||||
"""Tell listeners that the settings has changed. Automatically called by all setters."""
|
||||
self.emit(SIGNAL('plotSettingsChanged(PlotSettings)'), self)
|
||||
|
||||
def getPlotConfigList(self):
|
||||
"""Get a list of PlotConfig instances."""
|
||||
return self._plot_configs
|
||||
|
||||
def getPlotConfigDict(self):
|
||||
"""Get a dictionary of PlotConfig instances."""
|
||||
return self._plot_config_dict
|
||||
|
||||
def getLimitsTuple(self):
|
||||
"""Get the limits as a tuple: (x_min, x_max, y_min, y_max)"""
|
||||
return (self._x_limits[0], self._x_limits[1], self._y_limits[0], self._y_limits[1])
|
||||
|
||||
def getZoomTuple(self):
|
||||
"""Get the zoom factors as a tuple: (x_min, x_max, y_min, y_max)"""
|
||||
return (self._xminf, self._xmaxf, self._yminf, self._ymaxf)
|
||||
|
||||
def selectMember(self, member):
|
||||
"""Set a member as selected."""
|
||||
if not member in self._selected_members:
|
||||
self._selected_members.append(int(member))
|
||||
self.notify()
|
||||
|
||||
def unselectMember(self, member):
|
||||
"""Set a member as unselected."""
|
||||
member = int(member)
|
||||
if member in self._selected_members:
|
||||
self._selected_members.remove(member)
|
||||
self.notify()
|
||||
|
||||
def clearMemberSelection(self):
|
||||
"""Clear the list of selected members."""
|
||||
self._selected_members = []
|
||||
self.notify()
|
||||
|
||||
def getSelectedMembers(self):
|
||||
"""Returns the list of selected members."""
|
||||
return self._selected_members
|
||||
|
||||
def setMinYLimit(self, value):
|
||||
"""Set the lower limit of the Y axis. Can be set to None."""
|
||||
if not value == self._y_limits[0]:
|
||||
self._y_limits = (value, self._y_limits[1])
|
||||
self.notify()
|
||||
|
||||
def getMinYLimit(self, y_min, data_type=""):
|
||||
"""Return the lower limit of the Y Axis. Returns y_min if the internal value is None."""
|
||||
if self._y_limits[0] is None:
|
||||
return y_min
|
||||
else:
|
||||
return self._y_limits[0]
|
||||
|
||||
def setMaxYLimit(self, value):
|
||||
"""Set the upper limit of the Y axis. Can be set to None."""
|
||||
if not value == self._y_limits[1]:
|
||||
self._y_limits = (self._y_limits[0], value)
|
||||
self.notify()
|
||||
|
||||
def getMaxYLimit(self, y_max, data_type=""):
|
||||
"""Return the upper limit of the Y Axis. Returns y_max if the internal value is None."""
|
||||
if self._y_limits[1] is None:
|
||||
return y_max
|
||||
else:
|
||||
return self._y_limits[1]
|
||||
|
||||
def setMinXLimit(self, value):
|
||||
"""Set the lower limit of the X axis. Can be set to None."""
|
||||
if not value == self._x_limits[0]:
|
||||
self._x_limits = (value, self._x_limits[1])
|
||||
self.notify()
|
||||
|
||||
def getMinXLimit(self, x_min, data_type):
|
||||
"""Returns the provided x_min value if the internal x_min value is None. Converts dates to numbers"""
|
||||
if self._x_limits[0] is None:
|
||||
x_limit = x_min
|
||||
else:
|
||||
x_limit = self._x_limits[0]
|
||||
|
||||
if not x_limit is None and data_type == "time" and not isinstance(x_limit, time_t):
|
||||
x_limit = time_t(long(round(x_limit)))
|
||||
|
||||
return x_limit
|
||||
|
||||
def setMaxXLimit(self, value):
|
||||
"""Set the upper limit of the X axis. Can be set to None."""
|
||||
if not value == self._x_limits[1]:
|
||||
self._x_limits = (self._x_limits[0], value)
|
||||
self.notify()
|
||||
|
||||
def getMaxXLimit(self, x_max, data_type):
|
||||
"""Returns the provided x_max value if the internal x_max value is None. Converts dates to numbers"""
|
||||
if self._x_limits[1] is None:
|
||||
x_limit = x_max
|
||||
else:
|
||||
x_limit = self._x_limits[1]
|
||||
|
||||
if not x_limit is None and data_type == "time" and not isinstance(x_limit, time_t):
|
||||
x_limit = time_t(long(round(x_limit)))
|
||||
|
||||
return x_limit
|
||||
|
||||
def getLimitStates(self):
|
||||
"""
|
||||
Returns a tuple of True/False values.
|
||||
(not x_min is None, not x_max is None, not y_min is None, not y_max is None)
|
||||
"""
|
||||
x_min_state = not self._x_limits[0] is None
|
||||
x_max_state = not self._x_limits[1] is None
|
||||
y_min_state = not self._y_limits[0] is None
|
||||
y_max_state = not self._y_limits[1] is None
|
||||
return (x_min_state, x_max_state, y_min_state, y_max_state)
|
||||
|
||||
def setPlotPath(self, plot_path):
|
||||
"""Set the path to store plot images in."""
|
||||
if not plot_path == self._plot_path:
|
||||
self._plot_path = plot_path
|
||||
self.notify()
|
||||
|
||||
def setPlotConfigPath(self, plot_config_path):
|
||||
"""Set the path to store plot settings files in."""
|
||||
if not plot_config_path == self._plot_config_path:
|
||||
self._plot_config_path = plot_config_path
|
||||
self.notify()
|
||||
|
||||
def getPlotPath(self):
|
||||
"""The path to store plot images in."""
|
||||
return self._plot_path
|
||||
|
||||
def getPlotConfigPath(self):
|
||||
"""The path to store plot settings in."""
|
||||
return self._plot_config_path
|
||||
|
||||
def setMinXZoom(self, value):
|
||||
"""Set the x_min zoom factor. [0,1]"""
|
||||
if not self._xminf == value:
|
||||
self._xminf = value
|
||||
self.notify()
|
||||
|
||||
def setMaxXZoom(self, value):
|
||||
"""Set the x_max zoom factor. [0,1]"""
|
||||
if not self._xmaxf == value:
|
||||
self._xmaxf = value
|
||||
self.notify()
|
||||
|
||||
def setMinYZoom(self, value):
|
||||
"""Set the y_min zoom factor. [0,1]"""
|
||||
if not self._yminf == value:
|
||||
self._yminf = value
|
||||
self.notify()
|
||||
|
||||
def setMaxYZoom(self, value):
|
||||
"""Set the y_max zoom factor. [0,1]"""
|
||||
if not self._ymaxf == value:
|
||||
self._ymaxf = value
|
||||
self.notify()
|
||||
|
||||
def getMinXZoom(self):
|
||||
"""Returns the x_min zoom factor."""
|
||||
return self._xminf
|
||||
|
||||
def getMaxXZoom(self):
|
||||
"""Returns the x_max zoom factor."""
|
||||
return self._xmaxf
|
||||
|
||||
def getMinYZoom(self):
|
||||
"""Returns the y_min zoom factor."""
|
||||
return self._yminf
|
||||
|
||||
def getMaxYZoom(self):
|
||||
"""Returns the y_max zoom factor."""
|
||||
return self._ymaxf
|
||||
|
||||
def getAnnotations(self):
|
||||
"""Return a list of annotations."""
|
||||
return self._annotations
|
||||
|
||||
def clearAnnotations(self):
|
||||
"""Remove all annotations."""
|
||||
if len(self._annotations) > 0:
|
||||
self._annotations = []
|
||||
self.notify()
|
||||
|
||||
def addAnnotation(self, label, x, y, xt, yt):
|
||||
"""
|
||||
Add an annotation. x, y, xt, yt are in data coordinates.
|
||||
If any axis represents time. Use matplotlib time values.
|
||||
(Float days since 2000.01.01, starting from 1)
|
||||
Returns the annotation as a PlotAnnotation object.
|
||||
"""
|
||||
annotation = PlotAnnotation(label, x, y, xt, yt)
|
||||
self._annotations.append(annotation)
|
||||
self.notify()
|
||||
return annotation
|
||||
|
||||
def removeAnnotation(self, annotation):
|
||||
"""Remove an annotation. Expects PlotAnnotation instance."""
|
||||
if annotation in self._annotations:
|
||||
self._annotations.remove(annotation)
|
||||
self.notify()
|
||||
|
||||
|
||||
class PlotAnnotation:
|
||||
"""An annotation representation."""
|
||||
def __init__(self, label, x, y, xt, yt):
|
||||
self.label = label
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.xt = xt
|
||||
self.yt = yt
|
||||
|
||||
def setUserData(self, user_data):
|
||||
"""Usually used to store the matplotlib artist corresponding to this annotation."""
|
||||
self._user_data = user_data
|
||||
|
||||
def getUserData(self):
|
||||
"""Usually the matplotlib artist corresponding to this annotation."""
|
||||
return self._user_data
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,389 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'plotsettingsxml.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
import xml.dom.minidom
|
||||
import os
|
||||
|
||||
class PlotSettingsSaver:
|
||||
"""Save a PlotSettings instance to a xml-file."""
|
||||
def save(self, name, plot_settings):
|
||||
"""Save plot configuration to a file with the specified name as filename."""
|
||||
self.doc = xml.dom.minidom.Document()
|
||||
|
||||
self.root_element = self.doc.createElement("plot_configuration")
|
||||
self.root_element.setAttribute("name", name)
|
||||
self.doc.appendChild(self.root_element)
|
||||
|
||||
plot_configs = plot_settings.getPlotConfigList()
|
||||
|
||||
for plot_config in plot_configs:
|
||||
self.__addPlotConfig(plot_config)
|
||||
|
||||
self.__addLimits(plot_settings.getLimitsTuple(), plot_settings.getZoomTuple())
|
||||
self.__addSelectedMembers(plot_settings.getSelectedMembers())
|
||||
|
||||
self.__addAnnotations(plot_settings.getAnnotations())
|
||||
|
||||
path = "%s/config" % plot_settings.getPlotConfigPath()
|
||||
if not os.path.exists( path ):
|
||||
os.mkdir( path )
|
||||
|
||||
file_object = open("%s/%s.xml" % (path, name), "w")
|
||||
file_object.write(self.doc.toprettyxml())
|
||||
file_object.close()
|
||||
|
||||
def __addPlotConfig(self, plot_config):
|
||||
"""Add a plot config to the xml"""
|
||||
pc_element = self.doc.createElement("plot_config")
|
||||
self.root_element.appendChild(pc_element)
|
||||
pc_element.setAttribute("name", str(plot_config.name))
|
||||
pc_element.setAttribute("visible", str(plot_config.is_visible))
|
||||
pc_element.setAttribute("z_order", str(plot_config.z_order))
|
||||
pc_element.setAttribute("picker", str(plot_config.picker))
|
||||
|
||||
color = plot_config.color
|
||||
alpha = plot_config.alpha
|
||||
|
||||
color_element = self.doc.createElement("color")
|
||||
pc_element.appendChild(color_element)
|
||||
|
||||
color_element.setAttribute("alpha", str(alpha))
|
||||
color_element.setAttribute("red", str(color[0]))
|
||||
color_element.setAttribute("green", str(color[1]))
|
||||
color_element.setAttribute("blue", str(color[2]))
|
||||
|
||||
style_element = self.doc.createElement("style")
|
||||
pc_element.appendChild(style_element)
|
||||
|
||||
style_element.setAttribute("line", str(plot_config.linestyle))
|
||||
style_element.setAttribute("marker", str(plot_config.marker))
|
||||
|
||||
|
||||
def __addComment(self, element, comment):
|
||||
comment_element = self.doc.createComment(comment)
|
||||
element.appendChild(comment_element)
|
||||
|
||||
def __addComments(self, limits_element):
|
||||
comment1 = "When limit values represent a date, the date is stored "\
|
||||
"as the number of seconds since 1/1-1970."
|
||||
self.__addComment(limits_element, comment1)
|
||||
|
||||
|
||||
comment2 = "Setting a limit value to None means that the program should "\
|
||||
"use the corresponding value from the dataset as limits."
|
||||
self.__addComment(limits_element, comment2)
|
||||
|
||||
def __addLimits(self, limits, zoom):
|
||||
"""Add limits and zoom to the xml"""
|
||||
element = self.doc.createElement("limits_and_zoom")
|
||||
self.root_element.appendChild(element)
|
||||
|
||||
limits_element = self.doc.createElement("limits")
|
||||
|
||||
self.__addComments(limits_element)
|
||||
|
||||
element.appendChild(limits_element)
|
||||
limits_element.setAttribute("x_min", str(limits[0]))
|
||||
limits_element.setAttribute("x_max", str(limits[1]))
|
||||
limits_element.setAttribute("y_min", str(limits[2]))
|
||||
limits_element.setAttribute("y_max", str(limits[3]))
|
||||
|
||||
zoom_element = self.doc.createElement("zoom")
|
||||
element.appendChild(zoom_element)
|
||||
zoom_element.setAttribute("x_min", str(zoom[0]))
|
||||
zoom_element.setAttribute("x_max", str(zoom[1]))
|
||||
zoom_element.setAttribute("y_min", str(zoom[2]))
|
||||
zoom_element.setAttribute("y_max", str(zoom[3]))
|
||||
|
||||
def __addSelectedMembers(self, selected_members):
|
||||
"""Add list of selected members to the xml"""
|
||||
element = self.doc.createElement("selected_members")
|
||||
self.root_element.appendChild(element)
|
||||
|
||||
for selected_member in selected_members:
|
||||
member = self.doc.createElement("member")
|
||||
element.appendChild(member)
|
||||
member.setAttribute("id", str(selected_member))
|
||||
|
||||
def __addAnnotations(self, annotations):
|
||||
"""Add list of annotations to the xml"""
|
||||
element = self.doc.createElement("annotations")
|
||||
self.root_element.appendChild(element)
|
||||
|
||||
comment = "If any of the axis represents time the format is matplotlib specific: "\
|
||||
"A date is a floating point number which represent time in days since 0001-01-01 UTC, plus 1. "\
|
||||
"For example, 0001-01-01, 06:00 is 1.25, not 0.25"
|
||||
self.__addComment(element, comment)
|
||||
|
||||
for annotation in annotations:
|
||||
annotation_element = self.doc.createElement("annotation")
|
||||
element.appendChild(annotation_element)
|
||||
annotation_element.setAttribute("label", str(annotation.label))
|
||||
annotation_element.setAttribute("x", str(annotation.x))
|
||||
annotation_element.setAttribute("y", str(annotation.y))
|
||||
annotation_element.setAttribute("xt", str(annotation.xt))
|
||||
annotation_element.setAttribute("yt", str(annotation.yt))
|
||||
|
||||
|
||||
class PlotSettingsLoader:
|
||||
"""Load or copy data from a PlotSettings xml-file."""
|
||||
def __init__(self):
|
||||
self.skip_plot_settings = False
|
||||
self.skip_limits_and_zoom = False
|
||||
self.skip_selected_members = False
|
||||
self.skip_annotations = False
|
||||
|
||||
def skipPlotSettings(self, bool=True):
|
||||
"""Tell the loader to skip plot configs."""
|
||||
self.skip_plot_settings = bool
|
||||
|
||||
def skipLimitsAndZoom(self, bool=True):
|
||||
"""Tell the loader to skip limits and zoom factors."""
|
||||
self.skip_limits_and_zoom = bool
|
||||
|
||||
def skipSelectedMembers(self, bool=True):
|
||||
"""Tell the loader to skip selected members."""
|
||||
self.skip_selected_members = bool
|
||||
|
||||
def skipAnnotations(self, bool=True):
|
||||
"""Tell the loader to skip annotations."""
|
||||
self.skip_annotations = bool
|
||||
|
||||
def copy(self, plot_settings):
|
||||
"""Pops up a dialog where the user can choose another settings file to copy settings from."""
|
||||
pscd = PlotSettingsCopyDialog(plot_settings)
|
||||
success = pscd.exec_()
|
||||
if success:
|
||||
self.skipPlotSettings(not pscd.shouldCopyPlotSettings())
|
||||
self.skipLimitsAndZoom(not pscd.shouldCopyRangeLimits())
|
||||
self.skipSelectedMembers(not pscd.shouldCopySelectedMembers())
|
||||
self.skipAnnotations(not pscd.shouldCopyAnnotations())
|
||||
self.load(pscd.getName(), plot_settings)
|
||||
|
||||
|
||||
def load(self, name, plot_settings):
|
||||
"""Load settings into the provided settings file from a plot settings file with the specified name."""
|
||||
filename = "%s/config/%s.xml" % (plot_settings.getPlotConfigPath(), name)
|
||||
|
||||
if os.path.exists(filename):
|
||||
self.doc = xml.dom.minidom.parse(filename)
|
||||
|
||||
block_state = plot_settings.blockSignals(True) # we only want one emit from plot_settings so we only get one redraw
|
||||
|
||||
if not self.skip_plot_settings:
|
||||
self.__loadPlotConfigs(plot_settings)
|
||||
|
||||
if not self.skip_limits_and_zoom:
|
||||
self.__loadLimitsAndZoom(plot_settings)
|
||||
|
||||
if not self.skip_selected_members:
|
||||
self.__loadSelectedMembers(plot_settings)
|
||||
|
||||
if not self.skip_annotations:
|
||||
self.__loadAnnotations(plot_settings)
|
||||
|
||||
plot_settings.blockSignals(block_state)
|
||||
plot_settings.notify()
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def __loadPlotConfigs(self, plot_settings):
|
||||
plot_config_dict = plot_settings.getPlotConfigDict()
|
||||
xml_plot_configs = self.doc.getElementsByTagName("plot_config")
|
||||
|
||||
for xml_plot_config in xml_plot_configs:
|
||||
name = xml_plot_config.getAttribute("name")
|
||||
plot_config = plot_config_dict[name]
|
||||
visible = xml_plot_config.getAttribute("visible")
|
||||
z_order = xml_plot_config.getAttribute("z_order")
|
||||
picker = xml_plot_config.getAttribute("picker")
|
||||
|
||||
plot_config.is_visible = visible.lower() == "true"
|
||||
plot_config.z_order = int(z_order)
|
||||
|
||||
if picker.lower() == "none":
|
||||
plot_config.picker = None
|
||||
else:
|
||||
plot_config.picker = int(picker)
|
||||
|
||||
xml_color = xml_plot_config.getElementsByTagName("color")[0]
|
||||
|
||||
a = xml_color.getAttribute("alpha")
|
||||
r = xml_color.getAttribute("red")
|
||||
g = xml_color.getAttribute("green")
|
||||
b = xml_color.getAttribute("blue")
|
||||
|
||||
plot_config.alpha = float(a)
|
||||
plot_config.color = (float(r), float(g), float(b))
|
||||
|
||||
xml_style = xml_plot_config.getElementsByTagName("style")[0]
|
||||
|
||||
linestyle = xml_style.getAttribute("line")
|
||||
marker = xml_style.getAttribute("marker")
|
||||
|
||||
plot_config.linestyle = linestyle
|
||||
plot_config.marker = marker
|
||||
|
||||
|
||||
def floatify(self, f):
|
||||
if f.lower() == "none":
|
||||
return None
|
||||
else:
|
||||
return float(f)
|
||||
|
||||
def __loadLimitsAndZoom(self, plot_settings):
|
||||
xml_limits_and_zoom = self.doc.getElementsByTagName("limits_and_zoom")[0]
|
||||
|
||||
xml_limits = xml_limits_and_zoom.getElementsByTagName("limits")[0]
|
||||
x_min = xml_limits.getAttribute("x_min")
|
||||
x_max = xml_limits.getAttribute("x_max")
|
||||
y_min = xml_limits.getAttribute("y_min")
|
||||
y_max = xml_limits.getAttribute("y_max")
|
||||
|
||||
plot_settings.setMinXLimit(self.floatify(x_min))
|
||||
plot_settings.setMaxXLimit(self.floatify(x_max))
|
||||
plot_settings.setMinYLimit(self.floatify(y_min))
|
||||
plot_settings.setMaxYLimit(self.floatify(y_max))
|
||||
|
||||
xml_zoom = xml_limits_and_zoom.getElementsByTagName("zoom")[0]
|
||||
|
||||
x_min = xml_zoom.getAttribute("x_min")
|
||||
x_max = xml_zoom.getAttribute("x_max")
|
||||
y_min = xml_zoom.getAttribute("y_min")
|
||||
y_max = xml_zoom.getAttribute("y_max")
|
||||
|
||||
plot_settings.setMinXZoom(self.floatify(x_min))
|
||||
plot_settings.setMaxXZoom(self.floatify(x_max))
|
||||
plot_settings.setMinYZoom(self.floatify(y_min))
|
||||
plot_settings.setMaxYZoom(self.floatify(y_max))
|
||||
|
||||
def __loadSelectedMembers(self, plot_settings):
|
||||
xml_selected_members = self.doc.getElementsByTagName("selected_members")[0]
|
||||
|
||||
xml_members = xml_selected_members.getElementsByTagName("member")
|
||||
|
||||
plot_settings.clearMemberSelection()
|
||||
for member in xml_members:
|
||||
m = member.getAttribute("id")
|
||||
plot_settings.selectMember(int(m))
|
||||
|
||||
def __loadAnnotations(self, plot_settings):
|
||||
xml_annotations_element = self.doc.getElementsByTagName("annotations")[0]
|
||||
|
||||
xml_annotations = xml_annotations_element.getElementsByTagName("annotation")
|
||||
|
||||
plot_settings.clearAnnotations()
|
||||
for annotation in xml_annotations:
|
||||
label = annotation.getAttribute("label")
|
||||
x = annotation.getAttribute("x")
|
||||
y = annotation.getAttribute("y")
|
||||
xt = annotation.getAttribute("xt")
|
||||
yt = annotation.getAttribute("yt")
|
||||
|
||||
plot_settings.addAnnotation(label, self.floatify(x), self.floatify(y), self.floatify(xt), self.floatify(yt))
|
||||
|
||||
|
||||
from PyQt4.QtGui import QDialog, QFormLayout, QLabel, QDialogButtonBox, QComboBox, QCheckBox
|
||||
from PyQt4.QtCore import Qt, SIGNAL
|
||||
from ert_gui.widgets.util import createSpace
|
||||
|
||||
class PlotSettingsCopyDialog(QDialog):
|
||||
"""A dialog for selecting what settings to copy from another settings file."""
|
||||
def __init__(self, plot_settings, parent = None):
|
||||
QDialog.__init__(self, parent)
|
||||
|
||||
self.setModal(True)
|
||||
self.setWindowTitle("Copy plot settings")
|
||||
self.setMinimumWidth(250)
|
||||
self.setMinimumHeight(150)
|
||||
|
||||
layout = QFormLayout()
|
||||
|
||||
self.settings_list = QComboBox()
|
||||
|
||||
files = self.listSettings(plot_settings.getPlotConfigPath() + "/config")
|
||||
|
||||
for file in files:
|
||||
index = file.find(".xml")
|
||||
name = file[0:index]
|
||||
self.settings_list.addItem(name)
|
||||
|
||||
self.check_plot_settings = QCheckBox()
|
||||
self.check_plot_settings.setChecked(True)
|
||||
self.check_range_limits = QCheckBox()
|
||||
self.check_range_limits.setChecked(True)
|
||||
self.check_selected_members = QCheckBox()
|
||||
self.check_selected_members.setChecked(True)
|
||||
self.check_annotations = QCheckBox()
|
||||
self.check_annotations.setChecked(True)
|
||||
|
||||
layout.addRow(createSpace(10))
|
||||
layout.addRow("Copy from:", self.settings_list)
|
||||
layout.addRow("Plot settings:", self.check_plot_settings)
|
||||
layout.addRow("Range limits:", self.check_range_limits)
|
||||
layout.addRow("Selected members:", self.check_selected_members)
|
||||
layout.addRow("Annotations:", self.check_annotations)
|
||||
|
||||
layout.addRow(createSpace(10))
|
||||
|
||||
buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self)
|
||||
|
||||
layout.addRow(buttons)
|
||||
|
||||
self.connect(buttons, SIGNAL('accepted()'), self.accept)
|
||||
self.connect(buttons, SIGNAL('rejected()'), self.reject)
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
def getName(self):
|
||||
"""Return the name of the source."""
|
||||
return str(self.settings_list.currentText()).strip()
|
||||
|
||||
def shouldCopyPlotSettings(self):
|
||||
return self.check_plot_settings.isChecked()
|
||||
|
||||
def shouldCopyRangeLimits(self):
|
||||
return self.check_range_limits.isChecked()
|
||||
|
||||
def shouldCopySelectedMembers(self):
|
||||
return self.check_selected_members.isChecked()
|
||||
|
||||
def shouldCopyAnnotations(self):
|
||||
return self.check_annotations.isChecked()
|
||||
|
||||
def listSettings(self, path):
|
||||
"""Returns a list of settings filenames."""
|
||||
files = os.listdir(path)
|
||||
return sorted(filter(self.xmlFilter, files))
|
||||
|
||||
def xmlFilter(self, file):
|
||||
"""Filter .xml files from a list of filenames"""
|
||||
return file.endswith(".xml")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,228 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'plotview.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
|
||||
|
||||
import datetime
|
||||
import time
|
||||
from ert.ert.erttypes import time_t
|
||||
|
||||
from ert_gui.widgets.util import print_timing
|
||||
from plotdata import PlotData
|
||||
import ert_gui.widgets
|
||||
|
||||
from PyQt4.QtCore import SIGNAL
|
||||
import os
|
||||
|
||||
from plotconfig import PlotConfig
|
||||
from plotfigure import PlotFigure, matplotlib
|
||||
|
||||
from PyQt4.QtGui import QFrame, QInputDialog, QSizePolicy
|
||||
from plotsettingsxml import PlotSettingsSaver, PlotSettingsLoader
|
||||
from plotsettings import PlotSettings
|
||||
from plotsettingsxml import PlotSettingsCopyDialog
|
||||
from plotgenerator import PlotGenerator
|
||||
|
||||
class PlotView(QFrame):
|
||||
"""PlotView presents a matplotlib canvas with interaction possibilities. (picking and tooltip)"""
|
||||
|
||||
def __init__(self):
|
||||
"""Create a PlotView instance"""
|
||||
QFrame.__init__(self)
|
||||
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||
|
||||
# setup some default data values
|
||||
self.data = PlotData()
|
||||
self.data.x_data_type = "number"
|
||||
self.data.setValid(False)
|
||||
|
||||
self.plot_figure = PlotFigure()
|
||||
self.plot_settings = PlotSettings()
|
||||
|
||||
self.canvas = FigureCanvas(self.plot_figure.getFigure())
|
||||
self.canvas.setParent(self)
|
||||
self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||
|
||||
self.mouse_handler = MouseHandler(self)
|
||||
|
||||
def toggleMember(self, line):
|
||||
gid = int(line.get_gid())
|
||||
if gid in self.plot_settings.getSelectedMembers():
|
||||
self.plot_settings.unselectMember(gid)
|
||||
else:
|
||||
self.plot_settings.selectMember(gid)
|
||||
|
||||
@ert_gui.widgets.util.may_take_a_long_time
|
||||
def drawPlot(self):
|
||||
self.plot_figure.drawPlot(self.data, self.plot_settings)
|
||||
self.canvas.draw()
|
||||
|
||||
def resizeEvent(self, event):
|
||||
QFrame.resizeEvent(self, event)
|
||||
self.canvas.resize(event.size().width(), event.size().height())
|
||||
|
||||
def loadSettings(self, name):
|
||||
if self.data.isValid():
|
||||
plot_config_loader = PlotSettingsLoader()
|
||||
if not plot_config_loader.load(name, self.plot_settings):
|
||||
self.drawPlot()
|
||||
|
||||
def saveSettings(self):
|
||||
if self.data.isValid():
|
||||
plot_config_saver = PlotSettingsSaver()
|
||||
plot_config_saver.save(self.data.getSaveName(), self.plot_settings)
|
||||
|
||||
def setData(self, data):
|
||||
self.saveSettings()
|
||||
|
||||
self.data = data
|
||||
|
||||
self.loadSettings(self.data.getSaveName())
|
||||
|
||||
|
||||
def setXZoomFactors(self, xminf, xmaxf):
|
||||
self.plot_settings.setMinXZoom(xminf)
|
||||
self.plot_settings.setMaxXZoom(xmaxf)
|
||||
|
||||
def setYZoomFactors(self, yminf, ymaxf):
|
||||
self.plot_settings.setMinYZoom(yminf)
|
||||
self.plot_settings.setMaxYZoom(ymaxf)
|
||||
|
||||
def save(self):
|
||||
self.saveSettings()
|
||||
|
||||
plot_generator = PlotGenerator(self.plot_settings.getPlotPath(), self.plot_settings.getPlotConfigPath())
|
||||
plot_generator.save(self.data)
|
||||
|
||||
def saveAll(self):
|
||||
self.saveSettings()
|
||||
|
||||
plot_generator = PlotGenerator(self.plot_settings.getPlotPath(), self.plot_settings.getPlotConfigPath())
|
||||
plot_generator.saveAll()
|
||||
|
||||
def copyPlotSettings(self):
|
||||
plot_config_loader = PlotSettingsLoader()
|
||||
plot_config_loader.copy(self.plot_settings)
|
||||
|
||||
def setPlotPath(self, plot_path):
|
||||
self.plot_settings.setPlotPath(plot_path)
|
||||
|
||||
def setPlotConfigPath(self, path):
|
||||
self.plot_settings.setPlotConfigPath(path)
|
||||
|
||||
def _selectedMemberIdentifier(self, artist):
|
||||
return artist.get_gid() in self.plot_settings.getSelectedMembers()
|
||||
|
||||
def clearSelection(self):
|
||||
selected_lines = self.plot_figure.fig.findobj(self._selectedMemberIdentifier)
|
||||
for line in selected_lines:
|
||||
self.plot_settings.unselectMember(line.get_gid())
|
||||
|
||||
|
||||
def displayToolTip(self, event):
|
||||
if not self.data is None and not event.xdata is None and not event.ydata is None:
|
||||
if self.data.getXDataType() == "time":
|
||||
date = matplotlib.dates.num2date(event.xdata)
|
||||
self.setToolTip("x: %s y: %04f" % (date.strftime("%d/%m-%Y"), event.ydata))
|
||||
else:
|
||||
self.setToolTip("x: %04f y: %04f" % (event.xdata, event.ydata))
|
||||
else:
|
||||
self.setToolTip("")
|
||||
|
||||
def annotate(self, label, x, y, xt=None, yt=None):
|
||||
self.plot_settings.addAnnotation(label, x, y, xt, yt)
|
||||
|
||||
def removeAnnotation(self, annotation_artist):
|
||||
annotations = self.plot_settings.getAnnotations()
|
||||
for annotation in annotations:
|
||||
if annotation.getUserData() == annotation_artist:
|
||||
self.plot_settings.removeAnnotation(annotation)
|
||||
|
||||
def moveAnnotation(self, annotation_artist, xt, yt):
|
||||
annotations = self.plot_settings.getAnnotations()
|
||||
for annotation in annotations:
|
||||
if annotation.getUserData() == annotation_artist:
|
||||
annotation.xt = xt
|
||||
annotation.yt = yt
|
||||
|
||||
annotation_artist.xytext = (xt, yt)
|
||||
|
||||
def draw(self):
|
||||
self.canvas.draw()
|
||||
|
||||
def setMinYLimit(self, value):
|
||||
self.plot_settings.setMinYLimit(value)
|
||||
|
||||
def setMaxYLimit(self, value):
|
||||
self.plot_settings.setMaxYLimit(value)
|
||||
|
||||
def setMinXLimit(self, value):
|
||||
self.plot_settings.setMinXLimit(value)
|
||||
|
||||
def setMaxXLimit(self, value):
|
||||
self.plot_settings.setMaxXLimit(value)
|
||||
|
||||
def getPlotConfigList(self):
|
||||
return self.plot_settings.getPlotConfigList()
|
||||
|
||||
class MouseHandler:
|
||||
|
||||
def __init__(self, plot_view):
|
||||
self.plot_view = plot_view
|
||||
|
||||
fig = plot_view.plot_figure.getFigure()
|
||||
fig.canvas.mpl_connect('button_press_event', self.on_press)
|
||||
fig.canvas.mpl_connect('button_release_event', self.on_release)
|
||||
fig.canvas.mpl_connect('pick_event', self.on_pick)
|
||||
fig.canvas.mpl_connect('motion_notify_event', self.motion_notify_event)
|
||||
|
||||
self.button_position = None
|
||||
self.artist = None
|
||||
|
||||
def on_press(self, event):
|
||||
if event.button == 3 and self.artist is None and not event.xdata is None and not event.ydata is None:
|
||||
label, success = QInputDialog.getText(self.plot_view, "New label", "Enter label:")
|
||||
|
||||
if success and not str(label).strip() == "":
|
||||
self.plot_view.annotate(str(label), event.xdata, event.ydata)
|
||||
self.plot_view.draw()
|
||||
|
||||
def on_release(self, event):
|
||||
self.button_position = None
|
||||
self.artist = None
|
||||
|
||||
def on_pick(self, event):
|
||||
if isinstance(event.artist, matplotlib.lines.Line2D) and event.mouseevent.button == 1:
|
||||
self.plot_view.toggleMember(event.artist)
|
||||
elif isinstance(event.artist, matplotlib.text.Annotation) and event.mouseevent.button == 1:
|
||||
self.artist = event.artist
|
||||
self.button_position = (event.mouseevent.x, event.mouseevent.y)
|
||||
return True
|
||||
elif isinstance(event.artist, matplotlib.text.Annotation) and event.mouseevent.button == 3:
|
||||
self.artist = event.artist
|
||||
self.plot_view.removeAnnotation(self.artist)
|
||||
self.plot_view.draw()
|
||||
|
||||
def motion_notify_event(self, event):
|
||||
if self.artist is None:
|
||||
self.plot_view.displayToolTip(event)
|
||||
elif isinstance(self.artist, matplotlib.text.Annotation):
|
||||
if not event.xdata is None and not event.ydata is None:
|
||||
self.plot_view.moveAnnotation(self.artist, event.xdata, event.ydata)
|
||||
self.plot_view.draw()
|
||||
|
||||
|
||||
@@ -1,192 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'rftfetcher.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from fetcher import PlotDataFetcherHandler
|
||||
import ert.ert.ertwrapper as ertwrapper
|
||||
import ert.ert.enums as enums
|
||||
import plotdata
|
||||
from ert.ert.enums import ert_state_enum, obs_impl_type
|
||||
import numpy
|
||||
|
||||
class RFTFetcher(PlotDataFetcherHandler):
|
||||
|
||||
def __init__(self):
|
||||
PlotDataFetcherHandler.__init__(self)
|
||||
|
||||
def initialize(self, ert):
|
||||
ert.prototype("long enkf_main_get_obs(long)")
|
||||
ert.prototype("long enkf_main_get_fs(long)")
|
||||
ert.prototype("int enkf_main_get_ensemble_size(long)")
|
||||
ert.prototype("int enkf_main_get_history_length(long)")
|
||||
|
||||
ert.prototype("bool enkf_fs_has_node(long, long, int, int, int)")
|
||||
ert.prototype("void enkf_fs_fread_node(long, long, int, int, int)")
|
||||
|
||||
ert.prototype("bool enkf_obs_has_key(long, char*)")
|
||||
ert.prototype("long enkf_obs_get_vector(long, char*)")
|
||||
ert.prototype("long enkf_obs_alloc_typed_keylist(long, int)")
|
||||
|
||||
ert.prototype("char* obs_vector_get_state_kw(long)")
|
||||
ert.prototype("long obs_vector_iget_node(long, int)")
|
||||
ert.prototype("int obs_vector_get_num_active(long)")
|
||||
ert.prototype("bool obs_vector_iget_active(long, int)")
|
||||
|
||||
ert.prototype("long enkf_config_node_get_ref(long)")
|
||||
|
||||
ert.prototype("int* field_obs_get_i(long)")
|
||||
ert.prototype("int* field_obs_get_j(long)")
|
||||
ert.prototype("int* field_obs_get_k(long)")
|
||||
ert.prototype("int field_obs_get_size(long)")
|
||||
ert.prototype("void field_obs_iget(long, int, double*, double*)")
|
||||
|
||||
ert.prototype("double field_ijk_get_double(long, int, int, int)")
|
||||
|
||||
ert.prototype("long field_config_get_grid(long)")
|
||||
|
||||
ert.prototype("long enkf_node_alloc(long)")
|
||||
ert.prototype("void enkf_node_free(long)")
|
||||
ert.prototype("long enkf_node_value_ptr(long)")
|
||||
|
||||
ert.prototype("void ecl_grid_get_xyz3(long, int, int, int, double*, double*, double*)", lib=ert.ecl)
|
||||
|
||||
def isHandlerFor(self, ert, key):
|
||||
enkf_obs = ert.enkf.enkf_main_get_obs(ert.main)
|
||||
key_list = ert.enkf.enkf_obs_alloc_typed_keylist(enkf_obs, obs_impl_type.FIELD_OBS.value())
|
||||
field_obs = ert.getStringList(key_list, free_after_use=True)
|
||||
return key in field_obs
|
||||
|
||||
def fetch(self, ert, key, parameter, data, comparison_fs):
|
||||
enkf_obs = ert.enkf.enkf_main_get_obs(ert.main)
|
||||
obs_vector = ert.enkf.enkf_obs_get_vector(enkf_obs, key)
|
||||
|
||||
num_active = ert.enkf.obs_vector_get_num_active(obs_vector)
|
||||
if num_active == 1:
|
||||
report_step = ert.enkf.obs_vector_get_active_report_step(obs_vector)
|
||||
elif num_active > 1:
|
||||
history_length = ert.enkf.enkf_main_get_history_length(ert.main)
|
||||
active = []
|
||||
for index in range(history_length):
|
||||
if ert.enkf.obs_vector_iget_active(obs_vector , index):
|
||||
active.append(index)
|
||||
print "Active:", active
|
||||
report_step = active[0] #todo: enable selection from GUI
|
||||
else:
|
||||
return
|
||||
|
||||
fs = ert.enkf.enkf_main_get_fs(ert.main)
|
||||
state_kw = ert.enkf.obs_vector_get_state_kw(obs_vector)
|
||||
|
||||
ens_size = ert.enkf.enkf_main_get_ensemble_size(ert.main)
|
||||
config_node = ert.enkf.ensemble_config_get_node(ert.ensemble_config, state_kw)
|
||||
field_config = ert.enkf.enkf_config_node_get_ref(config_node)
|
||||
field_obs = ert.enkf.obs_vector_iget_node(obs_vector, report_step)
|
||||
|
||||
i = ert.enkf.field_obs_get_i(field_obs)
|
||||
j = ert.enkf.field_obs_get_j(field_obs)
|
||||
k = ert.enkf.field_obs_get_k(field_obs)
|
||||
obs_size = ert.enkf.field_obs_get_size(field_obs)
|
||||
grid = ert.enkf.field_config_get_grid(field_config)
|
||||
|
||||
node = ert.enkf.enkf_node_alloc(config_node)
|
||||
|
||||
y_obs = []
|
||||
x_obs = []
|
||||
x_std = []
|
||||
xpos = (ertwrapper.c_double)()
|
||||
ypos = (ertwrapper.c_double)()
|
||||
zpos = (ertwrapper.c_double)()
|
||||
value = (ertwrapper.c_double)()
|
||||
std = (ertwrapper.c_double)()
|
||||
for index in range(obs_size):
|
||||
ert.ecl.ecl_grid_get_xyz3(grid, i[index], j[index], k[index], xpos, ypos , zpos)
|
||||
y_obs.append(zpos.value)
|
||||
ert.enkf.field_obs_iget(field_obs, index, value, std)
|
||||
x_obs.append(value.value)
|
||||
x_std.append(std.value)
|
||||
data.checkMaxMin(value.value + std.value)
|
||||
data.checkMaxMin(value.value - std.value)
|
||||
data.obs_y = numpy.array(y_obs)
|
||||
data.obs_x = numpy.array(x_obs)
|
||||
data.obs_std_x = numpy.array(x_std)
|
||||
data.obs_std_y = None
|
||||
|
||||
|
||||
for member in range(ens_size):
|
||||
if ert.enkf.enkf_fs_has_node(fs, config_node, report_step, member, ert_state_enum.ANALYZED.value()):
|
||||
ert.enkf.enkf_fs_fread_node(fs, node, report_step, member, ert_state_enum.ANALYZED.value())
|
||||
elif ert.enkf.enkf_fs_has_node(fs, config_node, report_step, member, ert_state_enum.FORECAST.value()):
|
||||
ert.enkf.enkf_fs_fread_node(fs, node, report_step, member, ert_state_enum.FORECAST.value())
|
||||
else:
|
||||
print "No data found for member %d/%d." % (member, report_step)
|
||||
continue
|
||||
|
||||
data.x_data[member] = []
|
||||
data.y_data[member] = []
|
||||
x_data = data.x_data[member]
|
||||
y_data = data.y_data[member]
|
||||
|
||||
field = ert.enkf.enkf_node_value_ptr(node)
|
||||
for index in range(obs_size):
|
||||
value = ert.enkf.field_ijk_get_double(field, i[index] , j[index] , k[index])
|
||||
x_data.append(value)
|
||||
y_data.append(y_obs[index])
|
||||
data.checkMaxMin(value)
|
||||
|
||||
data.x_data[member] = numpy.array(x_data)
|
||||
data.y_data[member] = numpy.array(y_data)
|
||||
|
||||
if not comparison_fs is None:
|
||||
comp_node = ert.enkf.enkf_node_alloc(config_node)
|
||||
for member in range(ens_size):
|
||||
if ert.enkf.enkf_fs_has_node(comparison_fs, config_node, report_step, member, ert_state_enum.ANALYZED.value()):
|
||||
ert.enkf.enkf_fs_fread_node(comparison_fs, comp_node, report_step, member, ert_state_enum.ANALYZED.value())
|
||||
elif ert.enkf.enkf_fs_has_node(comparison_fs, config_node, report_step, member, ert_state_enum.FORECAST.value()):
|
||||
ert.enkf.enkf_fs_fread_node(comparison_fs, comp_node, report_step, member, ert_state_enum.FORECAST.value())
|
||||
else:
|
||||
print "No data found for member %d/%d." % (member, report_step)
|
||||
continue
|
||||
|
||||
data.x_comp_data[member] = []
|
||||
data.y_comp_data[member] = []
|
||||
x_data = data.x_comp_data[member]
|
||||
y_data = data.y_comp_data[member]
|
||||
|
||||
field = ert.enkf.enkf_node_value_ptr(comp_node)
|
||||
for index in range(obs_size):
|
||||
value = ert.enkf.field_ijk_get_double(field, i[index] , j[index] , k[index])
|
||||
x_data.append(value)
|
||||
y_data.append(y_obs[index])
|
||||
data.checkMaxMin(value)
|
||||
|
||||
data.x_comp_data[member] = numpy.array(x_data)
|
||||
data.y_comp_data[member] = numpy.array(y_data)
|
||||
|
||||
ert.enkf.enkf_node_free(comp_node)
|
||||
|
||||
ert.enkf.enkf_node_free(node)
|
||||
|
||||
data.x_data_type = "number"
|
||||
data.inverted_y_axis = True
|
||||
|
||||
def getConfigurationWidget(self, context_data):
|
||||
return None
|
||||
|
||||
def configure(self, parameter, context_data):
|
||||
pass #nothing to configure, yet
|
||||
|
||||
|
||||
|
||||
@@ -1,221 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'zoomslider.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4.QtGui import QFrame, QPainter, QColor
|
||||
from PyQt4.QtCore import QRectF, SIGNAL
|
||||
from PyQt4.Qt import QApplication, Qt
|
||||
|
||||
class ZoomSlider(QFrame):
|
||||
"""
|
||||
Two way slider representing narrowing of a view.
|
||||
The sliders coorespond to factors: a min value and a max value in the range [0, 1]
|
||||
Emits zoomValueChanged(float, float) whenever the markers are adjusted. (float, float) -> (min, max)
|
||||
"""
|
||||
def __init__(self, parent=None, horizontal=True):
|
||||
QFrame.__init__(self, parent)
|
||||
|
||||
self.horizontal = horizontal
|
||||
if horizontal:
|
||||
self.setFrameShape(QFrame.HLine)
|
||||
self.setMinimumHeight(21)
|
||||
self.tilt = 90
|
||||
else:
|
||||
self.setFrameShape(QFrame.VLine)
|
||||
self.setMinimumWidth(21)
|
||||
self.tilt = 180
|
||||
|
||||
self.setFrameShadow(QFrame.Sunken)
|
||||
self.setMidLineWidth(3)
|
||||
|
||||
self.setMouseTracking(True)
|
||||
|
||||
self.size = 12
|
||||
|
||||
self.min_value = 0.0
|
||||
self.max_value = 1.0
|
||||
|
||||
self.setDefaultColors()
|
||||
self.button = Qt.NoButton
|
||||
self.selected_marker = 'none'
|
||||
|
||||
|
||||
def paintEvent(self, paint_event):
|
||||
QFrame.paintEvent(self, paint_event)
|
||||
painter = QPainter(self)
|
||||
painter.setRenderHint(QPainter.Antialiasing)
|
||||
|
||||
w = self.width()
|
||||
h = self.height()
|
||||
|
||||
if self.horizontal:
|
||||
self.min_marker = QRectF(w * self.min_value, 4, self.size, self.size)
|
||||
self.max_marker = QRectF(w * self.max_value - self.size - 1, 4, self.size, self.size)
|
||||
else:
|
||||
self.min_marker = QRectF(4, h - h * self.min_value - self.size - 1, self.size, self.size)
|
||||
self.max_marker = QRectF(4, h - h * self.max_value, self.size, self.size)
|
||||
|
||||
pen = painter.pen()
|
||||
pen.setWidth(0)
|
||||
pen.setColor(QApplication.palette().background().color().dark())
|
||||
painter.setPen(pen)
|
||||
|
||||
painter.setBrush(self.min_marker_brush)
|
||||
painter.drawPie(self.min_marker, self.tilt * 16, 180 * 16)
|
||||
|
||||
painter.setBrush(self.max_marker_brush)
|
||||
painter.drawPie(self.max_marker, self.tilt * 16, -180 * 16)
|
||||
|
||||
def resizeEvent (self, resize_event):
|
||||
QFrame.resizeEvent(self, resize_event)
|
||||
|
||||
|
||||
def _getMinTestMarker(self):
|
||||
"""Returns the "real" marker bounds. Adjusted for the missing part of an arc."""
|
||||
if self.horizontal:
|
||||
return QRectF(self.min_marker.left(),
|
||||
self.min_marker.top(),
|
||||
self.min_marker.width() / 2.0,
|
||||
self.min_marker.height())
|
||||
else:
|
||||
return QRectF(self.min_marker.left(),
|
||||
self.min_marker.top() + self.min_marker.height() / 2.0,
|
||||
self.min_marker.width(),
|
||||
self.min_marker.height() / 2.0)
|
||||
|
||||
def _getMaxTestMarker(self):
|
||||
"""Returns the "real" marker bounds. Adjusted for the missing part of an arc."""
|
||||
if self.horizontal:
|
||||
return QRectF(self.max_marker.left() + self.max_marker.width() / 2.0,
|
||||
self.max_marker.top(),
|
||||
self.max_marker.width() / 2.0,
|
||||
self.max_marker.height())
|
||||
|
||||
else:
|
||||
return QRectF(self.max_marker.left(),
|
||||
self.max_marker.top(),
|
||||
self.max_marker.width(),
|
||||
self.max_marker.height() / 2.0)
|
||||
|
||||
def mouseMoveEvent (self, mouse_event):
|
||||
"""Dragging or highlighting the markers."""
|
||||
self.setDefaultColors()
|
||||
|
||||
min_test_marker = self._getMinTestMarker()
|
||||
|
||||
if min_test_marker.contains(mouse_event.x(), mouse_event.y()) or self.selected_marker == 'min':
|
||||
self.min_marker_brush = self.getDefaultHighlightColor()
|
||||
|
||||
if self.selected_marker == 'min':
|
||||
if self.horizontal:
|
||||
value = mouse_event.x() / float(self.width())
|
||||
else:
|
||||
value = (self.height() - mouse_event.y()) / float(self.height())
|
||||
|
||||
self.setMinValue(value, False)
|
||||
|
||||
max_test_marker = self._getMaxTestMarker()
|
||||
|
||||
if max_test_marker.contains(mouse_event.x(), mouse_event.y()) or self.selected_marker == 'max':
|
||||
self.max_marker_brush = self.getDefaultHighlightColor()
|
||||
|
||||
if self.selected_marker == 'max':
|
||||
if self.horizontal:
|
||||
value = mouse_event.x() / float(self.width())
|
||||
else:
|
||||
value = (self.height() - mouse_event.y()) / float(self.height())
|
||||
|
||||
self.setMaxValue(value, False)
|
||||
|
||||
self.update()
|
||||
|
||||
|
||||
def mousePressEvent (self, mouse_event):
|
||||
"""Selecting a marker."""
|
||||
if mouse_event.button() == Qt.LeftButton:
|
||||
min_test_marker = self._getMinTestMarker()
|
||||
|
||||
if min_test_marker.contains(mouse_event.x(), mouse_event.y()):
|
||||
self.selected_marker = 'min'
|
||||
|
||||
max_test_marker = self._getMaxTestMarker()
|
||||
|
||||
if max_test_marker.contains(mouse_event.x(), mouse_event.y()):
|
||||
self.selected_marker = 'max'
|
||||
|
||||
|
||||
def mouseReleaseEvent (self, mouse_event):
|
||||
self.selected_marker = 'none'
|
||||
|
||||
def leaveEvent (self, event):
|
||||
self.setDefaultColors()
|
||||
|
||||
def getDefaultMarkerColor(self):
|
||||
return QApplication.palette().background().color().light(175)
|
||||
|
||||
def getDefaultHighlightColor(self):
|
||||
return QApplication.palette().highlight().color()
|
||||
|
||||
def setDefaultColors(self):
|
||||
self.min_marker_brush = self.getDefaultMarkerColor()
|
||||
self.max_marker_brush = self.getDefaultMarkerColor()
|
||||
self.update()
|
||||
|
||||
def setMaxValue(self, max_value, update=True):
|
||||
"""The the position of the max marker."""
|
||||
if self.horizontal:
|
||||
m = float(self.width())
|
||||
else:
|
||||
m = float(self.height())
|
||||
|
||||
marker_offset = (self.size + 1) / m
|
||||
|
||||
if not self.max_value == max_value:
|
||||
self.max_value = max_value
|
||||
if self.max_value - marker_offset <= self.min_value:
|
||||
self.max_value = self.min_value + marker_offset
|
||||
if self.max_value > 1.0:
|
||||
self.max_value = 1
|
||||
|
||||
#print "max:", self.min_value, self.max_value
|
||||
|
||||
self.emit(SIGNAL('zoomValueChanged(float, float)'), self.min_value, self.max_value)
|
||||
|
||||
if update:
|
||||
self.update()
|
||||
|
||||
def setMinValue(self, min_value, update=True):
|
||||
"""The the position of the min marker."""
|
||||
if self.horizontal:
|
||||
m = float(self.width())
|
||||
else:
|
||||
m = float(self.height())
|
||||
|
||||
marker_offset = (self.size + 1) / m
|
||||
|
||||
if not self.min_value == min_value:
|
||||
self.min_value = min_value
|
||||
if self.min_value + marker_offset >= self.max_value:
|
||||
self.min_value = self.max_value - marker_offset
|
||||
if self.min_value < 0.0:
|
||||
self.min_value = 0.0
|
||||
|
||||
#print "min:", self.min_value, self.max_value
|
||||
|
||||
self.emit(SIGNAL('zoomValueChanged(float, float)'), self.min_value, self.max_value)
|
||||
|
||||
if update:
|
||||
self.update()
|
||||
@@ -1,17 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file '__init__.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'legend.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
|
||||
class LegendMarker(QtGui.QWidget):
|
||||
"""A widget that shows a colored box"""
|
||||
def __init__(self, color, parent = None):
|
||||
QtGui.QWidget.__init__(self, parent)
|
||||
|
||||
self.setMaximumSize(QtCore.QSize(12, 12))
|
||||
self.setMinimumSize(QtCore.QSize(12, 12))
|
||||
|
||||
self.color = color
|
||||
|
||||
def paintEvent(self, paintevent):
|
||||
"""Paints the box"""
|
||||
painter = QtGui.QPainter(self)
|
||||
|
||||
rect = self.contentsRect()
|
||||
rect.setWidth(rect.width() - 1)
|
||||
rect.setHeight(rect.height() - 1)
|
||||
painter.drawRect(rect)
|
||||
|
||||
rect.setX(rect.x() + 1)
|
||||
rect.setY(rect.y() + 1)
|
||||
painter.fillRect(rect, self.color)
|
||||
|
||||
class Legend(QtGui.QHBoxLayout):
|
||||
"""Combines a LegendMarker with a label"""
|
||||
def __init__(self, legend, color, parent=None):
|
||||
QtGui.QHBoxLayout.__init__(self, parent)
|
||||
|
||||
legendMarker = LegendMarker(color, parent)
|
||||
self.addWidget(legendMarker)
|
||||
self.addWidget(QtGui.QLabel(legend))
|
||||
legendMarker.setToolTip(legend)
|
||||
@@ -1,249 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'runpanel.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
|
||||
from ert_gui.widgets.helpedwidget import HelpedWidget, ContentModel
|
||||
from ert_gui.widgets.util import resourceIcon, ListCheckPanel, ValidatedTimestepCombo, createSpace, getItemsFromList, frange
|
||||
import threading
|
||||
import time
|
||||
#import widgets
|
||||
import math
|
||||
from ert_gui.widgets.cogwheel import Cogwheel
|
||||
from simulation import SimulationList, SimulationItemDelegate, SimulationItem, Simulation
|
||||
from legend import Legend
|
||||
from simulationsdialog import SimulationsDialog
|
||||
|
||||
class RunWidget(HelpedWidget):
|
||||
"""A widget that shows simulation parameters and the possibility to start the simulation"""
|
||||
run_mode_type = {"ENKF_ASSIMILATION" : 1, "ENSEMBLE_EXPERIMENT" : 2, "ENSEMBLE_PREDICTION" : 3, "INIT_ONLY" : 4}
|
||||
state_enum = {"UNDEFINED" : 0, "SERIALIZED" : 1, "FORECAST" : 2, "ANALYZED" : 4, "BOTH" : 6}
|
||||
|
||||
def __init__(self, parent=None):
|
||||
HelpedWidget.__init__(self, parent, widgetLabel="", helpLabel="") #
|
||||
|
||||
self.addLayout(self.createPanel(parent))
|
||||
|
||||
self.modelConnect("ensembleResized()", self.fetchContent)
|
||||
self.modelConnect("runpathChanged()", self.fetchContent)
|
||||
#self.rbAssimilation.toggle()
|
||||
self.rbExperiment.toggle()
|
||||
|
||||
def createPanel(self, parent):
|
||||
"""Creates the panel with the simulation parameters."""
|
||||
self.membersList = QtGui.QListWidget(self)
|
||||
self.membersList.setSelectionMode(QtGui.QAbstractItemView.MultiSelection)
|
||||
|
||||
self.membersList.setViewMode(QtGui.QListView.IconMode)
|
||||
self.membersList.setMovement(QtGui.QListView.Static)
|
||||
self.membersList.setResizeMode(QtGui.QListView.Adjust)
|
||||
self.membersList.setGridSize(QtCore.QSize(32, 16))
|
||||
self.membersList.setSelectionRectVisible(False)
|
||||
|
||||
memberLayout = QtGui.QFormLayout()
|
||||
memberLayout.setLabelAlignment(QtCore.Qt.AlignRight)
|
||||
|
||||
self.runpathLabel = QtGui.QLabel("")
|
||||
font = self.runpathLabel.font()
|
||||
font.setWeight(QtGui.QFont.Bold)
|
||||
self.runpathLabel.setFont(font)
|
||||
|
||||
memberLayout.addRow("Runpath:", self.runpathLabel)
|
||||
|
||||
membersCheckPanel = ListCheckPanel(self.membersList)
|
||||
#membersCheckPanel.insertWidget(0, QtGui.QLabel("Members"))
|
||||
|
||||
self.simulateFrom = ValidatedTimestepCombo(parent, fromLabel="Start", toLabel="End of history")
|
||||
self.simulateTo = ValidatedTimestepCombo(parent, fromLabel="End of history", toLabel="End of prediction")
|
||||
|
||||
self.startState = QtGui.QComboBox(self)
|
||||
self.startState.setMaximumWidth(100)
|
||||
self.startState.setToolTip("Select state")
|
||||
self.startState.addItem("Analyzed")
|
||||
self.startState.addItem("Forecast")
|
||||
|
||||
startLayout = QtGui.QHBoxLayout()
|
||||
startLayout.addWidget(self.simulateFrom)
|
||||
startLayout.addWidget(self.startState)
|
||||
|
||||
memberLayout.addRow("Run simulation from: ", startLayout)
|
||||
memberLayout.addRow("Run simulation to: ", self.simulateTo)
|
||||
memberLayout.addRow("Mode: ", self.createRadioButtons())
|
||||
memberLayout.addRow(membersCheckPanel)
|
||||
memberLayout.addRow("Members:", self.membersList)
|
||||
|
||||
self.actionButton = QtGui.QPushButton("Run simulations")
|
||||
|
||||
self.connect(self.actionButton, QtCore.SIGNAL('clicked()'), self.run)
|
||||
|
||||
actionLayout = QtGui.QHBoxLayout()
|
||||
actionLayout.addStretch(1)
|
||||
actionLayout.addWidget(self.actionButton)
|
||||
actionLayout.addStretch(1)
|
||||
|
||||
memberLayout.addRow(createSpace(10))
|
||||
memberLayout.addRow(actionLayout)
|
||||
|
||||
self.setRunpath("...")
|
||||
|
||||
return memberLayout
|
||||
|
||||
|
||||
def run(self):
|
||||
"""Do pre run checks and start the simulation. A new dialog will be shown with simulation information."""
|
||||
ert = self.getModel()
|
||||
selectedMembers = getItemsFromList(self.membersList)
|
||||
|
||||
selectedMembers = [int(member) for member in selectedMembers]
|
||||
|
||||
if len(selectedMembers) == 0:
|
||||
QtGui.QMessageBox.warning(self, "Missing data", "At least one member must be selected!")
|
||||
return
|
||||
|
||||
member_mask = ert.createBoolVector(self.membersList.count(), selectedMembers)
|
||||
if not ert.enkf.enkf_main_is_initialized(ert.main, member_mask):
|
||||
QtGui.QMessageBox.warning(self, "Case not initialized", "The case must be initialized before simulation can start!")
|
||||
return
|
||||
ert.freeBoolVector(member_mask)
|
||||
|
||||
|
||||
simFrom = self.simulateFrom.getSelectedValue()
|
||||
simTo = self.simulateTo.getSelectedValue()
|
||||
|
||||
if self.rbAssimilation.isChecked():
|
||||
mode = self.run_mode_type["ENKF_ASSIMILATION"]
|
||||
else:
|
||||
if simTo == -1: # -1 == End
|
||||
mode = self.run_mode_type["ENSEMBLE_PREDICTION"]
|
||||
else:
|
||||
mode = self.run_mode_type["ENSEMBLE_EXPERIMENT"]
|
||||
|
||||
state = self.state_enum["ANALYZED"]
|
||||
if self.startState.currentText() == "Forecast" and not simFrom == 0:
|
||||
state = self.state_enum["FORECAST"]
|
||||
|
||||
init_step_parameter = simFrom
|
||||
|
||||
#if mode == run_mode_type["ENKF_ASSIMILATION"]:
|
||||
# init_step_parameter = simFrom
|
||||
#elif mode == run_mode_type["ENSEMBLE_EXPERIMENT"]:
|
||||
# init_step_parameter = 0
|
||||
#else:
|
||||
# init_step_parameter = self.historyLength
|
||||
|
||||
jobsdialog = SimulationsDialog(self)
|
||||
jobsdialog.start(ert = ert,
|
||||
memberCount = self.membersList.count(),
|
||||
selectedMembers = selectedMembers,
|
||||
simFrom = simFrom,
|
||||
simTo = simTo,
|
||||
mode = mode,
|
||||
state = state,
|
||||
init_step_parameter = init_step_parameter)
|
||||
|
||||
|
||||
def setRunpath(self, runpath):
|
||||
"""Update the label widget with a new runpath"""
|
||||
self.runpathLabel.setText(runpath)
|
||||
|
||||
def fetchContent(self):
|
||||
"""Fetch updated data from ERT"""
|
||||
data = self.getFromModel()
|
||||
|
||||
self.historyLength = data["history_length"]
|
||||
|
||||
self.membersList.clear()
|
||||
|
||||
for member in data["members"]:
|
||||
self.membersList.addItem("%03d" % (member))
|
||||
#self.membersList.addItem(str(member))
|
||||
|
||||
self.setRunpath(data["runpath"])
|
||||
|
||||
self.simulateFrom.setHistoryLength(self.historyLength)
|
||||
self.simulateTo.setFromValue(self.historyLength)
|
||||
self.simulateTo.setToValue(-1)
|
||||
self.simulateTo.setMinTimeStep(0)
|
||||
self.simulateTo.setMaxTimeStep(self.historyLength)
|
||||
|
||||
self.membersList.selectAll()
|
||||
|
||||
|
||||
def initialize(self, ert):
|
||||
"""Prototype functions"""
|
||||
ert.prototype("int enkf_main_get_ensemble_size(long)")
|
||||
ert.prototype("int enkf_main_get_history_length(long)")
|
||||
ert.prototype("char* model_config_get_runpath_as_char(long)")
|
||||
ert.prototype("bool enkf_main_is_initialized(long)")
|
||||
|
||||
def getter(self, ert):
|
||||
"""Fetch data from EnKF. Such as number of realizations, runpath and number of timesteps."""
|
||||
members = ert.enkf.enkf_main_get_ensemble_size(ert.main)
|
||||
historyLength = ert.enkf.enkf_main_get_history_length(ert.main)
|
||||
runpath = ert.enkf.model_config_get_runpath_as_char(ert.model_config)
|
||||
|
||||
return {"members" : range(members), "history_length" : historyLength, "runpath" : runpath}
|
||||
|
||||
|
||||
def rbToggle(self):
|
||||
"""Activated when a toggle is selected. Enables/disables member selection."""
|
||||
if self.rbAssimilation.isChecked():
|
||||
self.membersList.setSelectionEnabled(False)
|
||||
self.membersList.selectAll()
|
||||
else:
|
||||
self.membersList.setSelectionEnabled(True)
|
||||
|
||||
def createRadioButtons(self):
|
||||
"""Create a toggle between assimilation and experiment."""
|
||||
radioLayout = QtGui.QVBoxLayout()
|
||||
radioLayout.setSpacing(2)
|
||||
self.rbExperiment = QtGui.QRadioButton("Ensemble experiment")
|
||||
radioLayout.addWidget(self.rbExperiment)
|
||||
self.rbAssimilation = QtGui.QRadioButton("EnKF assimilation")
|
||||
radioLayout.addWidget(self.rbAssimilation)
|
||||
|
||||
|
||||
|
||||
self.connect(self.rbAssimilation , QtCore.SIGNAL('toggled(bool)'), lambda : self.rbToggle())
|
||||
self.connect(self.rbExperiment , QtCore.SIGNAL('toggled(bool)'), lambda : self.rbToggle())
|
||||
|
||||
return radioLayout
|
||||
|
||||
|
||||
class RunPanel(QtGui.QFrame):
|
||||
"""A panel that represents data relateed to starting simulation."""
|
||||
def __init__(self, parent):
|
||||
QtGui.QFrame.__init__(self, parent)
|
||||
self.setFrameShape(QtGui.QFrame.Panel)
|
||||
self.setFrameShadow(QtGui.QFrame.Raised)
|
||||
|
||||
panelLayout = QtGui.QVBoxLayout()
|
||||
self.setLayout(panelLayout)
|
||||
|
||||
# button = QtGui.QPushButton("Refetch")
|
||||
# self.connect(button, QtCore.SIGNAL('clicked()'), ContentModel.updateObservers)
|
||||
# panelLayout.addWidget(button)
|
||||
|
||||
panelLayout.addWidget(RunWidget())
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,593 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'simulation.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from __future__ import division
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from ert_gui.widgets.util import resourceIcon, resourceStateIcon, shortTime
|
||||
import time
|
||||
from ert.ert.enums import ert_job_status_type
|
||||
|
||||
|
||||
class SimulationList(QtGui.QListWidget):
|
||||
"""A list widget with custom items representing simulation jobs"""
|
||||
def __init__(self):
|
||||
QtGui.QListWidget.__init__(self)
|
||||
|
||||
self.setViewMode(QtGui.QListView.IconMode)
|
||||
self.setMovement(QtGui.QListView.Static)
|
||||
self.setResizeMode(QtGui.QListView.Adjust)
|
||||
|
||||
self.setItemDelegate(SimulationItemDelegate())
|
||||
self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
|
||||
self.setSelectionRectVisible(False)
|
||||
|
||||
self.setSortingEnabled(True)
|
||||
self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
|
||||
|
||||
|
||||
class SimulationItem(QtGui.QListWidgetItem):
|
||||
"""Items for the custom SimulationList"""
|
||||
def __init__(self, simulation):
|
||||
self.simulation = simulation
|
||||
QtGui.QListWidgetItem.__init__(self, type=9901)
|
||||
self.setData(QtCore.Qt.DisplayRole, self.simulation)
|
||||
|
||||
def __ge__(self, other):
|
||||
return self.simulation >= other.simulation
|
||||
|
||||
def __lt__(self, other):
|
||||
return not self >= other
|
||||
|
||||
|
||||
class SimulationItemDelegate(QtGui.QStyledItemDelegate):
|
||||
"""The delegate that renders the custom SimulationListItems"""
|
||||
waiting = QtGui.QColor(164 , 164 , 255)
|
||||
pending = QtGui.QColor(164 , 200 , 255)
|
||||
running = QtGui.QColor(200 , 255 , 200)
|
||||
failed = QtGui.QColor(255 , 200 , 200)
|
||||
|
||||
userkilled = QtGui.QColor(255, 255, 200)
|
||||
finished = QtGui.QColor(200, 200, 200)
|
||||
notactive = QtGui.QColor(255, 255, 255)
|
||||
unknown = running # Loading + the intermidate states.
|
||||
|
||||
#Cool orange color: QtGui.QColor(255, 200, 128)
|
||||
|
||||
size = QtCore.QSize(32, 18)
|
||||
|
||||
def __init__(self):
|
||||
QtGui.QStyledItemDelegate.__init__(self)
|
||||
|
||||
def paint(self, painter, option, index):
|
||||
"""Renders the item"""
|
||||
painter.save()
|
||||
painter.setRenderHint(QtGui.QPainter.Antialiasing)
|
||||
|
||||
data = index.data(QtCore.Qt.DisplayRole)
|
||||
|
||||
if data is None:
|
||||
data = Simulation("0")
|
||||
data.status = 0
|
||||
else:
|
||||
data = data.toPyObject()
|
||||
|
||||
if data.isWaiting():
|
||||
color = self.waiting
|
||||
elif data.isPending():
|
||||
color = self.pending
|
||||
elif data.isRunning():
|
||||
color = self.running
|
||||
elif data.finishedSuccessfully():
|
||||
color = self.finished
|
||||
elif data.hasFailed():
|
||||
color = self.failed
|
||||
elif data.notActive():
|
||||
color = self.notactive
|
||||
elif data.isUserKilled():
|
||||
color = self.userkilled
|
||||
else:
|
||||
color = self.unknown
|
||||
|
||||
painter.setPen(color)
|
||||
rect = QtCore.QRect(option.rect)
|
||||
rect.setX(rect.x() + 1)
|
||||
rect.setY(rect.y() + 1)
|
||||
rect.setWidth(rect.width() - 2)
|
||||
rect.setHeight(rect.height() - 2)
|
||||
painter.fillRect(rect, color)
|
||||
|
||||
painter.setPen(QtCore.Qt.black)
|
||||
|
||||
painter.setRenderHint(QtGui.QPainter.Antialiasing, False)
|
||||
painter.drawRect(rect)
|
||||
|
||||
if option.state & QtGui.QStyle.State_Selected:
|
||||
painter.fillRect(option.rect, QtGui.QColor(255, 255, 255, 150))
|
||||
|
||||
painter.drawText(rect, QtCore.Qt.AlignCenter + QtCore.Qt.AlignVCenter, str(data.name))
|
||||
|
||||
painter.restore()
|
||||
|
||||
def sizeHint(self, option, index):
|
||||
"""Returns the size of the item"""
|
||||
return self.size
|
||||
|
||||
|
||||
class SimulationPanel(QtGui.QStackedWidget):
|
||||
"""
|
||||
A panel that shows information and enables interaction with jobs.
|
||||
Three different views: no selected jobs, one selected job and multiple selected jobs.
|
||||
"""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QtGui.QStackedWidget.__init__(self, parent)
|
||||
self.setFrameShape(QtGui.QFrame.Panel)
|
||||
self.setFrameShadow(QtGui.QFrame.Raised)
|
||||
|
||||
self.setMinimumWidth(200)
|
||||
self.setMaximumWidth(200)
|
||||
|
||||
self.ctrl = SimulationPanelController(self)
|
||||
|
||||
self.createNoSelectionsPanel()
|
||||
self.createSingleSelectionsPanel()
|
||||
self.createManySelectionsPanel()
|
||||
|
||||
self.addWidget(self.noSimulationsPanel)
|
||||
self.addWidget(self.singleSimulationsPanel)
|
||||
self.addWidget(self.manySimulationsPanel)
|
||||
|
||||
|
||||
def createButtons(self):
|
||||
"""Create kill, restart and resample and restart buttons"""
|
||||
self.killButton = QtGui.QToolButton(self)
|
||||
self.killButton.setIcon(resourceIcon("cross"))
|
||||
self.killButton.setToolTip("Kill job")
|
||||
self.connect(self.killButton, QtCore.SIGNAL('clicked()'), self.ctrl.kill)
|
||||
|
||||
self.restartButton = QtGui.QToolButton(self)
|
||||
self.restartButton.setIcon(resourceIcon("refresh"))
|
||||
self.restartButton.setToolTip("Restart job")
|
||||
self.connect(self.restartButton, QtCore.SIGNAL('clicked()'), lambda : self.ctrl.restart(False))
|
||||
|
||||
self.rrButton = QtGui.QToolButton(self)
|
||||
self.rrButton.setIcon(resourceIcon("refresh_resample"))
|
||||
self.rrButton.setToolTip("Resample and restart job")
|
||||
self.connect(self.rrButton, QtCore.SIGNAL('clicked()'), lambda : self.ctrl.restart(True))
|
||||
|
||||
buttonLayout = QtGui.QHBoxLayout()
|
||||
buttonLayout.addWidget(self.killButton)
|
||||
buttonLayout.addWidget(self.restartButton)
|
||||
buttonLayout.addWidget(self.rrButton)
|
||||
|
||||
return buttonLayout
|
||||
|
||||
def createButtonedLayout(self, layout, prestretch=True):
|
||||
"""A centered layout for buttons"""
|
||||
btnlayout = QtGui.QVBoxLayout()
|
||||
btnlayout.addLayout(layout)
|
||||
|
||||
if prestretch:
|
||||
btnlayout.addStretch(1)
|
||||
|
||||
btnlayout.addLayout(self.createButtons())
|
||||
return btnlayout
|
||||
|
||||
|
||||
def createManySelectionsPanel(self):
|
||||
"""The panel for multiple selected jobs"""
|
||||
self.manySimulationsPanel = QtGui.QWidget()
|
||||
|
||||
layout = QtGui.QVBoxLayout()
|
||||
label = QtGui.QLabel("Selected jobs:")
|
||||
label.setAlignment(QtCore.Qt.AlignHCenter)
|
||||
layout.addWidget(label)
|
||||
|
||||
self.selectedSimulationsLabel = QtGui.QLabel()
|
||||
self.selectedSimulationsLabel.setWordWrap(True)
|
||||
font = self.selectedSimulationsLabel.font()
|
||||
font.setWeight(QtGui.QFont.Bold)
|
||||
self.selectedSimulationsLabel.setFont(font)
|
||||
|
||||
scrolledLabel = QtGui.QScrollArea()
|
||||
scrolledLabel.setWidget(self.selectedSimulationsLabel)
|
||||
scrolledLabel.setWidgetResizable(True)
|
||||
layout.addWidget(scrolledLabel)
|
||||
|
||||
self.manySimulationsPanel.setLayout(self.createButtonedLayout(layout, False))
|
||||
|
||||
def createSingleSelectionsPanel(self):
|
||||
"""The panel for a single selected job"""
|
||||
self.singleSimulationsPanel = QtGui.QWidget()
|
||||
|
||||
layout = QtGui.QFormLayout()
|
||||
layout.setLabelAlignment(QtCore.Qt.AlignRight)
|
||||
self.jobLabel = QtGui.QLabel()
|
||||
self.submitLabel = QtGui.QLabel()
|
||||
self.startLabel = QtGui.QLabel()
|
||||
self.finishLabel = QtGui.QLabel()
|
||||
self.waitingLabel = QtGui.QLabel()
|
||||
self.runningLabel = QtGui.QLabel()
|
||||
self.stateLabel = QtGui.QLabel()
|
||||
|
||||
layout.addRow("Job #:", self.jobLabel)
|
||||
layout.addRow("Submitted:", self.submitLabel)
|
||||
layout.addRow("Started:", self.startLabel)
|
||||
layout.addRow("Finished:", self.finishLabel)
|
||||
layout.addRow("Waiting:", self.runningLabel)
|
||||
layout.addRow("Running:", self.waitingLabel)
|
||||
layout.addRow("State:", self.stateLabel)
|
||||
|
||||
self.singleSimulationsPanel.setLayout(self.createButtonedLayout(layout))
|
||||
|
||||
|
||||
def createNoSelectionsPanel(self):
|
||||
"""The panel for no selected jobs. Enables pausing and killing the entire simulation"""
|
||||
self.noSimulationsPanel = QtGui.QWidget()
|
||||
|
||||
layout = QtGui.QVBoxLayout()
|
||||
label = QtGui.QLabel("Pause queue after currently running jobs are finished:")
|
||||
label.setWordWrap(True)
|
||||
layout.addWidget(label)
|
||||
|
||||
self.pauseButton = QtGui.QToolButton(self)
|
||||
self.pauseButton.setIcon(resourceIcon("pause"))
|
||||
self.pauseButton.setCheckable(True)
|
||||
self.connect(self.pauseButton, QtCore.SIGNAL('clicked()'), lambda : self.ctrl.pause(self.pauseButton.isChecked()))
|
||||
|
||||
|
||||
buttonLayout = QtGui.QHBoxLayout()
|
||||
buttonLayout.addStretch(1)
|
||||
buttonLayout.addWidget(self.pauseButton)
|
||||
buttonLayout.addStretch(1)
|
||||
layout.addLayout(buttonLayout)
|
||||
|
||||
label = QtGui.QLabel("Remove all jobs from the queue:")
|
||||
label.setWordWrap(True)
|
||||
layout.addWidget(label)
|
||||
|
||||
self.killAllButton = QtGui.QToolButton(self)
|
||||
self.killAllButton.setIcon(resourceIcon("cancel"))
|
||||
self.connect(self.killAllButton, QtCore.SIGNAL('clicked()'), self.ctrl.killAll)
|
||||
|
||||
buttonLayout = QtGui.QHBoxLayout()
|
||||
buttonLayout.addStretch(1)
|
||||
buttonLayout.addWidget(self.killAllButton)
|
||||
buttonLayout.addStretch(1)
|
||||
|
||||
layout.addLayout(buttonLayout)
|
||||
|
||||
self.noSimulationsPanel.setLayout(layout)
|
||||
|
||||
|
||||
|
||||
def setSimulations(self, selection=None):
|
||||
"""Set the list of selected jobs"""
|
||||
if selection is None: selection = []
|
||||
self.ctrl.setSimulations(selection)
|
||||
|
||||
# def markText(self, a, b):
|
||||
# if b.isRunning():
|
||||
# c = SimulationItemDelegate.running
|
||||
# elif b.isWaiting():
|
||||
# c = SimulationItemDelegate.waiting
|
||||
# else:
|
||||
# c = QtGui.QColor(255, 255, 255, 0)
|
||||
#
|
||||
# color = "rgb(%d, %d, %d)" % (c.red(), c.green(), c.blue())
|
||||
#
|
||||
# b = "<span style='background: " + color + ";'>" + str(b) + "</span>"
|
||||
#
|
||||
# if not a == "":
|
||||
# return a + " " + b
|
||||
# else:
|
||||
# return b
|
||||
|
||||
def setModel(self, ert):
|
||||
"""Set the reference to ERT (ertwrapper instance)"""
|
||||
self.ctrl.setModel(ert)
|
||||
|
||||
def setSimulationStatistics(self, statistics):
|
||||
"""Set the associated simulation statistics"""
|
||||
self.ctrl.setSimulationStatistics(statistics)
|
||||
|
||||
|
||||
class SimulationPanelController:
|
||||
"""Controller code for the simulation panel"""
|
||||
def __init__(self, view):
|
||||
self.view = view
|
||||
self.initialized = False
|
||||
self.selectedSimulations = []
|
||||
self.view.connect(self.view, QtCore.SIGNAL('simulationsUpdated()'), self.showSelectedSimulations)
|
||||
|
||||
def initialize(self, ert):
|
||||
"""Set prototypes for ERT"""
|
||||
if not self.initialized:
|
||||
ert.prototype("bool job_queue_get_pause(long)", lib = ert.job_queue)
|
||||
ert.prototype("void job_queue_set_pause_on(long)", lib = ert.job_queue)
|
||||
ert.prototype("void job_queue_set_pause_off(long)", lib = ert.job_queue)
|
||||
ert.prototype("void job_queue_user_exit(long)", lib = ert.job_queue)
|
||||
ert.prototype("long enkf_main_iget_state(long, int)")
|
||||
ert.prototype("void enkf_state_kill_simulation(long)")
|
||||
ert.prototype("void enkf_state_resubmit_simulation(long, int)")
|
||||
ert.prototype("int enkf_state_get_run_status(long)")
|
||||
ert.prototype("long site_config_get_job_queue(long)")
|
||||
self.initialized = True
|
||||
|
||||
def setModel(self, ert):
|
||||
"""Set the reference to ERT (ertwrapper instance)"""
|
||||
self.initialize(ert)
|
||||
self.ert = ert
|
||||
|
||||
def kill(self):
|
||||
"""Kills the selected simulations."""
|
||||
for simulation in self.selectedSimulations:
|
||||
state = self.ert.enkf.enkf_main_iget_state(self.ert.main, simulation.name)
|
||||
status = self.ert.enkf.enkf_state_get_run_status(state)
|
||||
|
||||
#if status == Simulation.RUNNING:
|
||||
self.ert.enkf.enkf_state_kill_simulation(state)
|
||||
|
||||
def restart(self, resample):
|
||||
"""Restarts the selected simulations. May also resample."""
|
||||
for simulation in self.selectedSimulations:
|
||||
state = self.ert.enkf.enkf_main_iget_state(self.ert.main, simulation.name)
|
||||
status = self.ert.enkf.enkf_state_get_run_status(state)
|
||||
|
||||
#if status == Simulation.USER_KILLED:
|
||||
self.ert.enkf.enkf_state_resubmit_simulation(state , resample)
|
||||
|
||||
def pause(self, pause):
|
||||
"""Pause the job queue after the currently running jobs are finished."""
|
||||
job_queue = self.ert.enkf.site_config_get_job_queue(self.ert.site_config)
|
||||
|
||||
if pause:
|
||||
self.statistics.stop()
|
||||
self.ert.job_queue.job_queue_set_pause_on(job_queue)
|
||||
else:
|
||||
self.statistics.startTiming()
|
||||
self.ert.job_queue.job_queue_set_pause_off(job_queue)
|
||||
|
||||
def killAll(self):
|
||||
"""Kills all simulations"""
|
||||
killAll = QtGui.QMessageBox.question(self.view, "Remove all jobs?", "Are you sure you want to remove all jobs from the queue?", QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
|
||||
|
||||
if killAll == QtGui.QMessageBox.Yes:
|
||||
job_queue = self.ert.enkf.site_config_get_job_queue(self.ert.site_config)
|
||||
self.ert.job_queue.job_queue_user_exit(job_queue)
|
||||
|
||||
def showSelectedSimulations(self):
|
||||
"""Update information relating to a single job"""
|
||||
if len(self.selectedSimulations) >= 2:
|
||||
members = reduce(lambda a, b: str(a) + " " + str(b), sorted(self.selectedSimulations))
|
||||
self.view.selectedSimulationsLabel.setText(members)
|
||||
elif len(self.selectedSimulations) == 1:
|
||||
sim = self.selectedSimulations[0]
|
||||
self.view.jobLabel.setText(str(sim.name))
|
||||
self.view.submitLabel.setText(shortTime(sim.submitTime))
|
||||
self.view.startLabel.setText(shortTime(sim.startTime))
|
||||
self.view.finishLabel.setText(shortTime(sim.finishedTime))
|
||||
|
||||
if sim.startTime == -1:
|
||||
runningTime = "-"
|
||||
elif sim.finishedTime > -1:
|
||||
runningTime = sim.finishedTime - sim.startTime
|
||||
else:
|
||||
runningTime = int(time.time()) - sim.startTime
|
||||
|
||||
|
||||
if sim.submitTime == -1:
|
||||
waitingTime = "-"
|
||||
elif sim.startTime > -1:
|
||||
waitingTime = sim.startTime - sim.submitTime
|
||||
else:
|
||||
waitingTime = int(time.time()) - sim.submitTime
|
||||
|
||||
self.view.runningLabel.setText(str(waitingTime) + " secs")
|
||||
self.view.waitingLabel.setText(str(runningTime) + " secs")
|
||||
|
||||
status = sim.status.name[10:]
|
||||
self.view.stateLabel.setText(status)
|
||||
|
||||
|
||||
def setSimulations(self, selection=None):
|
||||
"""Change the view according to the selection. No, single or multiple jobs."""
|
||||
if selection is None: selection = []
|
||||
self.selectedSimulations = selection
|
||||
|
||||
if len(selection) >= 2:
|
||||
self.view.setCurrentWidget(self.view.manySimulationsPanel)
|
||||
elif len(selection) == 1:
|
||||
self.view.setCurrentWidget(self.view.singleSimulationsPanel)
|
||||
else:
|
||||
self.view.setCurrentWidget(self.view.noSimulationsPanel)
|
||||
|
||||
self.showSelectedSimulations()
|
||||
|
||||
def setSimulationStatistics(self, statistics):
|
||||
"""Set the associated statistics"""
|
||||
self.statistics = statistics
|
||||
|
||||
|
||||
class Simulation:
|
||||
"""Container for state information for a single simulation."""
|
||||
|
||||
def __init__(self, name, statistics=None):
|
||||
self.name = name
|
||||
self.status = ert_job_status_type.NOT_ACTIVE
|
||||
self.statuslog = []
|
||||
self.statistics = statistics
|
||||
|
||||
self.resetTime()
|
||||
|
||||
def checkStatus(self, type):
|
||||
"""Check the internal status against an ERT enum"""
|
||||
return self.status == type
|
||||
|
||||
def isWaiting(self):
|
||||
"""Is the job waiting?"""
|
||||
return self.checkStatus(ert_job_status_type.WAITING) or self.checkStatus(ert_job_status_type.SUBMITTED)
|
||||
|
||||
def isPending(self):
|
||||
"""Is the job PENDING in the LSF queue?"""
|
||||
return self.checkStatus(ert_job_status_type.PENDING)
|
||||
|
||||
def isRunning(self):
|
||||
"""Is the job running?"""
|
||||
return self.checkStatus(ert_job_status_type.RUNNING)
|
||||
|
||||
def hasFailed(self):
|
||||
"""Has the job failed?"""
|
||||
return self.checkStatus(ert_job_status_type.ALL_FAIL)
|
||||
|
||||
def notActive(self):
|
||||
"""Is the job active?"""
|
||||
return self.checkStatus(ert_job_status_type.NOT_ACTIVE)
|
||||
|
||||
def finishedSuccessfully(self):
|
||||
"""Has the job finished?"""
|
||||
return self.checkStatus(ert_job_status_type.ALL_OK)
|
||||
|
||||
def isUserKilled(self):
|
||||
"""Has the job been killed by the user?"""
|
||||
return self.checkStatus(ert_job_status_type.USER_KILLED) or self.checkStatus(ert_job_status_type.USER_EXIT)
|
||||
|
||||
|
||||
def setStatus(self, status):
|
||||
"""Update the status of this job"""
|
||||
if len(self.statuslog) == 0 or not self.statuslog[len(self.statuslog) - 1] == status:
|
||||
self.statuslog.append(status)
|
||||
|
||||
if status == ert_job_status_type.ALL_OK:
|
||||
self.setFinishedTime(int(time.time()))
|
||||
|
||||
self.status = status
|
||||
|
||||
def setStartTime(self, secs):
|
||||
"""Set the time the job started"""
|
||||
self.startTime = secs
|
||||
|
||||
def setSubmitTime(self, secs):
|
||||
"""Set the time the job was submitted to LSF"""
|
||||
self.submitTime = secs
|
||||
if self.submitTime > self.finishedTime:
|
||||
self.finishedTime = -1
|
||||
|
||||
def setFinishedTime(self, secs):
|
||||
"""Set the time the job finished"""
|
||||
self.finishedTime = secs
|
||||
|
||||
if not self.statistics is None:
|
||||
self.statistics.addTime(self.submitTime, self.startTime, self.finishedTime)
|
||||
|
||||
def printTime(self, secs):
|
||||
if not secs == -1:
|
||||
print time.localtime(secs)
|
||||
|
||||
def resetTime(self):
|
||||
"""Reset job timing"""
|
||||
self.startTime = -1
|
||||
self.submitTime = -1
|
||||
self.finishedTime = -1
|
||||
|
||||
def __str__(self):
|
||||
return str(self.name)
|
||||
|
||||
def __ge__(self, other):
|
||||
return self.name >= other.name
|
||||
|
||||
def __lt__(self, other):
|
||||
return not self >= other
|
||||
|
||||
|
||||
class SimulationStatistics:
|
||||
"""A class that tracks statistics for Simulations (running time, waiting time, estimates, etc...)"""
|
||||
|
||||
|
||||
def __init__(self, name="default"):
|
||||
"""Create a new tracking object"""
|
||||
self.name = name
|
||||
self.clear()
|
||||
self.old_job_count = 0
|
||||
self.old_duration = 0
|
||||
|
||||
def clear(self):
|
||||
"""Reset all values and stop estimate calculation"""
|
||||
self.jobs = 0
|
||||
self.waiting = 0
|
||||
self.running = 0
|
||||
self.total = 0
|
||||
self.start = 0
|
||||
self.last = 0
|
||||
|
||||
self.stopped = True
|
||||
|
||||
def startTiming(self):
|
||||
"""Starts estimate calculation"""
|
||||
self.stopped = False
|
||||
self.start = int(time.time())
|
||||
|
||||
def jobsPerSecond(self):
|
||||
"""Returns the number of jobs per second as a float"""
|
||||
#t = int(time.time()) - self.start
|
||||
t = self.last - self.start
|
||||
if t > 0:
|
||||
return self.jobs / t
|
||||
else:
|
||||
return 0
|
||||
|
||||
def averageRunningTime(self):
|
||||
"""Calculates the average running time"""
|
||||
return self.running / self.jobs
|
||||
|
||||
def secondsPerJob(self):
|
||||
"""Returns how long a job takes in seconds"""
|
||||
return 1.0 / self.jobsPerSecond()
|
||||
|
||||
def averageConcurrentJobs(self):
|
||||
"""Returns the average number of jobs performed in parallel"""
|
||||
return max(self.running / (self.last - self.start), 1)
|
||||
|
||||
def estimate(self, jobs):
|
||||
"""Returns an estimate on how long the rest of the job will take. Jobs = the total number of jobs"""
|
||||
if self.jobsPerSecond() > 0:
|
||||
avg_concurrent_jobs = self.averageConcurrentJobs()
|
||||
avg_running = self.averageRunningTime()
|
||||
|
||||
jobs_left = jobs - self.jobs
|
||||
est_remaining_running = avg_running * (jobs_left) / avg_concurrent_jobs
|
||||
timeUsed = int(time.time()) - self.last
|
||||
return est_remaining_running - timeUsed
|
||||
else:
|
||||
return -1
|
||||
|
||||
|
||||
def addTime(self, submit, start, finish):
|
||||
"""Add new statistical data to the tracker"""
|
||||
if not self.stopped:
|
||||
self.jobs += 1
|
||||
self.waiting += start - submit
|
||||
self.running += finish - start
|
||||
self.total += finish - submit
|
||||
self.last = int(time.time())
|
||||
|
||||
def stop(self):
|
||||
"""Pause the tracker. Estimate data will be reset"""
|
||||
self.old_job_count += self.jobs
|
||||
self.old_duration += int(time.time()) - self.start
|
||||
self.clear()
|
||||
|
||||
@@ -1,266 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'simulationsdialog.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from ert_gui.widgets.cogwheel import Cogwheel
|
||||
from legend import Legend
|
||||
from simulation import SimulationItemDelegate, SimulationList, SimulationItem, Simulation, SimulationPanel, SimulationStatistics
|
||||
|
||||
import threading
|
||||
import time
|
||||
from ert_gui.widgets.util import getItemsFromList
|
||||
from ert.ert.enums import ert_job_status_type
|
||||
from PyQt4.QtGui import QApplication
|
||||
|
||||
class SimulationsDialog(QtGui.QDialog):
|
||||
"""A dialog that shows the progress of a simulation"""
|
||||
def __init__(self, parent=None):
|
||||
QtGui.QDialog.__init__(self, parent)
|
||||
self.setModal(True)
|
||||
self.setWindowTitle("Running jobs")
|
||||
self.setMinimumWidth(250)
|
||||
#self.setMinimumHeight(250)
|
||||
|
||||
self.ctrl = SimulationsDialogController(self)
|
||||
|
||||
self.simulationProgress = QtGui.QProgressBar()
|
||||
self.simulationProgress.setValue(0)
|
||||
self.connect(self.simulationProgress, QtCore.SIGNAL('setValue(int)'), self.updateProgress)
|
||||
|
||||
self.cogwheel = Cogwheel(size=20)
|
||||
|
||||
memberLayout = QtGui.QVBoxLayout()
|
||||
|
||||
progressLayout = QtGui.QHBoxLayout()
|
||||
progressLayout.addWidget(self.simulationProgress)
|
||||
progressLayout.addWidget(self.cogwheel)
|
||||
memberLayout.addLayout(progressLayout)
|
||||
|
||||
|
||||
simulationLayout = QtGui.QHBoxLayout()
|
||||
self.simulationList = SimulationList()
|
||||
self.simulationList.contextMenuEvent = self._contextMenu
|
||||
self.connect(self.simulationList, QtCore.SIGNAL('itemSelectionChanged()'), self.ctrl.selectSimulation)
|
||||
simulationLayout.addWidget(self.simulationList)
|
||||
self.simulationPanel = SimulationPanel()
|
||||
simulationLayout.addWidget(self.simulationPanel)
|
||||
memberLayout.addLayout(simulationLayout)
|
||||
|
||||
legendLayout = QtGui.QHBoxLayout()
|
||||
legendLayout.addLayout(Legend("Not active", SimulationItemDelegate.notactive))
|
||||
legendLayout.addLayout(Legend("Waiting", SimulationItemDelegate.waiting))
|
||||
legendLayout.addLayout(Legend("Pending", SimulationItemDelegate.pending))
|
||||
legendLayout.addLayout(Legend("Running", SimulationItemDelegate.running))
|
||||
legendLayout.addLayout(Legend("User killed", SimulationItemDelegate.userkilled))
|
||||
legendLayout.addLayout(Legend("Failed", SimulationItemDelegate.failed))
|
||||
legendLayout.addLayout(Legend("Finished", SimulationItemDelegate.finished))
|
||||
memberLayout.addLayout(legendLayout)
|
||||
|
||||
|
||||
self.doneButton = QtGui.QPushButton("Done", self)
|
||||
self.connect(self.doneButton, QtCore.SIGNAL('clicked()'), self.accept)
|
||||
|
||||
buttonLayout = QtGui.QHBoxLayout()
|
||||
|
||||
self.estimateLabel = QtGui.QLabel()
|
||||
buttonLayout.addWidget(self.estimateLabel)
|
||||
buttonLayout.addStretch(1)
|
||||
buttonLayout.addWidget(self.doneButton)
|
||||
|
||||
memberLayout.addSpacing(10)
|
||||
memberLayout.addLayout(buttonLayout)
|
||||
|
||||
self.setLayout(memberLayout)
|
||||
|
||||
|
||||
def _createAction(self, name, func, parent=None):
|
||||
"""Create an action for the right click menu"""
|
||||
action = QtGui.QAction(name, parent)
|
||||
action.connect(action, QtCore.SIGNAL("triggered()"), func)
|
||||
return action
|
||||
|
||||
def _contextMenu(self, event):
|
||||
"""Create a right click menu for the simulation view."""
|
||||
menu = QtGui.QMenu(self.simulationList)
|
||||
selectAll = self._createAction("Select all", self.simulationList.selectAll)
|
||||
unselectAll = self._createAction("Unselect all", self.simulationList.clearSelection)
|
||||
selectRunning = self._createAction("Select all running", lambda : self.ctrl.select(ert_job_status_type.RUNNING))
|
||||
selectFailed = self._createAction("Select all failed", lambda : self.ctrl.select(ert_job_status_type.ALL_FAIL))
|
||||
selectUserKilled = self._createAction("Select all user killed", lambda : self.ctrl.select(ert_job_status_type.USER_KILLED))
|
||||
selectWaiting = self._createAction("Select all waiting", lambda : self.ctrl.select(ert_job_status_type.WAITING, ert_job_status_type.PENDING))
|
||||
|
||||
menu.addAction(selectAll)
|
||||
menu.addAction(unselectAll)
|
||||
menu.addAction(selectWaiting)
|
||||
menu.addAction(selectRunning)
|
||||
menu.addAction(selectFailed)
|
||||
menu.addAction(selectUserKilled)
|
||||
menu.exec_(event.globalPos())
|
||||
|
||||
|
||||
def closeEvent(self, event):
|
||||
"""Ignore clicking of the x in the top right corner"""
|
||||
event.ignore()
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
"""Ignore ESC keystrokes"""
|
||||
if not event.key() == QtCore.Qt.Key_Escape:
|
||||
QtGui.QDialog.keyPressEvent(self, event)
|
||||
|
||||
def updateProgress(self, value):
|
||||
"""Update the progress bar"""
|
||||
self.simulationProgress.setValue(value)
|
||||
|
||||
def setRunningState(self, state):
|
||||
"""Set wether the cogwheel should spin and the Done button is enabled"""
|
||||
self.cogwheel.setRunning(state)
|
||||
self.doneButton.setEnabled(not state)
|
||||
|
||||
def start(self, **kwargs):
|
||||
"""Show the dialog and start the simulation"""
|
||||
self.open()
|
||||
self.ctrl.start(**kwargs)
|
||||
self.exec_()
|
||||
|
||||
|
||||
class SimulationsDialogController:
|
||||
"""All controller code for the dialog"""
|
||||
def __init__(self, view):
|
||||
self.view = view
|
||||
self.initialized = False
|
||||
|
||||
def select(self, *states):
|
||||
"""Used by the right click menu to select multiple running jobs"""
|
||||
self.view.simulationList.clearSelection()
|
||||
|
||||
items = getItemsFromList(self.view.simulationList, lambda item : item, selected=False)
|
||||
|
||||
for state in states:
|
||||
for item in items:
|
||||
if item.simulation.checkStatus(state):
|
||||
item.setSelected(True)
|
||||
|
||||
def selectSimulation(self):
|
||||
"""Set a job as selected"""
|
||||
selection = getItemsFromList(self.view.simulationList, lambda item : item.simulation)
|
||||
self.view.simulationPanel.setSimulations(selection)
|
||||
|
||||
|
||||
def initialize(self, ert):
|
||||
"""Protoype ERT functions"""
|
||||
if not self.initialized:
|
||||
ert.prototype("long enkf_main_iget_state(long, int)")
|
||||
ert.prototype("int enkf_state_get_run_status(long)")
|
||||
ert.prototype("long site_config_queue_is_running(long)")
|
||||
ert.prototype("long enkf_state_get_start_time(long)")
|
||||
ert.prototype("long enkf_state_get_submit_time(long)")
|
||||
self.initialized = True
|
||||
|
||||
def start(self, **kwargs):
|
||||
"""Start the simulation. Two threads are started one for the simulation and one for progress monitoring"""
|
||||
ert = kwargs["ert"]
|
||||
memberCount = kwargs["memberCount"]
|
||||
selectedMembers = kwargs["selectedMembers"]
|
||||
mode = kwargs["mode"]
|
||||
init_step_parameter = kwargs["init_step_parameter"]
|
||||
simFrom = kwargs["simFrom"]
|
||||
simTo = kwargs["simTo"]
|
||||
state = kwargs["state"]
|
||||
|
||||
|
||||
self.initialize(ert)
|
||||
self.view.simulationPanel.setModel(ert)
|
||||
|
||||
self.statistics = SimulationStatistics()
|
||||
self.view.simulationPanel.setSimulationStatistics(self.statistics)
|
||||
simulations = {}
|
||||
for member in selectedMembers:
|
||||
simulations[member] = SimulationItem(Simulation(member, self.statistics))
|
||||
self.view.simulationList.addItem(simulations[member])
|
||||
|
||||
|
||||
self.runthread = threading.Thread(name="enkf_main_run")
|
||||
def run():
|
||||
self.view.setRunningState(True)
|
||||
boolVector = ert.createBoolVector(memberCount, selectedMembers)
|
||||
boolPtr = ert.getBoolVectorPtr(boolVector)
|
||||
|
||||
ert.enkf.enkf_main_run(ert.main, mode, boolPtr, init_step_parameter, simFrom, state)
|
||||
ert.freeBoolVector(boolVector)
|
||||
self.view.setRunningState(False)
|
||||
|
||||
self.runthread.setDaemon(True)
|
||||
self.runthread.run = run
|
||||
|
||||
|
||||
self.pollthread = threading.Thread(name="polling_thread")
|
||||
def poll():
|
||||
while not ert.enkf.site_config_queue_is_running(ert.site_config):
|
||||
time.sleep(0.5)
|
||||
|
||||
job_start_time = int(time.time())
|
||||
|
||||
while(self.runthread.isAlive()):
|
||||
for member in selectedMembers:
|
||||
state = ert.enkf.enkf_main_iget_state( ert.main , member)
|
||||
status = ert.enkf.enkf_state_get_run_status( state )
|
||||
|
||||
simulations[member].simulation.setStatus(ert_job_status_type.resolveValue(status))
|
||||
|
||||
if not ert_job_status_type.NOT_ACTIVE == status:
|
||||
start_time = ert.enkf.enkf_state_get_start_time(state)
|
||||
submit_time = ert.enkf.enkf_state_get_submit_time(state)
|
||||
|
||||
simulations[member].simulation.setStartTime(start_time)
|
||||
simulations[member].simulation.setSubmitTime(submit_time)
|
||||
|
||||
|
||||
totalCount = len(simulations.keys())
|
||||
succesCount = 0
|
||||
for key in simulations.keys():
|
||||
if simulations[key].simulation.finishedSuccessfully():
|
||||
succesCount+=1
|
||||
|
||||
count = (100 * succesCount / totalCount)
|
||||
self.view.simulationProgress.emit(QtCore.SIGNAL("setValue(int)"), count)
|
||||
self.view.simulationPanel.emit(QtCore.SIGNAL("simulationsUpdated()"))
|
||||
|
||||
qmi1 = self.view.simulationList.indexFromItem(simulations[0])
|
||||
qmi2 = self.view.simulationList.indexFromItem(simulations[len(simulations) - 1])
|
||||
self.view.simulationList.model().emit(QtCore.SIGNAL("dataChanged(QModelIndex, QModelIndex)"), qmi1, qmi2)
|
||||
|
||||
|
||||
if self.view.cogwheel.isRunning():
|
||||
job_running_time = int(time.time()) - job_start_time
|
||||
self.view.estimateLabel.setText("Total runnning time: %d seconds" % (job_running_time))
|
||||
# if self.statistics.jobsPerSecond() > 0:
|
||||
# #with assimilation the number of jobs must be multiplied by timesteps
|
||||
# self.view.estimateLabel.setText("Estimated finished in %d seconds" % (self.statistics.estimate(len(simulations))))
|
||||
# else:
|
||||
# self.view.estimateLabel.setText("")
|
||||
QApplication.processEvents()
|
||||
self.view.update()
|
||||
time.sleep(0.1)
|
||||
|
||||
self.pollthread.setDaemon(True)
|
||||
self.pollthread.run = poll
|
||||
|
||||
self.statistics.startTiming()
|
||||
self.runthread.start()
|
||||
self.pollthread.start()
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file '__init__.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'activelabel.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from helpedwidget import HelpedWidget
|
||||
|
||||
class ActiveLabel(HelpedWidget):
|
||||
"""Label shows a string. The data structure expected from the getter is a string."""
|
||||
|
||||
def __init__(self, parent=None, label="", help="", default_string=""):
|
||||
"""Construct a StringBox widget"""
|
||||
HelpedWidget.__init__(self, parent, label, help)
|
||||
|
||||
self.active_label = QtGui.QLabel()
|
||||
self.addWidget(self.active_label)
|
||||
|
||||
font = self.active_label.font()
|
||||
font.setWeight(QtGui.QFont.Bold)
|
||||
self.active_label.setFont(font)
|
||||
|
||||
#self.addHelpButton()
|
||||
|
||||
self.active_label.setText(default_string)
|
||||
|
||||
|
||||
def fetchContent(self):
|
||||
"""Retrieves data from the model and inserts it into the edit line"""
|
||||
self_get_from_model = self.getFromModel()
|
||||
if self_get_from_model is None:
|
||||
self_get_from_model = ""
|
||||
|
||||
self.active_label.setText(self_get_from_model)
|
||||
@@ -1,64 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'checkbox.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from helpedwidget import *
|
||||
|
||||
class CheckBox(HelpedWidget):
|
||||
"""A checbox widget for booleans. The data structure expected and sent to the getter and setter is a boolean."""
|
||||
|
||||
def __init__(self, parent=None, checkLabel="Do this", help="", altLabel="", defaultCheckState=True):
|
||||
"""Construct a checkbox widget for booleans"""
|
||||
HelpedWidget.__init__(self, parent, checkLabel, help)
|
||||
|
||||
if altLabel:
|
||||
self.check = QtGui.QCheckBox(altLabel, self)
|
||||
else:
|
||||
self.check = QtGui.QCheckBox(checkLabel, self)
|
||||
|
||||
self.check.setTristate(False)
|
||||
|
||||
if defaultCheckState:
|
||||
self.check.setCheckState(QtCore.Qt.Checked)
|
||||
else:
|
||||
self.check.setCheckState(QtCore.Qt.Unchecked)
|
||||
|
||||
|
||||
self.addWidget(self.check)
|
||||
|
||||
self.addStretch()
|
||||
self.addHelpButton()
|
||||
|
||||
#self.connect(self.spinner, QtCore.SIGNAL('valueChanged(int)'), self.updateContent)
|
||||
self.connect(self.check, QtCore.SIGNAL('stateChanged(int)'), self.contentsChanged)
|
||||
|
||||
|
||||
def contentsChanged(self):
|
||||
"""Called whenever the contents of the checbox changes."""
|
||||
if self.check.checkState() == QtCore.Qt.Checked:
|
||||
self.updateContent(True)
|
||||
else:
|
||||
self.updateContent(False)
|
||||
|
||||
|
||||
def fetchContent(self):
|
||||
"""Retrieves data from the model and inserts it into the checkbox"""
|
||||
if self.getFromModel():
|
||||
self.check.setCheckState(QtCore.Qt.Checked)
|
||||
else:
|
||||
self.check.setCheckState(QtCore.Qt.Unchecked)
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'cogwheel.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from util import frange
|
||||
import math
|
||||
|
||||
class Cogwheel(QtGui.QWidget):
|
||||
"""A rotating cogwheel that indicates that a process is running."""
|
||||
|
||||
def __init__(self, color=QtGui.QColor(128, 128, 128), size=64, parent = None):
|
||||
QtGui.QWidget.__init__(self, parent)
|
||||
|
||||
self.size = size
|
||||
qsize = QtCore.QSize(size, size)
|
||||
self.setMaximumSize(qsize)
|
||||
self.setMinimumSize(qsize)
|
||||
|
||||
self.color = color
|
||||
self.inc = 0
|
||||
self.step = 2.5
|
||||
|
||||
self._createCogwheel(size)
|
||||
|
||||
timer = QtCore.QTimer(self)
|
||||
self.connect(timer, QtCore.SIGNAL("timeout()"), self, QtCore.SLOT("update()"))
|
||||
timer.start(16)
|
||||
|
||||
self.running = False
|
||||
|
||||
|
||||
def paintEvent(self, paintevent):
|
||||
"""Called whenever the widget needs to redraw"""
|
||||
painter = QtGui.QPainter(self)
|
||||
painter.setRenderHint(QtGui.QPainter.Antialiasing)
|
||||
|
||||
rect = self.contentsRect()
|
||||
|
||||
painter.setPen(QtGui.QColor(255, 255, 255, 0))
|
||||
|
||||
painter.setClipRect(rect)
|
||||
painter.translate(rect.center())
|
||||
painter.rotate(self.step * self.inc)
|
||||
self._drawCogwheel(painter)
|
||||
|
||||
r = (self.size / 2.0) * 0.3
|
||||
painter.setBrush(QtGui.QBrush(self.color.light(150)))
|
||||
painter.drawEllipse(QtCore.QPointF(0, 0), r, r)
|
||||
|
||||
if self.running:
|
||||
self.inc += 1
|
||||
|
||||
|
||||
def _drawCogwheel(self, painter):
|
||||
"""Draw the cogwheel polygon"""
|
||||
painter.save()
|
||||
painter.setBrush(QtGui.QBrush(self.color))
|
||||
painter.drawPolygon(QtGui.QPolygonF(self.points), len(self.points))
|
||||
painter.restore()
|
||||
|
||||
|
||||
def _createCogwheel(self, size):
|
||||
"""Creates the points that are part of the cogwheel polygon"""
|
||||
self.points = []
|
||||
r1 = (size / 2.0) - 1.0
|
||||
r2 = 0.80
|
||||
teeth = 9
|
||||
out = False
|
||||
for t in frange(0.0, 2 * math.pi, 2 * math.pi / (teeth * 2.0)):
|
||||
x = r1 * math.cos(t)
|
||||
y = r1 * math.sin(t)
|
||||
if out:
|
||||
self.points.append(QtCore.QPointF(x, y))
|
||||
self.points.append(QtCore.QPointF(r2 * x, r2 * y))
|
||||
else:
|
||||
self.points.append(QtCore.QPointF(r2 * x, r2 * y))
|
||||
self.points.append(QtCore.QPointF(x, y))
|
||||
out = not out
|
||||
|
||||
def setRunning(self, bool):
|
||||
"""Set wether it should animat or not"""
|
||||
self.running = bool
|
||||
|
||||
def isRunning(self):
|
||||
return self.running
|
||||
@@ -1,67 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'combochoice.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from helpedwidget import *
|
||||
|
||||
class ComboChoice(HelpedWidget):
|
||||
"""
|
||||
A combo box widget for choices. The data structure expected and sent to the getter and setter is a string
|
||||
that is equal to one of the available ones.
|
||||
"""
|
||||
def __init__(self, parent=None, choiceList=None, comboLabel="Choice", help=""):
|
||||
"""Construct a ComboChoice widget"""
|
||||
HelpedWidget.__init__(self, parent, comboLabel, help)
|
||||
|
||||
self.combo = QtGui.QComboBox(self)
|
||||
|
||||
if choiceList is None:
|
||||
choiceList = ["No choices"]
|
||||
|
||||
for choice in choiceList:
|
||||
self.combo.addItem(str(choice))
|
||||
|
||||
self.addWidget(self.combo)
|
||||
self.addStretch()
|
||||
self.addHelpButton()
|
||||
|
||||
self.connect(self.combo, QtCore.SIGNAL('currentIndexChanged(QString)'), self.updateContent)
|
||||
|
||||
|
||||
def fetchContent(self):
|
||||
"""Retrieves data from the model and updates the combo box."""
|
||||
newValue = self.getFromModel()
|
||||
|
||||
indexSet = False
|
||||
for i in range(self.combo.count()):
|
||||
if str(self.combo.itemText(i)).lower() == str(newValue).lower():
|
||||
self.combo.setCurrentIndex(i)
|
||||
indexSet = True
|
||||
break
|
||||
|
||||
if not indexSet:
|
||||
raise AssertionError("ComboBox can not be set to: " + str(newValue))
|
||||
|
||||
def updateList(self, choiceList):
|
||||
"""Replace the list of choices with the specified items"""
|
||||
self.disconnect(self.combo, QtCore.SIGNAL('currentIndexChanged(QString)'), self.updateContent)
|
||||
|
||||
self.combo.clear()
|
||||
for choice in choiceList:
|
||||
self.combo.addItem(choice)
|
||||
|
||||
self.connect(self.combo, QtCore.SIGNAL('currentIndexChanged(QString)'), self.updateContent)
|
||||
@@ -1,80 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'configpanel.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from util import createSeparator
|
||||
|
||||
class ConfigPanel(QtGui.QTabWidget):
|
||||
"""Convenience class for a tabbed configuration panel"""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
"""Creates a config panel widget"""
|
||||
QtGui.QTabWidget.__init__(self, parent)
|
||||
self.layoutQueue = []
|
||||
|
||||
|
||||
def startPage(self, name):
|
||||
"""Starts a new page of the configuration panel"""
|
||||
self.pageName = name
|
||||
self.contentPage = QtGui.QWidget()
|
||||
self.formLayout = QtGui.QFormLayout()
|
||||
self.formLayout.setLabelAlignment(QtCore.Qt.AlignRight)
|
||||
|
||||
|
||||
def addRow(self, row, label=None):
|
||||
"""
|
||||
Add a new row on a configuration page. Returns the row widget.
|
||||
If the row does not have a getLabel() function the row spans both columns.
|
||||
"""
|
||||
if hasattr(row, "getLabel") and not row.getLabel() == "":
|
||||
self.formLayout.addRow(row.getLabel(), row)
|
||||
else:
|
||||
if label is None:
|
||||
self.formLayout.addRow(row)
|
||||
else:
|
||||
self.formLayout.addRow(label, row)
|
||||
|
||||
return row
|
||||
|
||||
def endPage(self):
|
||||
"""Indicate the end of a complete configuration page."""
|
||||
self.contentPage.setLayout(self.formLayout)
|
||||
self.addTab(self.contentPage, self.pageName)
|
||||
|
||||
self.contentPage = None
|
||||
self.formLayout = None
|
||||
self.pageName = None
|
||||
|
||||
def startGroup(self, groupTitle):
|
||||
"""Start a titled sub group on the page."""
|
||||
self.groupBox = QtGui.QGroupBox(groupTitle)
|
||||
self.layoutQueue.append(self.formLayout)
|
||||
self.formLayout = QtGui.QFormLayout()
|
||||
self.formLayout.setLabelAlignment(QtCore.Qt.AlignRight)
|
||||
|
||||
def endGroup(self):
|
||||
"""Finish the titled sub group"""
|
||||
self.groupBox.setLayout(self.formLayout)
|
||||
|
||||
self.formLayout = self.layoutQueue.pop()
|
||||
self.formLayout.addRow(self.groupBox)
|
||||
self.groupBox = None
|
||||
|
||||
def addSeparator(self):
|
||||
"""Adds a separator line to the panel."""
|
||||
|
||||
self.formLayout.addRow(createSeparator())
|
||||
@@ -1,67 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'help.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# The variable @help_prefix should be set to point to a directory
|
||||
# containing (directories) with html help files. In the current
|
||||
# implementation this variable is set from the gert_main.py script.
|
||||
help_prefix = None
|
||||
|
||||
|
||||
def getTemplate():
|
||||
path = help_prefix + "template.html"
|
||||
if os.path.exists(path) and os.path.isfile(path):
|
||||
f = open(path, 'r')
|
||||
template = f.read()
|
||||
f.close()
|
||||
return template
|
||||
else:
|
||||
return "<html>%s</html>"
|
||||
|
||||
|
||||
def resolveHelpLabel(label):
|
||||
"""
|
||||
Reads a HTML file from the help directory.
|
||||
The HTML must follow the specification allowed by QT here: http://doc.trolltech.com/4.6/richtext-html-subset.html
|
||||
"""
|
||||
|
||||
# This code can be used to find widgets with empty help labels
|
||||
# if label.strip() == "":
|
||||
# raise AssertionError("NOOOOOOOOOOOOOOOOOOOOO!!!!!!!!!!!!")
|
||||
|
||||
path = help_prefix + label + ".html"
|
||||
if os.path.exists(path) and os.path.isfile(path):
|
||||
f = open(path, 'r')
|
||||
help = f.read()
|
||||
f.close()
|
||||
return getTemplate() % help
|
||||
else:
|
||||
# This code automatically creates empty help files
|
||||
# sys.stderr.write("Missing help file: '%s'\n" % label)
|
||||
# if not label == "" and not label.find("/") == -1:
|
||||
# sys.stderr.write("Creating help file: '%s'\n" % label)
|
||||
# directory, filename = os.path.split(path)
|
||||
#
|
||||
# if not os.path.exists(directory):
|
||||
# os.makedirs(directory)
|
||||
#
|
||||
# file_object = open(path, "w")
|
||||
# file_object.write(label)
|
||||
# file_object.close()
|
||||
return ""
|
||||
@@ -1,307 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'helpedwidget.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
import help
|
||||
import sys
|
||||
from util import resourceIcon, resourceImage
|
||||
import inspect
|
||||
import ert.ert.enums as enums
|
||||
|
||||
def abstract():
|
||||
"""Abstract keyword that indicate an abstract function"""
|
||||
import inspect
|
||||
caller = inspect.getouterframes(inspect.currentframe())[1][3]
|
||||
raise NotImplementedError(caller + ' must be implemented in subclass')
|
||||
|
||||
class UpdateOperations(enums.enum):
|
||||
INSERT = None
|
||||
REMOVE = None
|
||||
UPDATE = None
|
||||
UpdateOperations.INSERT = UpdateOperations("Insert", 1)
|
||||
UpdateOperations.REMOVE = UpdateOperations("Remove", 2)
|
||||
UpdateOperations.UPDATE = UpdateOperations("Update", 3)
|
||||
|
||||
|
||||
class ContentModel:
|
||||
"""This class is a wrapper for communication between the model and the view."""
|
||||
contentModel = None
|
||||
signalManager = QtCore.QObject()
|
||||
observers = []
|
||||
|
||||
INSERT = UpdateOperations.INSERT
|
||||
REMOVE = UpdateOperations.REMOVE
|
||||
UPDATE = UpdateOperations.UPDATE
|
||||
|
||||
def __init__(self):
|
||||
"""Constructs a ContentModel. All inheritors are registered"""
|
||||
ContentModel.observers.append(self)
|
||||
|
||||
def initialize(self, model):
|
||||
"""Should be implemented by inheriting classes that wants to do some one time initialization before getting and setting."""
|
||||
abstract()
|
||||
|
||||
def getter(self, model):
|
||||
"""MUST be implemented to get data from a source. Should not be called directly."""
|
||||
abstract()
|
||||
|
||||
def setter(self, model, value):
|
||||
"""MUST be implemented to update the source with new data. Should not be called directly."""
|
||||
abstract()
|
||||
|
||||
def insert(self, model, value):
|
||||
"""Can be implemented to insert new data to the source. Should not be called directly."""
|
||||
abstract()
|
||||
|
||||
def remove(self, model, value):
|
||||
"""Can be implemented to remove data from the source. Should not be called directly."""
|
||||
abstract()
|
||||
|
||||
def fetchContent(self):
|
||||
"""MUST be implemented. This function is called to tell all inheriting classes to retrieve data from the model. """
|
||||
abstract()
|
||||
|
||||
def getFromModel(self):
|
||||
"""Retrieves the data from the model. Calls the getter function with an appropriate model."""
|
||||
gargs = inspect.getargspec(self.getter)
|
||||
|
||||
if inspect.isfunction(self.getter) and "self" in gargs[0]:
|
||||
data = self.getter.__call__(self, ContentModel.contentModel)
|
||||
else:
|
||||
data = self.getter(ContentModel.contentModel)
|
||||
|
||||
return data
|
||||
|
||||
def updateContent(self, value, operation = UPDATE):
|
||||
"""
|
||||
Sends updated data to the model.
|
||||
Calls the a function with an appropriate model.
|
||||
The function is one of INSERT, REMOVE, UPDATE which corresponds to insert, remove and setter
|
||||
Any value returned by insert, remove or setter is also returned to the caller of this function
|
||||
|
||||
Emits a SIGNAL 'contentsChanged()' after the function has been called.
|
||||
Emits a SIGNAL 'contentsChanged(int)' after the function has been called, where int is the operation performed.
|
||||
"""
|
||||
if not ContentModel.contentModel is None :
|
||||
if ContentModel.INSERT == operation:
|
||||
result = self.insert(ContentModel.contentModel, value)
|
||||
elif ContentModel.REMOVE == operation:
|
||||
result = self.remove(ContentModel.contentModel, value)
|
||||
elif ContentModel.UPDATE == operation:
|
||||
result = self.setter(ContentModel.contentModel, value)
|
||||
else:
|
||||
sys.stderr.write("Unknown operation: %d\n" % (operation))
|
||||
return
|
||||
|
||||
self.emit(QtCore.SIGNAL('contentsChanged()'))
|
||||
self.emit(QtCore.SIGNAL('contentsChanged(int)'), operation)
|
||||
|
||||
return result
|
||||
|
||||
def getModel(self):
|
||||
"""Returns the contentModel associated with this session"""
|
||||
return ContentModel.contentModel
|
||||
|
||||
# The modelConnect, modelDisconnect and modelEmit uses Qt signal handling to enable communication between
|
||||
# separate parts of the model that needs to know about changes.
|
||||
@classmethod
|
||||
def modelConnect(cls, signal, callable):
|
||||
"""Connect to a custom signal available to all ContentModel objects."""
|
||||
QtCore.QObject.connect(ContentModel.signalManager, QtCore.SIGNAL(signal), callable)
|
||||
|
||||
@classmethod
|
||||
def modelDisconnect(cls, signal, callable):
|
||||
"""Disconnect from a custom signal available to all ContentModel objects."""
|
||||
QtCore.QObject.disconnect(ContentModel.signalManager, QtCore.SIGNAL(signal), callable)
|
||||
|
||||
@classmethod
|
||||
def modelEmit(cls, signal, *args):
|
||||
"""Emit a custom signal available to all ContentModel objects."""
|
||||
ContentModel.signalManager.emit(QtCore.SIGNAL(signal), *args)
|
||||
|
||||
@classmethod
|
||||
def updateObservers(cls):
|
||||
"""
|
||||
Calls all ContentModel inheritors to initialize (if implemented) and perform initial fetch of data.
|
||||
The signal 'initialized()' is emitted after initialization and fetching is completed.
|
||||
"""
|
||||
for o in ContentModel.observers:
|
||||
try:
|
||||
o.initialize(ContentModel.contentModel)
|
||||
except NotImplementedError:
|
||||
sys.stderr.write("Missing initializer: " + o.helpLabel + "\n")
|
||||
except Exception:
|
||||
sys.stderr.write("Caught an exception during initialization!\n")
|
||||
|
||||
#try:
|
||||
o.fetchContent()
|
||||
#except Exception:
|
||||
# sys.stderr.write("Caught an exception while fetching!\n")
|
||||
|
||||
ContentModel.modelEmit('initialized()')
|
||||
|
||||
@classmethod
|
||||
def printObservers(cls):
|
||||
"""Convenience method for printing the registered inheritors."""
|
||||
for o in ContentModel.observers:
|
||||
print o
|
||||
|
||||
@classmethod
|
||||
def emptyInitializer(cls, model):
|
||||
"""An empty initializer. Provided for convenience."""
|
||||
pass
|
||||
|
||||
class ContentModelProxy:
|
||||
"""
|
||||
A ContentModelProxy adds an apply mode to a ContentModel
|
||||
The proxy sits between the widget and the updateContent function call
|
||||
and delays the updateContent call until the apply function of the proxy is called.
|
||||
It only relays the last updateContent call (for a single instance) so it should only
|
||||
be used in situations when this is the desired behaviour.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.objectFunctions = {}
|
||||
self.objectContent = {}
|
||||
|
||||
def proxifyObject(self, object):
|
||||
"""
|
||||
This function is here because lambdas loose context in loops.
|
||||
Lambdas point to the variable and not the content.
|
||||
"""
|
||||
self.objectFunctions[object] = object.updateContent
|
||||
object.updateContent = lambda value, operation = ContentModel.UPDATE : self._proxyUpdateContent(object, value,
|
||||
operation)
|
||||
|
||||
def proxify(self, *objects):
|
||||
"""Add a ContenModel instance to this proxy group"""
|
||||
for object in objects:
|
||||
self.proxifyObject(object)
|
||||
|
||||
def _proxyUpdateContent(self, object, value, operation):
|
||||
self.objectContent[object] = (value, operation)
|
||||
|
||||
def apply(self):
|
||||
"""Perform all delayed updateContent calls"""
|
||||
for key in self.objectFunctions.keys():
|
||||
function = self.objectFunctions[key]
|
||||
if self.objectContent.has_key(key):
|
||||
data = self.objectContent[key]
|
||||
function(data[0], data[1])
|
||||
else:
|
||||
#This usually means that no value has been sent to the setter
|
||||
#print "Unknown key: %s" % (str(key))
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class HelpedWidget(QtGui.QWidget, ContentModel):
|
||||
"""
|
||||
HelpedWidget is a class that enables embedded help messages in widgets.
|
||||
The help button must manually be added to the containing layout with addHelpButton().
|
||||
"""
|
||||
|
||||
STRONG_ERROR_COLOR = QtGui.QColor(255, 215, 215)
|
||||
ERROR_COLOR = QtGui.QColor(255, 235, 235)
|
||||
INVALID_COLOR = QtGui.QColor(235, 235, 255)
|
||||
|
||||
WARNING = "warning"
|
||||
EXCLAMATION = "exclamation"
|
||||
|
||||
def __init__(self, parent=None, widgetLabel="", helpLabel=""):
|
||||
"""Creates a widget that can have a help button"""
|
||||
QtGui.QWidget.__init__(self, parent)
|
||||
ContentModel.__init__(self)
|
||||
|
||||
|
||||
self.validationLabel = QtGui.QLabel()
|
||||
self.validationLabel.setMaximumSize(QtCore.QSize(16, 16))
|
||||
self.validationLabel.setPixmap(resourceImage("warning"))
|
||||
self.validationLabel.setHidden(True)
|
||||
|
||||
if not widgetLabel == "":
|
||||
self.label = widgetLabel + ":"
|
||||
else:
|
||||
self.label = ""
|
||||
|
||||
self.helpMessage = help.resolveHelpLabel(helpLabel)
|
||||
self.helpLabel = helpLabel
|
||||
|
||||
self.widgetLayout = QtGui.QHBoxLayout()
|
||||
#self.setStyleSheet("padding: 2px")
|
||||
self.widgetLayout.setMargin(0)
|
||||
self.widgetLayout.addWidget(self.validationLabel)
|
||||
self.setLayout(self.widgetLayout)
|
||||
|
||||
|
||||
def getHelpButton(self):
|
||||
"""Returns the help button or None"""
|
||||
try:
|
||||
self.helpButton
|
||||
except AttributeError:
|
||||
self.helpButton = None
|
||||
|
||||
return self.helpButton
|
||||
|
||||
def showHelp(self):
|
||||
"""Pops up the tooltip associated to the button"""
|
||||
QtGui.QToolTip.showText(QtGui.QCursor.pos(), self.helpMessage, self)
|
||||
|
||||
def addHelpButton(self):
|
||||
"""Adds the help button to the provided layout."""
|
||||
|
||||
self.helpButton = QtGui.QToolButton(self)
|
||||
|
||||
self.helpButton.setIcon(resourceIcon("help"))
|
||||
self.helpButton.setIconSize(QtCore.QSize(16, 16))
|
||||
self.helpButton.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly)
|
||||
self.helpButton.setAutoRaise(True)
|
||||
|
||||
self.connect(self.helpButton, QtCore.SIGNAL('clicked()'), self.showHelp)
|
||||
|
||||
if self.helpMessage == "":
|
||||
self.helpButton.setEnabled(False)
|
||||
|
||||
if not self.getHelpButton() is None :
|
||||
self.addWidget(self.getHelpButton())
|
||||
|
||||
def getLabel(self):
|
||||
"""Returns the label of this widget if set or empty string."""
|
||||
return self.label
|
||||
|
||||
def addLayout(self, layout):
|
||||
"""Add a layout to the layout of this widget."""
|
||||
self.widgetLayout.addLayout(layout)
|
||||
|
||||
|
||||
def addWidget(self, widget):
|
||||
"""Add a widget to the layout of this widget."""
|
||||
self.widgetLayout.addWidget(widget)
|
||||
|
||||
def addStretch(self):
|
||||
"""Add stretch between widgets. Usually added between a widget and the help button."""
|
||||
self.widgetLayout.addStretch(1)
|
||||
|
||||
def setValidationMessage(self, message, validationType=WARNING):
|
||||
"""Add a warning or information icon to the widget with a tooltip"""
|
||||
if message == "":
|
||||
self.validationLabel.setHidden(True)
|
||||
self.validationLabel.setToolTip("")
|
||||
else:
|
||||
self.validationLabel.setHidden(False)
|
||||
self.validationLabel.setToolTip(message)
|
||||
self.validationLabel.setPixmap(resourceImage(validationType))
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'pathchooser.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
import os
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from helpedwidget import *
|
||||
import re
|
||||
|
||||
class PathChooser(HelpedWidget):
|
||||
"""PathChooser shows, enables choosing of and validates paths. The data structure expected and sent to the getter and setter is a string."""
|
||||
|
||||
file_does_not_exist_msg = "The specified path does not exist."
|
||||
file_is_not_executable_msg = "The specified file is not an executable."
|
||||
path_is_not_a_file_msg = "The specified path must be a file."
|
||||
required_field_msg = "A value is required."
|
||||
path_format_msg = "Must be a path format."
|
||||
|
||||
# UNDEFINED = 0
|
||||
# REQUIRED = 1
|
||||
# FILE = 2
|
||||
# DIRECTORY = 4
|
||||
# MUST_EXIST = 8
|
||||
# EXECUTABLE = 16
|
||||
|
||||
def __init__(self, parent=None, pathLabel="Path", help="",
|
||||
show_files=False,
|
||||
must_be_set=True,
|
||||
path_format=False,
|
||||
must_exist=True,
|
||||
absolute_path = False,
|
||||
is_executable_file=False):
|
||||
"""Construct a PathChooser widget"""
|
||||
HelpedWidget.__init__(self, parent, pathLabel, help)
|
||||
|
||||
self.editing = True
|
||||
self.selectFiles = show_files
|
||||
self.must_be_set = must_be_set
|
||||
self.path_format = path_format
|
||||
self.must_exist = must_exist
|
||||
self.absolute_path = absolute_path
|
||||
self.is_executable_file = is_executable_file
|
||||
|
||||
self.pathLine = QtGui.QLineEdit()
|
||||
#self.pathLine.setMinimumWidth(250)
|
||||
|
||||
self.connect(self.pathLine, QtCore.SIGNAL('editingFinished()'), self.validatePath)
|
||||
self.connect(self.pathLine, QtCore.SIGNAL('editingFinished()'), self.contentsChanged)
|
||||
self.connect(self.pathLine, QtCore.SIGNAL('textChanged(QString)'), self.validatePath)
|
||||
|
||||
self.addWidget(self.pathLine)
|
||||
|
||||
dialogButton = QtGui.QToolButton(self)
|
||||
dialogButton.setIcon(resourceIcon("folder"))
|
||||
dialogButton.setIconSize(QtCore.QSize(16, 16))
|
||||
self.connect(dialogButton, QtCore.SIGNAL('clicked()'), self.selectDirectory)
|
||||
self.addWidget(dialogButton)
|
||||
|
||||
self.addHelpButton()
|
||||
|
||||
self.validColor = self.pathLine.palette().color(self.pathLine.backgroundRole())
|
||||
|
||||
self.pathLine.setText(os.getcwd())
|
||||
self.editing = False
|
||||
|
||||
def getValidationTypeAndColor(self):
|
||||
"""Returns the type of validation message and the color that should be applied"""
|
||||
if self.must_be_set:
|
||||
color = self.ERROR_COLOR
|
||||
type = self.WARNING
|
||||
else:
|
||||
color = self.INVALID_COLOR
|
||||
type = self.EXCLAMATION
|
||||
return type, color
|
||||
|
||||
def validatePath(self):
|
||||
"""Called whenever the path is modified"""
|
||||
palette = self.pathLine.palette()
|
||||
|
||||
path = self.getPath().strip()
|
||||
exists = os.path.exists(path)
|
||||
|
||||
color = self.validColor
|
||||
message = ""
|
||||
type = self.WARNING
|
||||
|
||||
self.valid = True
|
||||
|
||||
if path == "" and self.must_be_set:
|
||||
message = self.required_field_msg
|
||||
color = self.ERROR_COLOR
|
||||
self.valid = False
|
||||
elif self.path_format and not re.search("%[0-9]*d", path):
|
||||
message = self.path_format_msg
|
||||
color = self.ERROR_COLOR
|
||||
self.valid = False
|
||||
elif not exists:
|
||||
if not self.path_format and self.must_exist:
|
||||
message = self.file_does_not_exist_msg
|
||||
self.valid = False
|
||||
type, color = self.getValidationTypeAndColor()
|
||||
elif exists:
|
||||
if self.is_executable_file and os.path.isfile(path) and not os.access(path, os.X_OK):
|
||||
type, color = self.getValidationTypeAndColor()
|
||||
message = self.file_is_not_executable_msg
|
||||
self.valid = False
|
||||
elif self.is_executable_file and not os.path.isfile(path):
|
||||
type, color = self.getValidationTypeAndColor()
|
||||
message = self.path_is_not_a_file_msg
|
||||
self.valid = False
|
||||
|
||||
|
||||
self.setValidationMessage(message, type)
|
||||
self.pathLine.setToolTip(message)
|
||||
palette.setColor(self.pathLine.backgroundRole(), color)
|
||||
|
||||
self.pathLine.setPalette(palette)
|
||||
|
||||
|
||||
def getPath(self):
|
||||
"""Returns the path"""
|
||||
return str(self.pathLine.text())
|
||||
|
||||
def pathExists(self):
|
||||
"""Returns True if the entered path exists"""
|
||||
return os.path.exists(self.getPath())
|
||||
|
||||
def isValid(self):
|
||||
"""Retruns the validation value"""
|
||||
return self.valid
|
||||
|
||||
|
||||
def selectDirectory(self):
|
||||
"""Pops up the 'select a directory' dialog"""
|
||||
self.editing = True
|
||||
currentDirectory = self.getPath()
|
||||
|
||||
#if not os.path.exists(currentDirectory):
|
||||
# currentDirectory = "~"
|
||||
|
||||
if self.selectFiles:
|
||||
currentDirectory = QtGui.QFileDialog.getOpenFileName(self, "Select a path", currentDirectory)
|
||||
else:
|
||||
currentDirectory = QtGui.QFileDialog.getExistingDirectory(self, "Select a directory", currentDirectory)
|
||||
|
||||
if not currentDirectory == "":
|
||||
if not self.absolute_path:
|
||||
cwd = os.getcwd()
|
||||
match = re.match(cwd + "/(.*)", currentDirectory)
|
||||
if match:
|
||||
currentDirectory = match.group(1)
|
||||
|
||||
self.pathLine.setText(currentDirectory)
|
||||
self.updateContent(self.getPath())
|
||||
|
||||
self.editing = False
|
||||
|
||||
|
||||
def contentsChanged(self):
|
||||
"""Called whenever the path is changed."""
|
||||
if not self.editing:
|
||||
self.updateContent(self.getPath())
|
||||
|
||||
|
||||
def fetchContent(self):
|
||||
"""Retrieves data from the model and inserts it into the edit line"""
|
||||
self.editing = True
|
||||
|
||||
path = self.getFromModel()
|
||||
if path is None:
|
||||
path = ""
|
||||
|
||||
self.pathLine.setText(path)
|
||||
self.editing = False
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'reloadbutton.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from helpedwidget import HelpedWidget
|
||||
|
||||
class ReloadButton(HelpedWidget):
|
||||
"""Presents a reload button. """
|
||||
|
||||
def __init__(self, parent=None, label="", help="", button_text=""):
|
||||
"""Construct a StringBox widget"""
|
||||
HelpedWidget.__init__(self, parent, label, help)
|
||||
|
||||
self.button = QtGui.QToolButton(self)
|
||||
self.button.setText(button_text)
|
||||
self.addWidget(self.button)
|
||||
|
||||
self.connect(self.button, QtCore.SIGNAL('clicked()'), self.fetchContent)
|
||||
|
||||
self.addStretch()
|
||||
self.addHelpButton()
|
||||
|
||||
|
||||
def fetchContent(self):
|
||||
"""Retrieves data from the model"""
|
||||
data = self.getFromModel()
|
||||
@@ -1,153 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'searchablelist.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from tablewidgets import AddRemoveWidget
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from tablewidgets import OrderWidget
|
||||
|
||||
class SearchableList(QtGui.QWidget):
|
||||
"""
|
||||
A searchable list of items.
|
||||
Emits addItem(QListWidget) and removeItem(QListWidget) when the add and remove buttons are pressed.
|
||||
"""
|
||||
passiveColor = QtGui.QColor(194, 194, 194)
|
||||
|
||||
def __init__(self, parent=None, converter=lambda item : str(item.text()), list_height=350, list_width = 130, ignore_case=False, order_editable=False):
|
||||
QtGui.QWidget.__init__(self, parent)
|
||||
self.setMaximumWidth(list_width)
|
||||
self.setMinimumWidth(list_width)
|
||||
self.converter = converter
|
||||
self.ignore_case = ignore_case
|
||||
|
||||
vlayout = QtGui.QVBoxLayout()
|
||||
vlayout.setMargin(0)
|
||||
|
||||
self.searchBox = QtGui.QLineEdit(parent)
|
||||
self.searchBox.setToolTip("Type to search!")
|
||||
self.searchBox.focusInEvent = lambda event : self.enterSearch(event)
|
||||
self.searchBox.focusOutEvent = lambda event : self.exitSearch(event)
|
||||
self.activeColor = self.searchBox.palette().color(self.searchBox.foregroundRole())
|
||||
self.disableSearch = True
|
||||
self.presentSearch()
|
||||
self.connect(self.searchBox, QtCore.SIGNAL('textChanged(QString)'), self.searchInList)
|
||||
vlayout.addWidget(self.searchBox)
|
||||
|
||||
self.list = QtGui.QListWidget(parent)
|
||||
self.list.setMaximumWidth(list_width - 2)
|
||||
self.list.setMinimumWidth(list_width - 2)
|
||||
self.list.setMinimumHeight(list_height)
|
||||
|
||||
if not order_editable:
|
||||
self.list.setSortingEnabled(True)
|
||||
|
||||
vlayout.addWidget(self.list)
|
||||
|
||||
addItem = lambda : self.emit(QtCore.SIGNAL("addItem(list)"), self.list)
|
||||
removeItem = lambda : self.emit(QtCore.SIGNAL("removeItem(list)"), self.list)
|
||||
add_remove_widget = AddRemoveWidget(self, addItem, removeItem, True)
|
||||
|
||||
if order_editable:
|
||||
def moveItemUp():
|
||||
index = self.list.currentRow()
|
||||
if index > 0 and self.list.count() > 1:
|
||||
item = self.list.takeItem(index)
|
||||
self.list.insertItem(index - 1, item)
|
||||
self.list.setCurrentItem(item)
|
||||
self.emit(QtCore.SIGNAL("orderChanged(list)"), self.list)
|
||||
|
||||
def moveItemDown():
|
||||
index = self.list.currentRow()
|
||||
if index < self.list.count() - 1 and self.list.count() > 1:
|
||||
item = self.list.takeItem(index)
|
||||
self.list.insertItem(index + 1, item)
|
||||
self.list.setCurrentItem(item)
|
||||
self.emit(QtCore.SIGNAL("orderChanged(list)"), self.list)
|
||||
|
||||
hlayout = QtGui.QHBoxLayout()
|
||||
hlayout.setMargin(0)
|
||||
hlayout.addWidget(OrderWidget(self, moveItemUp, moveItemDown, True))
|
||||
|
||||
hlayout.addWidget(add_remove_widget)
|
||||
vlayout.addLayout(hlayout)
|
||||
|
||||
else:
|
||||
vlayout.addWidget(add_remove_widget)
|
||||
|
||||
|
||||
|
||||
|
||||
self.setLayout(vlayout)
|
||||
|
||||
def emitter(current, previous):
|
||||
self.emit(QtCore.SIGNAL("currentItemChanged(QListWidgetItem, QListWidgetItem)"), current, previous)
|
||||
|
||||
self.connect(self.list, QtCore.SIGNAL('currentItemChanged(QListWidgetItem *, QListWidgetItem *)'), emitter)
|
||||
|
||||
def presentSearch(self):
|
||||
"""Is called to present the greyed out search"""
|
||||
self.disableSearch = True
|
||||
self.searchBox.setText("Search")
|
||||
palette = self.searchBox.palette()
|
||||
palette.setColor(self.searchBox.foregroundRole(), self.passiveColor)
|
||||
self.searchBox.setPalette(palette)
|
||||
|
||||
def activateSearch(self):
|
||||
"""Is called to remove the greyed out search"""
|
||||
self.disableSearch = False
|
||||
self.searchBox.setText("")
|
||||
palette = self.searchBox.palette()
|
||||
palette.setColor(self.searchBox.foregroundRole(), self.activeColor)
|
||||
self.searchBox.setPalette(palette)
|
||||
|
||||
def enterSearch(self, focusEvent):
|
||||
"""Called when the line edit gets the focus"""
|
||||
QtGui.QLineEdit.focusInEvent(self.searchBox, focusEvent)
|
||||
if str(self.searchBox.text()) == "Search":
|
||||
self.activateSearch()
|
||||
|
||||
def exitSearch(self, focusEvent):
|
||||
"""Called when the line edit looses focus"""
|
||||
QtGui.QLineEdit.focusOutEvent(self.searchBox, focusEvent)
|
||||
if str(self.searchBox.text()) == "":
|
||||
self.presentSearch()
|
||||
|
||||
def searchInList(self, value):
|
||||
"""Called when the contents of the search box changes"""
|
||||
if not self.disableSearch:
|
||||
for index in range(self.list.count()):
|
||||
item = self.list.item(index)
|
||||
text = self.converter(item)
|
||||
|
||||
if self.ignore_case:
|
||||
value = str(value).lower()
|
||||
text = text.lower()
|
||||
|
||||
if not text.find(value) == -1:
|
||||
item.setHidden(False)
|
||||
else:
|
||||
item.setHidden(True)
|
||||
|
||||
def getList(self):
|
||||
"""Returns the contained list widget"""
|
||||
return self.list
|
||||
|
||||
def getItems(self):
|
||||
items = []
|
||||
|
||||
for index in range(self.list.count()):
|
||||
items.append(self.list.item(index))
|
||||
return items
|
||||
@@ -1,82 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'spinnerwidgets.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from helpedwidget import HelpedWidget
|
||||
|
||||
class IntegerSpinner(HelpedWidget):
|
||||
"""A spinner widget for integers. The data structure expected and sent to the getter and setter is an integer."""
|
||||
def __init__(self, parent=None, spinnerLabel="Number", help="", min=0, max=10):
|
||||
"""Construct a spinner widget for integers"""
|
||||
HelpedWidget.__init__(self, parent, spinnerLabel, help)
|
||||
|
||||
self.spinner = QtGui.QSpinBox(self)
|
||||
self.spinner.setMinimum(min)
|
||||
self.spinner.setMaximum(max)
|
||||
#self.connect(self.pathLine, QtCore.SIGNAL('textChanged(QString)'), self.validatePath)
|
||||
self.addWidget(self.spinner)
|
||||
|
||||
self.infoLabel = QtGui.QLabel()
|
||||
self.infoLabel.setHidden(True)
|
||||
self.addWidget(self.infoLabel)
|
||||
|
||||
self.addStretch()
|
||||
self.addHelpButton()
|
||||
|
||||
#self.connect(self.spinner, QtCore.SIGNAL('valueChanged(int)'), self.updateContent)
|
||||
self.connect(self.spinner, QtCore.SIGNAL('editingFinished()'), self.contentsChanged)
|
||||
|
||||
def contentsChanged(self):
|
||||
"""Called whenever the contents of the spinner changes."""
|
||||
self.updateContent(self.spinner.value())
|
||||
|
||||
def fetchContent(self):
|
||||
"""Retrieves data from the model and inserts it into the spinner"""
|
||||
self.spinner.setValue(self.getFromModel())
|
||||
|
||||
def setInfo(self, info):
|
||||
self.infoLabel.setText(info)
|
||||
self.infoLabel.setHidden(False)
|
||||
|
||||
class DoubleSpinner(HelpedWidget):
|
||||
"""A spinner widget for doubles. The data structure expected and sent to the getter and setter is a double."""
|
||||
def __init__(self, parent=None, spinnerLabel="Double Number", help="", min=0.0, max=1.0, decimals=2):
|
||||
"""Construct a spinner widget for doubles"""
|
||||
HelpedWidget.__init__(self, parent, spinnerLabel, help)
|
||||
|
||||
self.spinner = QtGui.QDoubleSpinBox(self)
|
||||
self.spinner.setMinimum(min)
|
||||
self.spinner.setMaximum(max)
|
||||
self.spinner.setDecimals(decimals)
|
||||
self.spinner.setSingleStep(0.01)
|
||||
|
||||
self.addWidget(self.spinner)
|
||||
|
||||
self.addStretch()
|
||||
self.addHelpButton()
|
||||
|
||||
#self.connect(self.spinner, QtCore.SIGNAL('valueChanged(int)'), self.updateContent)
|
||||
self.connect(self.spinner, QtCore.SIGNAL('editingFinished()'), self.contentsChanged)
|
||||
|
||||
def contentsChanged(self):
|
||||
"""Called whenever the contents of the spinner changes."""
|
||||
self.updateContent(self.spinner.value())
|
||||
|
||||
|
||||
def fetchContent(self):
|
||||
"""Retrieves data from the model and inserts it into the spinner"""
|
||||
self.spinner.setValue(self.getFromModel())
|
||||
@@ -1,94 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'stringbox.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from helpedwidget import *
|
||||
|
||||
class StringBox(HelpedWidget):
|
||||
"""StringBox shows a string. The data structure expected and sent to the getter and setter is a string."""
|
||||
|
||||
def __init__(self, parent=None, pathLabel="String", help="", defaultString=""):
|
||||
"""Construct a StringBox widget"""
|
||||
HelpedWidget.__init__(self, parent, pathLabel, help)
|
||||
|
||||
self.boxString = QtGui.QLineEdit()
|
||||
self.connect(self.boxString, QtCore.SIGNAL('editingFinished()'), self.validateString)
|
||||
self.connect(self.boxString, QtCore.SIGNAL('editingFinished()'), self.contentsChanged)
|
||||
self.connect(self.boxString, QtCore.SIGNAL('textChanged(QString)'), self.validateString)
|
||||
self.addWidget(self.boxString)
|
||||
|
||||
self.addHelpButton()
|
||||
|
||||
self.boxString.setText(defaultString)
|
||||
|
||||
|
||||
def validateString(self):
|
||||
"""Override this to provide validation of the contained string. NOT SUPPORTED YET!"""
|
||||
stringToValidate = self.boxString.text()
|
||||
#todo implement validation possibility
|
||||
|
||||
|
||||
def contentsChanged(self):
|
||||
"""Called whenever the contents of the editline changes."""
|
||||
box_string_text = str(self.boxString.text())
|
||||
if box_string_text == "":
|
||||
box_string_text = None
|
||||
|
||||
self.updateContent(box_string_text)
|
||||
|
||||
def fetchContent(self):
|
||||
"""Retrieves data from the model and inserts it into the edit line"""
|
||||
self_get_from_model = self.getFromModel()
|
||||
if self_get_from_model is None:
|
||||
self_get_from_model = ""
|
||||
|
||||
self.boxString.setText(self_get_from_model)
|
||||
|
||||
|
||||
|
||||
class DoubleBox(HelpedWidget):
|
||||
"""DoubleBox shows a double value. The data structure expected and sent to the getter and setter is a double."""
|
||||
|
||||
def __init__(self, parent=None, pathLabel="Double", help=""):
|
||||
"""Construct a DoubleBox widget"""
|
||||
HelpedWidget.__init__(self, parent, pathLabel, help)
|
||||
|
||||
self.doubleBox = QtGui.QLineEdit()
|
||||
self.doubleBox.setValidator(QtGui.QDoubleValidator(self))
|
||||
self.doubleBox.setMaximumWidth(75)
|
||||
|
||||
#self.connect(self.doubleBox, QtCore.SIGNAL('editingFinished()'), self.validateString)
|
||||
self.connect(self.doubleBox, QtCore.SIGNAL('editingFinished()'), self.contentsChanged)
|
||||
self.connect(self.doubleBox, QtCore.SIGNAL('textChanged(QString)'), self.validateString)
|
||||
self.addWidget(self.doubleBox)
|
||||
|
||||
self.addStretch()
|
||||
self.addHelpButton()
|
||||
|
||||
|
||||
def validateString(self):
|
||||
stringToValidate = str(self.doubleBox.text())
|
||||
if stringToValidate.strip() == "":
|
||||
self.contentsChanged()
|
||||
|
||||
def contentsChanged(self):
|
||||
"""Called whenever the contents of the editline changes."""
|
||||
self.updateContent(str(self.doubleBox.text()))
|
||||
|
||||
def fetchContent(self):
|
||||
"""Retrieves data from the model and inserts it into the edit line"""
|
||||
self.doubleBox.setText(str(self.getFromModel()))
|
||||
@@ -1,279 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'tablewidgets.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from helpedwidget import *
|
||||
from util import *
|
||||
|
||||
class OrderWidget(QtGui.QWidget):
|
||||
"""
|
||||
A simple class that provides to vertically positioned buttons for adding and removing something.
|
||||
The addFunction and removeFunction functions must be provided.
|
||||
"""
|
||||
def __init__(self, parent=None, upFunction=None, downFunction=None, horizontal=False):
|
||||
"""Creates a two button widget"""
|
||||
QtGui.QWidget.__init__(self, parent)
|
||||
|
||||
self.moveUpButton = QtGui.QToolButton(self)
|
||||
self.moveUpButton.setIcon(resourceIcon("arrow_up"))
|
||||
self.moveUpButton.setIconSize(QtCore.QSize(16, 16))
|
||||
self.connect(self.moveUpButton, QtCore.SIGNAL('clicked()'), upFunction)
|
||||
|
||||
self.moveDownButton = QtGui.QToolButton(self)
|
||||
self.moveDownButton.setIcon(resourceIcon("arrow_down"))
|
||||
self.moveDownButton.setIconSize(QtCore.QSize(16, 16))
|
||||
self.connect(self.moveDownButton, QtCore.SIGNAL('clicked()'), downFunction)
|
||||
|
||||
if horizontal:
|
||||
self.buttonLayout = QtGui.QHBoxLayout()
|
||||
else:
|
||||
self.buttonLayout = QtGui.QVBoxLayout()
|
||||
|
||||
self.buttonLayout.setMargin(0)
|
||||
|
||||
if not horizontal:
|
||||
self.buttonLayout.addStretch(1)
|
||||
|
||||
self.buttonLayout.addWidget(self.moveUpButton)
|
||||
self.buttonLayout.addWidget(self.moveDownButton)
|
||||
|
||||
if horizontal:
|
||||
self.buttonLayout.addStretch(1)
|
||||
else:
|
||||
self.buttonLayout.addSpacing(2)
|
||||
|
||||
self.setLayout(self.buttonLayout)
|
||||
|
||||
def enableUpButton(self, state):
|
||||
"""Enable or disable the add button"""
|
||||
self.moveUpButton.setEnabled(state)
|
||||
|
||||
def enableDownButton(self, state):
|
||||
"""Enable or disable the remove button"""
|
||||
self.moveDownButton.setEnabled(state)
|
||||
|
||||
|
||||
class AddRemoveWidget(QtGui.QWidget):
|
||||
"""
|
||||
A simple class that provides to vertically positioned buttons for adding and removing something.
|
||||
The addFunction and removeFunction functions must be provided.
|
||||
"""
|
||||
def __init__(self, parent=None, addFunction=None, removeFunction=None, horizontal=False):
|
||||
"""Creates a two button widget"""
|
||||
QtGui.QWidget.__init__(self, parent)
|
||||
|
||||
self.addButton = QtGui.QToolButton(self)
|
||||
self.addButton.setIcon(resourceIcon("add"))
|
||||
self.addButton.setIconSize(QtCore.QSize(16, 16))
|
||||
self.connect(self.addButton, QtCore.SIGNAL('clicked()'), addFunction)
|
||||
|
||||
self.removeButton = QtGui.QToolButton(self)
|
||||
self.removeButton.setIcon(resourceIcon("remove"))
|
||||
self.removeButton.setIconSize(QtCore.QSize(16, 16))
|
||||
self.connect(self.removeButton, QtCore.SIGNAL('clicked()'), removeFunction)
|
||||
|
||||
if horizontal:
|
||||
self.buttonLayout = QtGui.QHBoxLayout()
|
||||
else:
|
||||
self.buttonLayout = QtGui.QVBoxLayout()
|
||||
|
||||
self.buttonLayout.setMargin(0)
|
||||
|
||||
if horizontal:
|
||||
self.buttonLayout.addStretch(1)
|
||||
|
||||
self.buttonLayout.addWidget(self.addButton)
|
||||
self.buttonLayout.addWidget(self.removeButton)
|
||||
|
||||
if not horizontal:
|
||||
self.buttonLayout.addStretch(1)
|
||||
else:
|
||||
self.buttonLayout.addSpacing(2)
|
||||
|
||||
self.setLayout(self.buttonLayout)
|
||||
|
||||
def enableAddButton(self, state):
|
||||
"""Enable or disable the add button"""
|
||||
self.addButton.setEnabled(state)
|
||||
|
||||
def enableRemoveButton(self, state):
|
||||
"""Enable or disable the remove button"""
|
||||
self.removeButton.setEnabled(state)
|
||||
|
||||
|
||||
class KeywordList(HelpedWidget):
|
||||
"""Shows a list of keywords. The data structure expected and sent to the getter and setter is an array of values."""
|
||||
def __init__(self, parent=None, listLabel="", help=""):
|
||||
"""Construct a list for showing keywords"""
|
||||
HelpedWidget.__init__(self, parent, listLabel, help)
|
||||
|
||||
self.list = QtGui.QListWidget(self)
|
||||
self.list.setMinimumHeight(50)
|
||||
self.list.setMaximumHeight(70)
|
||||
|
||||
self.addWidget(self.list)
|
||||
|
||||
self.addRemoveWidget = AddRemoveWidget(self, self.addItem, self.removeItem)
|
||||
self.addWidget(self.addRemoveWidget)
|
||||
|
||||
#self.addStretch()
|
||||
self.addHelpButton()
|
||||
self.title = "New keyword"
|
||||
self.description = "Enter name of keyword:"
|
||||
|
||||
def setPopupLabels(self, title, description):
|
||||
"""Change the labels of the default popup."""
|
||||
self.title = title
|
||||
self.description = description
|
||||
|
||||
def newKeywordPopup(self, list):
|
||||
"""
|
||||
Pops up a message box asking for a new keyword.
|
||||
Override this and return a string to customize the input dialog - Empty string equals canceled.
|
||||
The provided list are the already defined keywords
|
||||
"""
|
||||
newKeyword, ok = QtGui.QInputDialog.getText(self, self.tr(self.title), self.tr(self.description), QtGui.QLineEdit.Normal)
|
||||
|
||||
if ok:
|
||||
return str(newKeyword).strip()
|
||||
else:
|
||||
return ""
|
||||
|
||||
def addItem(self):
|
||||
"""Called by the add button to insert a new keyword"""
|
||||
newKeyword = self.newKeywordPopup(self.getList())
|
||||
if not newKeyword == "":
|
||||
self.list.addItem(newKeyword)
|
||||
self.contentsChanged()
|
||||
|
||||
|
||||
def removeItem(self):
|
||||
"""Called by the remove button to remove a selected keyword"""
|
||||
if not self.list.currentItem() is None:
|
||||
self.list.takeItem(self.list.currentRow())
|
||||
self.contentsChanged()
|
||||
|
||||
|
||||
def getList(self):
|
||||
"""Returns the keywrods available in the list"""
|
||||
keywordList = []
|
||||
for index in range(self.list.count()):
|
||||
keywordList.append(str(self.list.item(index).text()))
|
||||
return keywordList
|
||||
|
||||
def contentsChanged(self):
|
||||
"""Called whenever the contents of the list changes."""
|
||||
self.updateContent(self.getList())
|
||||
|
||||
|
||||
def fetchContent(self):
|
||||
"""Retrieves data from the model and inserts it into the list"""
|
||||
keywords = self.getFromModel()
|
||||
|
||||
self.list.clear()
|
||||
|
||||
for keyword in keywords:
|
||||
self.list.addItem(keyword)
|
||||
|
||||
|
||||
|
||||
class KeywordTable(HelpedWidget):
|
||||
"""Shows a table of key/value pairs. The data structure expected and sent to the getter and setter is a dictionary of values."""
|
||||
def __init__(self, parent=None, tableLabel="", help="", colHead1="Keyword", colHead2="Value"):
|
||||
"""Construct a table for key/value pairs."""
|
||||
HelpedWidget.__init__(self, parent, tableLabel, help)
|
||||
|
||||
self.table = QtGui.QTableWidget(self)
|
||||
self.table.setColumnCount(2)
|
||||
self.headers = [colHead1, colHead2]
|
||||
self.table.setHorizontalHeaderLabels(self.headers)
|
||||
self.table.verticalHeader().setHidden(True)
|
||||
self.table.setColumnWidth(0, 150)
|
||||
#self.table.setColumnWidth(1, 250)
|
||||
self.table.horizontalHeader().setStretchLastSection(True)
|
||||
|
||||
self.table.setMinimumHeight(110)
|
||||
self.table.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
|
||||
self.table.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
|
||||
|
||||
self.addWidget(self.table)
|
||||
|
||||
self.addWidget(AddRemoveWidget(self, self.addItem, self.removeItem))
|
||||
|
||||
self.addHelpButton()
|
||||
|
||||
#self.connect(self.spinner, QtCore.SIGNAL('valueChanged(int)'), self.updateContent)
|
||||
self.connect(self.table, QtCore.SIGNAL('cellChanged(int,int)'), self.contentsChanged)
|
||||
|
||||
|
||||
def addItem(self):
|
||||
"""Called by the add button to insert a new keyword"""
|
||||
self.table.insertRow(self.table.currentRow() + 1)
|
||||
|
||||
self.contentsChanged()
|
||||
|
||||
|
||||
def removeItem(self):
|
||||
"""Called by the remove button to remove a selected keyword"""
|
||||
currentRow = self.table.currentRow()
|
||||
|
||||
if currentRow >= 0:
|
||||
doDelete = QtGui.QMessageBox.question(self, "Delete row?", "Are you sure you want to delete the key/value pair?", QtGui.QMessageBox.Yes | QtGui.QMessageBox.No )
|
||||
|
||||
if doDelete:
|
||||
self.table.removeRow(currentRow)
|
||||
self.contentsChanged()
|
||||
|
||||
|
||||
def contentsChanged(self):
|
||||
"""Called whenever the contents of a cell changes."""
|
||||
keyValueList = []
|
||||
|
||||
for index in range(self.table.rowCount()):
|
||||
key = self.table.item(index, 0)
|
||||
if not key is None:
|
||||
key = str(key.text()).strip()
|
||||
value = self.table.item(index, 1)
|
||||
|
||||
if not key == "" and not value is None:
|
||||
keyValueList.append([key, str(value.text()).strip()])
|
||||
|
||||
self.updateContent(keyValueList)
|
||||
|
||||
|
||||
def fetchContent(self):
|
||||
"""Retrieves data from the model and inserts it into the table."""
|
||||
values = self.getFromModel()
|
||||
|
||||
for row in reversed(range(self.table.rowCount())):
|
||||
self.table.removeRow(row)
|
||||
|
||||
#for column in reversed(range(self.table.columnCount())):
|
||||
# self.table.removeColumn(column)
|
||||
|
||||
#self.table.clearContents()
|
||||
|
||||
row = 0
|
||||
for value in values:
|
||||
keyItem = QtGui.QTableWidgetItem(value[0])
|
||||
valueItem = QtGui.QTableWidgetItem(value[1])
|
||||
self.table.insertRow(row)
|
||||
self.table.setItem(row, 0, keyItem)
|
||||
self.table.setItem(row, 1, valueItem)
|
||||
row+=1
|
||||
|
||||
|
||||
@@ -1,317 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'util.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
import os
|
||||
import time
|
||||
|
||||
# The variable @img_prefix should be set to point to a directory
|
||||
# containing icons and images. In the current implementation this
|
||||
# variable is set from the gert_main.py script.
|
||||
img_prefix = None
|
||||
|
||||
def resourceIcon(name):
|
||||
"""Load an image as an icon"""
|
||||
return QtGui.QIcon(img_prefix + name)
|
||||
|
||||
def resourceStateIcon(on, off):
|
||||
"""Load two images as an icon with on and off states"""
|
||||
icon = QtGui.QIcon()
|
||||
icon.addPixmap(resourceImage(on), state=QtGui.QIcon.On)
|
||||
icon.addPixmap(resourceImage(off), state=QtGui.QIcon.Off)
|
||||
return icon
|
||||
|
||||
def resourceImage(name):
|
||||
"""Load an image as a Pixmap"""
|
||||
return QtGui.QPixmap(img_prefix + name)
|
||||
|
||||
|
||||
class ListCheckPanel(QtGui.QHBoxLayout):
|
||||
"""
|
||||
Creates a panel with two buttons to select and unselect all elements of a list.
|
||||
A function: setSelectionEnabled(bool) is added to the list which enables enabling/disabling of list and buttons.
|
||||
"""
|
||||
|
||||
def __init__(self, list):
|
||||
QtGui.QHBoxLayout.__init__(self)
|
||||
|
||||
list.checkAll = QtGui.QToolButton()
|
||||
list.checkAll.setIcon(resourceIcon("checked"))
|
||||
list.checkAll.setIconSize(QtCore.QSize(16, 16))
|
||||
list.checkAll.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly)
|
||||
list.checkAll.setAutoRaise(True)
|
||||
list.checkAll.setToolTip("Select all")
|
||||
|
||||
list.uncheckAll = QtGui.QToolButton()
|
||||
list.uncheckAll.setIcon(resourceIcon("notchecked"))
|
||||
list.uncheckAll.setIconSize(QtCore.QSize(16, 16))
|
||||
list.uncheckAll.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly)
|
||||
list.uncheckAll.setAutoRaise(True)
|
||||
list.uncheckAll.setToolTip("Unselect all")
|
||||
|
||||
self.setMargin(0)
|
||||
self.setSpacing(0)
|
||||
self.addStretch(1)
|
||||
self.addWidget(list.checkAll)
|
||||
self.addWidget(list.uncheckAll)
|
||||
|
||||
self.connect(list.checkAll, QtCore.SIGNAL('clicked()'), list.selectAll)
|
||||
self.connect(list.uncheckAll, QtCore.SIGNAL('clicked()'), list.clearSelection)
|
||||
|
||||
def setSelectionEnabled(bool):
|
||||
list.setEnabled(bool)
|
||||
list.checkAll.setEnabled(bool)
|
||||
list.uncheckAll.setEnabled(bool)
|
||||
|
||||
list.setSelectionEnabled = setSelectionEnabled
|
||||
|
||||
|
||||
|
||||
|
||||
class ValidatedTimestepCombo(QtGui.QComboBox):
|
||||
"""
|
||||
A special type of combobox applicable to ERTs "fluxing" history length
|
||||
It supports values that have different representations and internal values
|
||||
"""
|
||||
def __init__(self, parent, fromValue=0, fromLabel="Initial", toValue=1, toLabel="Final"):
|
||||
"""Constructor"""
|
||||
QtGui.QComboBox.__init__(self, parent)
|
||||
|
||||
self.fromLabel = fromLabel
|
||||
self.fromValue = fromValue
|
||||
self.toLabel = toLabel
|
||||
self.toValue = toValue
|
||||
self.minTimeStep = fromValue
|
||||
self.maxTimeStep = toValue
|
||||
|
||||
self.setMaximumWidth(150)
|
||||
self.setEditable(True)
|
||||
self.setValidator(QtGui.QIntValidator(self.minTimeStep, self.maxTimeStep, None))
|
||||
self.addItem(self.fromLabel + " (" + str(self.fromValue) + ")")
|
||||
self.addItem(self.toLabel + " (" + str(self.toValue) + ")")
|
||||
|
||||
|
||||
def focusOutEvent(self, event):
|
||||
"""Combo lost focus. Validate and approve contents."""
|
||||
QtGui.QComboBox.focusOutEvent(self, event)
|
||||
|
||||
timestepMakesSense = False
|
||||
currentText = str(self.currentText())
|
||||
if currentText.startswith(self.fromLabel) or currentText.startswith(self.toLabel):
|
||||
timestepMakesSense = True
|
||||
|
||||
elif currentText.isdigit():
|
||||
intValue = int(currentText)
|
||||
timestepMakesSense = True
|
||||
|
||||
if intValue < self.minTimeStep:
|
||||
self.setCurrentIndex(0)
|
||||
|
||||
if intValue > self.maxTimeStep:
|
||||
self.setCurrentIndex(1)
|
||||
|
||||
|
||||
if not timestepMakesSense:
|
||||
self.setCurrentIndex(0)
|
||||
|
||||
|
||||
def setMinTimeStep(self, value):
|
||||
"""Set the minimum timestep value for custom values"""
|
||||
self.minTimeStep = value
|
||||
self.validator().setBottom(value)
|
||||
|
||||
def setMaxTimeStep(self, value):
|
||||
"""Set the maximum timestep value for custom values"""
|
||||
self.maxTimeStep = value
|
||||
self.validator().setTop(value)
|
||||
|
||||
def setFromValue(self, value):
|
||||
"""Set the presented from value"""
|
||||
self.fromValue = value
|
||||
self.setItemText(0, self.fromLabel + " (" + str(self.fromValue) + ")")
|
||||
|
||||
def setToValue(self, value):
|
||||
"""Set the presented to value"""
|
||||
self.toValue = value
|
||||
if self.toValue < self.fromValue:
|
||||
self.setItemText(1, self.toLabel)
|
||||
else:
|
||||
self.setItemText(1, self.toLabel + " (" + str(self.toValue) + ")")
|
||||
|
||||
def setHistoryLength(self, length):
|
||||
"""Set history length. Applies to both maximum timestep and value"""
|
||||
self.setMaxTimeStep(length)
|
||||
self.setToValue(length)
|
||||
|
||||
def getSelectedValue(self):
|
||||
"""Return the selected value. Either custom or one of: from value or to value"""
|
||||
currentText = str(self.currentText())
|
||||
|
||||
if currentText.startswith(self.fromLabel):
|
||||
return self.fromValue
|
||||
elif currentText.startswith(self.toLabel):
|
||||
return self.toValue
|
||||
else:
|
||||
return int(currentText)
|
||||
|
||||
|
||||
class ValidationInfo(QtGui.QWidget):
|
||||
"""A message with an icon that present information about validation."""
|
||||
|
||||
WARNING = "warning"
|
||||
EXCLAMATION = "exclamation"
|
||||
|
||||
def __init__(self, type=WARNING, parent = None):
|
||||
QtGui.QWidget.__init__(self, parent)
|
||||
|
||||
layout = QtGui.QHBoxLayout()
|
||||
self.iconLabel = QtGui.QLabel()
|
||||
self.iconLabel.setMaximumSize(QtCore.QSize(16, 16))
|
||||
self.iconLabel.setPixmap(resourceImage(type))
|
||||
layout.addWidget(self.iconLabel)
|
||||
|
||||
self.messageLabel = QtGui.QLabel()
|
||||
layout.addWidget(self.messageLabel)
|
||||
self.setLayout(layout)
|
||||
self.setHidden(True)
|
||||
|
||||
def setMessage(self, msg):
|
||||
"""Set this message to an empty string to hide the validation widget"""
|
||||
if msg.strip() == "":
|
||||
self.setHidden(True)
|
||||
else:
|
||||
self.setHidden(False)
|
||||
|
||||
self.messageLabel.setText(msg)
|
||||
|
||||
|
||||
|
||||
def createSeparator():
|
||||
"""Creates a widget that can be used as a separator line on a panel."""
|
||||
qw = QtGui.QWidget()
|
||||
qwl = QtGui.QVBoxLayout()
|
||||
qw.setLayout(qwl)
|
||||
|
||||
qf = QtGui.QFrame()
|
||||
qf.setFrameShape(QtGui.QFrame.HLine)
|
||||
qf.setFrameShadow(QtGui.QFrame.Sunken)
|
||||
|
||||
qwl.addSpacing(5)
|
||||
qwl.addWidget(qf)
|
||||
qwl.addSpacing(5)
|
||||
|
||||
return qw
|
||||
|
||||
def createSpace(size = 5):
|
||||
"""Creates a widget that can be used as spacing on a panel."""
|
||||
qw = QtGui.QWidget()
|
||||
qw.setMinimumSize(QtCore.QSize(size, size))
|
||||
|
||||
return qw
|
||||
|
||||
def createEmptyPanel():
|
||||
"""An empty expanding bordered panel"""
|
||||
emptyPanel = QtGui.QFrame()
|
||||
emptyPanel.setFrameShape(QtGui.QFrame.StyledPanel)
|
||||
emptyPanel.setFrameShadow(QtGui.QFrame.Plain)
|
||||
emptyPanel.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
|
||||
return emptyPanel
|
||||
|
||||
def centeredWidget(widget):
|
||||
"""Returns a layout with the widget centered"""
|
||||
layout = QtGui.QHBoxLayout()
|
||||
layout.addStretch(1)
|
||||
layout.addWidget(widget)
|
||||
layout.addStretch(1)
|
||||
return layout
|
||||
|
||||
|
||||
def getItemsFromList(list, func = lambda item : str(item.text()), selected = True) :
|
||||
"""Creates a list of strings from the selected items of a ListWidget or all items if selected is False"""
|
||||
if selected:
|
||||
selectedItemsList = list.selectedItems()
|
||||
else:
|
||||
selectedItemsList = []
|
||||
for index in range(list.count()):
|
||||
selectedItemsList.append(list.item(index))
|
||||
|
||||
selectedItems = []
|
||||
for item in selectedItemsList:
|
||||
selectedItems.append(func(item))
|
||||
|
||||
return selectedItems
|
||||
|
||||
|
||||
def frange(*args):
|
||||
"""
|
||||
A float range generator.
|
||||
Found here: http://code.activestate.com/recipes/66472/
|
||||
"""
|
||||
start = 0.0
|
||||
step = 1.0
|
||||
|
||||
l = len(args)
|
||||
if l == 1:
|
||||
end = args[0]
|
||||
elif l == 2:
|
||||
start, end = args
|
||||
elif l == 3:
|
||||
start, end, step = args
|
||||
if step == 0.0:
|
||||
raise ValueError, "step must not be zero"
|
||||
else:
|
||||
raise TypeError, "frange expects 1-3 arguments, got %d" % l
|
||||
|
||||
v = start
|
||||
while True:
|
||||
if (step > 0 and v >= end) or (step < 0 and v <= end):
|
||||
raise StopIteration
|
||||
yield v
|
||||
v += step
|
||||
|
||||
def shortTime(secs):
|
||||
"""Converts seconds into hours:minutes:seconds. -1 returns a '-'"""
|
||||
if secs == -1:
|
||||
return "-"
|
||||
else:
|
||||
t = time.localtime(secs)
|
||||
return time.strftime("%H:%M:%S", t)
|
||||
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# Function decorators
|
||||
#-------------------------------------------------------------
|
||||
|
||||
def print_timing(func):
|
||||
"""A function decorator that performs timing of the applied function"""
|
||||
def wrapper(*arg):
|
||||
t1 = time.time()
|
||||
res = func(*arg)
|
||||
t2 = time.time()
|
||||
print '%s took %0.3f ms' % (func.func_name, (t2-t1)*1000.0)
|
||||
return res
|
||||
return wrapper
|
||||
|
||||
|
||||
def may_take_a_long_time(func):
|
||||
"""A function decorator to show the wait cursor while the function is working."""
|
||||
def wrapper(*arg):
|
||||
QtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor))
|
||||
res = func(*arg)
|
||||
QtGui.QApplication.restoreOverrideCursor()
|
||||
return res
|
||||
return wrapper
|
||||
@@ -1,121 +0,0 @@
|
||||
# Copyright (C) 2011 Statoil ASA, Norway.
|
||||
#
|
||||
# The file 'validateddialog.py' is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details.
|
||||
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
import util
|
||||
|
||||
class ValidatedDialog(QtGui.QDialog):
|
||||
"""A dialog for creating a validated. Performs validation of name."""
|
||||
|
||||
INVALID_COLOR = QtGui.QColor(255, 235, 235)
|
||||
|
||||
def __init__(self, parent, title = "Title", description = "Description", uniqueNames = None, chooseFromList=False):
|
||||
"""Creates a new dialog that validates uniqueness against the provided list"""
|
||||
QtGui.QDialog.__init__(self, parent)
|
||||
self.setModal(True)
|
||||
self.setWindowTitle(title)
|
||||
self.setMinimumWidth(250)
|
||||
self.setMinimumHeight(150)
|
||||
|
||||
if uniqueNames is None:
|
||||
uniqueNames = []
|
||||
self.uniqueNames = uniqueNames
|
||||
|
||||
self.layout = QtGui.QFormLayout()
|
||||
|
||||
q_label = QtGui.QLabel(description)
|
||||
q_label.setAlignment(QtCore.Qt.AlignHCenter)
|
||||
|
||||
self.layout.addRow(util.createSpace(5))
|
||||
self.layout.addRow(q_label)
|
||||
self.layout.addRow(util.createSpace(10))
|
||||
|
||||
|
||||
buttons = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel, QtCore.Qt.Horizontal, self)
|
||||
self.okbutton = buttons.button(QtGui.QDialogButtonBox.Ok)
|
||||
self.okbutton.setEnabled(False)
|
||||
|
||||
|
||||
if chooseFromList:
|
||||
self.paramNameCombo = QtGui.QComboBox()
|
||||
self.connect(self.paramNameCombo, QtCore.SIGNAL('currentIndexChanged(QString)'), self.validateChoice)
|
||||
for item in uniqueNames:
|
||||
self.paramNameCombo.addItem(item)
|
||||
self.layout.addRow("Job:", self.paramNameCombo)
|
||||
else:
|
||||
self.paramName = QtGui.QLineEdit(self)
|
||||
self.connect(self.paramName, QtCore.SIGNAL('textChanged(QString)'), self.validateName)
|
||||
self.validColor = self.paramName.palette().color(self.paramName.backgroundRole())
|
||||
|
||||
self.layout.addRow("Name:", self.paramName)
|
||||
self.layout.addRow(util.createSpace(10))
|
||||
|
||||
|
||||
self.layout.addRow(buttons)
|
||||
|
||||
self.connect(buttons, QtCore.SIGNAL('accepted()'), self.accept)
|
||||
self.connect(buttons, QtCore.SIGNAL('rejected()'), self.reject)
|
||||
|
||||
self.setLayout(self.layout)
|
||||
|
||||
def notValid(self, msg):
|
||||
"""Called when the name is not valid."""
|
||||
self.okbutton.setEnabled(False)
|
||||
palette = self.paramName.palette()
|
||||
palette.setColor(self.paramName.backgroundRole(), self.INVALID_COLOR)
|
||||
self.paramName.setToolTip(msg)
|
||||
self.paramName.setPalette(palette)
|
||||
|
||||
def valid(self):
|
||||
"""Called when the name is valid."""
|
||||
self.okbutton.setEnabled(True)
|
||||
palette = self.paramName.palette()
|
||||
palette.setColor(self.paramName.backgroundRole(), self.validColor)
|
||||
self.paramName.setToolTip("")
|
||||
self.paramName.setPalette(palette)
|
||||
|
||||
def validateName(self, value):
|
||||
"""Called to perform validation of a name. For specific needs override this function and call valid() and notValid(msg)."""
|
||||
value = str(value)
|
||||
|
||||
if value == "":
|
||||
self.notValid("Can not be empty!")
|
||||
elif not value.find(" ") == -1:
|
||||
self.notValid("No spaces allowed!")
|
||||
elif value in self.uniqueNames:
|
||||
self.notValid("Name must be unique!")
|
||||
else:
|
||||
self.valid()
|
||||
|
||||
def validateChoice(self, choice):
|
||||
"""Only called when using selection mode."""
|
||||
self.okbutton.setEnabled(not choice == "")
|
||||
|
||||
|
||||
def getName(self):
|
||||
"""Return the new name chosen by the user"""
|
||||
if hasattr(self, "paramName"):
|
||||
return str(self.paramName.text())
|
||||
else:
|
||||
return str(self.paramNameCombo.currentText())
|
||||
|
||||
def showAndTell(self):
|
||||
"""Shows the dialog and returns the result"""
|
||||
if self.exec_():
|
||||
return str(self.getName()).strip()
|
||||
|
||||
return ""
|
||||
@@ -37,6 +37,8 @@
|
||||
#include <ert/plot/plot_dataset.h>
|
||||
|
||||
#include <ert/ecl/ecl_rft_file.h>
|
||||
#include <ert/ecl/ecl_rft_node.h>
|
||||
#include <ert/ecl/ecl_rft_cell.h>
|
||||
|
||||
#include <ert/enkf/enkf_main.h>
|
||||
#include <ert/enkf/enkf_obs.h>
|
||||
@@ -245,7 +247,12 @@ void enkf_tui_plot_RFT_simIn(enkf_main_type * enkf_main, path_fmt_type * runpath
|
||||
for (int nobs =0; nobs<lines; nobs++){
|
||||
int start_index = 0;
|
||||
int i; int j; int k;
|
||||
int global_index = ecl_grid_get_global_index_from_xyz(grid,double_vector_iget(UTM_x,nobs) ,double_vector_iget(UTM_y,nobs) ,double_vector_iget(TVD_z,nobs) ,start_index);
|
||||
int global_index = ecl_grid_get_global_index_from_xyz( grid ,
|
||||
double_vector_iget(UTM_x,nobs) ,
|
||||
double_vector_iget(UTM_y,nobs) ,
|
||||
double_vector_iget(TVD_z,nobs) ,
|
||||
start_index);
|
||||
|
||||
ecl_grid_get_ijk1(grid , global_index, &i, &j , &k);
|
||||
int is_active = ecl_grid_get_active_index1(grid , global_index);
|
||||
int_vector_iset(i_values, nobs, i);
|
||||
@@ -287,17 +294,16 @@ void enkf_tui_plot_RFT_simIn(enkf_main_type * enkf_main, path_fmt_type * runpath
|
||||
else{
|
||||
for( int nobs = 0; nobs < lines; nobs++){
|
||||
if( int_vector_iget(active,nobs) > -1){
|
||||
int cell_index = ecl_rft_node_lookup_ijk( rft_refcase_node ,
|
||||
int_vector_iget(i_values,nobs) ,
|
||||
int_vector_iget(j_values,nobs) ,
|
||||
int_vector_iget(k_values,nobs) ); //lookup cell
|
||||
|
||||
if(cell_index > -1){
|
||||
double pressure_value = ecl_rft_node_iget_pressure( rft_refcase_node , cell_index); // Pressure
|
||||
const ecl_rft_cell_type * cell = ecl_rft_node_lookup_ijk( rft_refcase_node ,
|
||||
int_vector_iget(i_values,nobs) ,
|
||||
int_vector_iget(j_values,nobs) ,
|
||||
int_vector_iget(k_values,nobs) );
|
||||
|
||||
if (cell) {
|
||||
double pressure_value = ecl_rft_cell_get_pressure( cell );
|
||||
double_vector_append(RFT_refcase, pressure_value);
|
||||
bool_vector_append(refcase_has_data, true);
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
double_vector_append(RFT_refcase, 0.0);
|
||||
bool_vector_append(refcase_has_data, false);
|
||||
}
|
||||
@@ -337,17 +343,19 @@ void enkf_tui_plot_RFT_simIn(enkf_main_type * enkf_main, path_fmt_type * runpath
|
||||
else{
|
||||
for( int nobs = 0; nobs < lines; nobs++){
|
||||
if( int_vector_iget(active,nobs) > -1){
|
||||
int cell_index = ecl_rft_node_lookup_ijk( rftnode , int_vector_iget(i_values,nobs), int_vector_iget(j_values,nobs),int_vector_iget(k_values,nobs) ); //lookup cell
|
||||
double pressure_value = ecl_rft_node_iget_pressure( rftnode , cell_index); // Pressure
|
||||
double_vector_iset(simulated_pressures,nobs , pressure_value);
|
||||
if(cell_index > -1)
|
||||
const ecl_rft_cell_type * cell = ecl_rft_node_lookup_ijk( rftnode ,
|
||||
int_vector_iget(i_values,nobs),
|
||||
int_vector_iget(j_values,nobs),
|
||||
int_vector_iget(k_values,nobs) ); //lookup cell
|
||||
if (cell) {
|
||||
double pressure_value = ecl_rft_cell_get_pressure( cell );
|
||||
double_vector_iset(simulated_pressures, nobs , pressure_value);
|
||||
bool_vector_iset(has_data, nobs, true);
|
||||
else
|
||||
} else {
|
||||
double_vector_iset(simulated_pressures,nobs ,0.0);
|
||||
bool_vector_iset(has_data, nobs, false);
|
||||
}
|
||||
else {
|
||||
double_vector_iset(simulated_pressures,nobs ,0.0);
|
||||
bool_vector_iset(has_data, nobs, false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user