Skip to content

Commit

Permalink
pysd bugfix
Browse files Browse the repository at this point in the history
makes workbench compatible with latest version of pysd
  • Loading branch information
quaquel committed Dec 15, 2023
1 parent 6dc6018 commit 0e0026b
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 104 deletions.
12 changes: 6 additions & 6 deletions ema_workbench/connectors/pysd_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,20 @@ def mdl_file(self, mdl_file):
if not os.path.isfile(mdl_file):
raise ValueError("mdl_file not found")

mdl_file = os.path.abspath(mdl_file)

# Todo: replace when pysd adds an attribute for the .py filename
self.py_model_name = mdl_file.replace(".mdl", ".py")
self._mdl_file = mdl_file

def __init__(self, name=None, mdl_file=None):
self.mdl_file = mdl_file
if name is None:
name = pysd.utils.make_python_identifier(mdl_file)[0]
name = name.replace("_", "")
def __init__(self, name, mdl_file=None):
super().__init__(name)
self.mdl_file = mdl_file
self.model = None

@method_logger(__name__)
def model_init(self, policy, **kwargs):
AbstractModel.model_init(self, policy, **kwargs)
super().model_init(policy)

# TODO:: should be updated only if mdl file has been changed
# or if not initialized
Expand Down
2 changes: 1 addition & 1 deletion ema_workbench/examples/example_pysd_teacup.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

mdl_file = "./models/pysd/Teacup.mdl"

model = PysdModel(mdl_file=mdl_file)
model = PysdModel("teacup", mdl_file=mdl_file)

model.uncertainties = [RealParameter("Room Temperature", 33, 120)]
model.outcomes = [TimeSeriesOutcome("Teacup Temperature")]
Expand Down
197 changes: 100 additions & 97 deletions ema_workbench/examples/models/pysd/Teacup.py
Original file line number Diff line number Diff line change
@@ -1,140 +1,143 @@
"""
Python model "Teacup.py"
Translated using PySD version 0.9.0
Python model 'Teacup.py'
Translated using PySD
"""

from pysd.py_backend import functions
from pysd.py_backend.functions import cache

_subscript_dict = {}

_namespace = {
"TIME": "time",
"Time": "time",
"Characteristic Time": "characteristic_time",
"Heat Loss to Room": "heat_loss_to_room",
"Room Temperature": "room_temperature",
"Teacup Temperature": "teacup_temperature",
"FINAL TIME": "final_time",
"INITIAL TIME": "initial_time",
"SAVEPER": "saveper",
"TIME STEP": "time_step",
}
from pathlib import Path
import numpy as np

__pysd_version__ = "0.9.0"
from pysd.py_backend.statefuls import Integ
from pysd import Component

__pysd_version__ = "3.12.0"

@cache("run")
def characteristic_time():
"""
Real Name: Characteristic Time
Original Eqn: 10
Units: Minutes
Limits: (None, None)
Type: constant
__data = {"scope": None, "time": lambda: 0}

_root = Path(__file__).parent

"""
return 10

component = Component()

@cache("step")
def heat_loss_to_room():
"""
Real Name: Heat Loss to Room
Original Eqn: (Teacup Temperature - Room Temperature) / Characteristic Time
Units: Degrees/Minute
Limits: (None, None)
Type: component
This is the rate at which heat flows from the cup into the room. We can
ignore it at this point.
"""
return (teacup_temperature() - room_temperature()) / characteristic_time()
#######################################################################
# CONTROL VARIABLES #
#######################################################################


@cache("run")
def room_temperature():
"""
Real Name: Room Temperature
Original Eqn: 70
Units:
Limits: (None, None)
Type: constant
_control_vars = {
"initial_time": lambda: 0,
"final_time": lambda: 30,
"time_step": lambda: 0.125,
"saveper": lambda: time_step(),
}


"""
return 70
def _init_outer_references(data):
for key in data:
__data[key] = data[key]


@cache("step")
def teacup_temperature():
@component.add(name="Time")
def time():
"""
Real Name: Teacup Temperature
Original Eqn: INTEG ( -Heat Loss to Room, 180)
Units: Degrees
Limits: (None, None)
Type: component
Current time of the model.
"""
return integ_teacup_temperature()
return __data["time"]()


@cache("run")
@component.add(name="FINAL TIME", units="Minute", comp_type="Constant", comp_subtype="Normal")
def final_time():
"""
Real Name: FINAL TIME
Original Eqn: 30
Units: Minute
Limits: (None, None)
Type: constant
The final time for the simulation.
"""
return 30
return __data["time"].final_time()


@cache("run")
@component.add(name="INITIAL TIME", units="Minute", comp_type="Constant", comp_subtype="Normal")
def initial_time():
"""
Real Name: INITIAL TIME
Original Eqn: 0
Units: Minute
Limits: (None, None)
Type: constant
The initial time for the simulation.
"""
return 0
return __data["time"].initial_time()


@cache("step")
@component.add(
name="SAVEPER",
units="Minute",
limits=(0.0, np.nan),
comp_type="Auxiliary",
comp_subtype="Normal",
depends_on={"time_step": 1},
)
def saveper():
"""
Real Name: SAVEPER
Original Eqn: TIME STEP
Units: Minute
Limits: (0.0, None)
Type: component
The frequency with which output is stored.
"""
return time_step()
return __data["time"].saveper()


@cache("run")
@component.add(
name="TIME STEP",
units="Minute",
limits=(0.0, np.nan),
comp_type="Constant",
comp_subtype="Normal",
)
def time_step():
"""
Real Name: TIME STEP
Original Eqn: 0.125
Units: Minute
Limits: (0.0, None)
Type: constant
The time step for the simulation.
"""
return 0.125
return __data["time"].time_step()


#######################################################################
# MODEL VARIABLES #
#######################################################################


@component.add(
name="Characteristic Time",
units="Minutes",
comp_type="Constant",
comp_subtype="Normal",
)
def characteristic_time():
return 10


@component.add(
name="Heat Loss to Room",
units="Degrees/Minute",
comp_type="Auxiliary",
comp_subtype="Normal",
depends_on={
"teacup_temperature": 1,
"room_temperature": 1,
"characteristic_time": 1,
},
)
def heat_loss_to_room():
"""
This is the rate at which heat flows from the cup into the room. We can ignore it at this point.
"""
return (teacup_temperature() - room_temperature()) / characteristic_time()


@component.add(name="Room Temperature", comp_type="Constant", comp_subtype="Normal")
def room_temperature():
return 70


@component.add(
name="Teacup Temperature",
units="Degrees",
comp_type="Stateful",
comp_subtype="Integ",
depends_on={"_integ_teacup_temperature": 1},
other_deps={"_integ_teacup_temperature": {"initial": {}, "step": {"heat_loss_to_room": 1}}},
)
def teacup_temperature():
return _integ_teacup_temperature()


integ_teacup_temperature = functions.Integ(lambda: -heat_loss_to_room(), lambda: 180)
_integ_teacup_temperature = Integ(
lambda: -heat_loss_to_room(), lambda: 180, "_integ_teacup_temperature"
)

0 comments on commit 0e0026b

Please sign in to comment.