# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of Sandia, LLC
# Under the terms of Contract DE-NA0003525 with National Technology and
# Engineering Solutions of Sandia, LLC, the U.S. Government retains certain
# rights in this software.
# ___________________________________________________________________________
#
# This module was originally developed as part of the IDAES PSE Framework
#
# Institute for the Design of Advanced Energy Systems Process Systems
# Engineering Framework (IDAES PSE Framework) Copyright (c) 2018-2019, by the
# software owners: The Regents of the University of California, through
# Lawrence Berkeley National Laboratory, National Technology & Engineering
# Solutions of Sandia, LLC, Carnegie Mellon University, West Virginia
# University Research Corporation, et al. All rights reserved.
#
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
"""
UI data objects for sharing data and settings between different parts of the UI.
"""
__author__ = "John Eslick"
import logging
from pyomo.common.collections import ComponentMap
from pyomo.contrib.viewer.qt import *
import pyomo.environ as pyo
_log = logging.getLogger(__name__)
[docs]
class UIDataNoUi(object):
"""
This is the UIData object minus the signals. This is the base class for
UIData. The class is split this way for testing when PyQt is not available.
"""
[docs]
def __init__(self, model=None, model_var_name_in_main=None):
"""
This class holds the basic UI setup, but doesn't depend on Qt. It
shouldn't really be used except for testing when Qt is not available.
Args:
model: The Pyomo model to view
model_var_name_in_main: if this is set, check that the model variable
which points to a model object in __main__ has the same id when
the UI is refreshed due to a command being executed in jupyter
notebook or QtConsole, if not the same id, then update the model
Since the model viewer is not necessarily pointed at a model in the
__main__ namespace only set this if you want the model to auto
update. Since the model selector dialog lets you choose models
from the __main__ namespace it sets this when you select a model.
This is useful if you run a script repeatedly that replaces a model
preventing you from looking at a previous version of the model.
"""
super().__init__()
self._model = None
self.model_var_name_in_main = model_var_name_in_main
self._begin_update = False
self.value_cache = ComponentMap()
self.value_cache_units = ComponentMap()
self.begin_update()
self.model = model
self.end_update()
[docs]
def begin_update(self):
"""
Lets the model setup be changed without emitting the updated signal
until the end_update function is called.
"""
self._begin_update = True
[docs]
def end_update(self, emit=True):
"""
Sets the begin update flag to false. Needs to be overloaded to also
emit an update signal in the full UIData class
"""
self._begin_update = False
[docs]
def emit_update(self):
"""
Don't forget to overloaded this, not raising a NotImplementedError so
tests can run without Qt
"""
pass
[docs]
def emit_exec_refresh(self):
"""
Don't forget to overloaded this, not raising a NotImplementedError so
tests can run without Qt
"""
pass
@property
def model(self):
return self._model
@model.setter
def model(self, value):
self._model = value
self.value_cache = ComponentMap()
self.value_cache_units = ComponentMap()
self.emit_update()
def calculate_constraints(self):
for o in self.model.component_data_objects(pyo.Constraint, active=True):
try:
self.value_cache[o] = pyo.value(o.body, exception=False)
except ZeroDivisionError:
self.value_cache[o] = "Divide_by_0"
self.emit_exec_refresh()
def calculate_expressions(self):
for o in self.model.component_data_objects(pyo.Expression, active=True):
try:
self.value_cache[o] = pyo.value(o, exception=False)
except ZeroDivisionError:
self.value_cache[o] = "Divide_by_0"
try:
self.value_cache_units[o] = str(pyo.units.get_units(o))
except:
# If units aren't obtainable for whatever reason, let it go.
pass
self.emit_exec_refresh()
if not available:
class UIData(UIDataNoUi):
pass
else:
[docs]
class UIData(UIDataNoUi, QtCore.QObject):
updated = Signal()
exec_refresh = Signal()
[docs]
def __init__(self, *args, **kwargs):
"""
This class holds the basic UI setup
Args:
model: The Pyomo model to view
"""
super().__init__(*args, **kwargs)
[docs]
def end_update(self, emit=True):
"""
Start automatically emitting update signal again when properties
are changed and emit update for changes made between begin_update
and end_update
"""
super().end_update(emit=emit)
if emit:
self.emit_update()
[docs]
def emit_update(self):
if not self._begin_update:
self.updated.emit()
[docs]
def emit_exec_refresh(self):
self.exec_refresh.emit()