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:
Jacob Støren
2013-08-26 13:56:42 +02:00
parent 64c234d988
commit b63f51921d
250 changed files with 9280 additions and 4701 deletions

View File

@@ -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_())

View File

@@ -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)

View File

@@ -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.

View File

@@ -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())

View File

@@ -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.

View File

@@ -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()

View File

@@ -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)

View File

@@ -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()

View File

@@ -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()

View File

@@ -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.

View File

@@ -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

View File

@@ -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!"

View File

@@ -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)

View File

@@ -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()

View File

@@ -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.

View File

@@ -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()

View File

@@ -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()

View File

@@ -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]

View File

@@ -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()

View File

@@ -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

View File

@@ -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)

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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.

View File

@@ -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)

View File

@@ -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

View 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()

View File

@@ -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.

View File

@@ -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)

View File

@@ -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

View File

@@ -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.

View File

@@ -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)

View File

@@ -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

View File

@@ -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())

View File

@@ -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

View File

@@ -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()

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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")

View File

@@ -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()

View File

@@ -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

View File

@@ -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()

View File

@@ -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.

View File

@@ -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)

View File

@@ -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())

View File

@@ -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()

View File

@@ -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()

View File

@@ -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.

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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())

View File

@@ -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 ""

View File

@@ -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))

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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())

View File

@@ -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()))

View File

@@ -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

View File

@@ -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

View File

@@ -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 ""

View File

@@ -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);
}
}
}
}