Skip to content

Commit

Permalink
Changes towards publishing the package on OpenSource. Still version 0…
Browse files Browse the repository at this point in the history
….1, but suitable to try out and a basis for further discussion
  • Loading branch information
eisDNV committed Jun 30, 2024
1 parent 5bdec44 commit 8e61d30
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 95 deletions.
91 changes: 48 additions & 43 deletions case_study/case.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ def _disect_at_time(self, txt: str, value: PyVal | list[PyVal] | None = None) ->
assert len(pre), f"'{txt}' is not allowed as basis for _disect_at_time"
if not len(at): # no @time spec
if self.name == "results" or (isinstance(value, str) and value.lower() == "novalue"):
return (pre, "get", self.special["stopTime"])
return (pre, "get", self.special["stopTime"]) # report final value
else:
msg = f"Value required for 'set' in _disect_at_time('{txt}','{self.name}','{value}')"
assert Case._num_elements(value), msg
Expand Down Expand Up @@ -377,14 +377,14 @@ def read_spec_item(self, key: str, value: PyVal | list[PyVal] | None = None):
_inst = self.cases.simulator.component_id_from_name(inst)
if not self.cases.simulator.allowed_action("get", _inst, tuple(var_refs), 0):
raise AssertionError(self.cases.simulator.message) from None
elif at_time_type == "get" or at_time_arg == -1:
elif at_time_type == "get" or at_time_arg == -1: # normal get or step without time spec
self.add_action(
"get",
self.cases.simulator.get_variable_value,
(_inst, cvar_info["type"], tuple(var_refs)),
at_time_arg if at_time_arg <= 0 else at_time_arg * self.cases.timefac,
)
else: # step actions
else: # step actions with specified interval
for time in np.arange(start=at_time_arg, stop=self.special["stopTime"], step=at_time_arg):
self.add_action(
time,
Expand Down Expand Up @@ -529,58 +529,64 @@ def run(self, dump: bool | str = False):
False: only as string, True: json file with automatic file name, str: explicit filename.json
"""

def do_actions(_t: float, _a, _iter, time: int, results: dict | None = None):
while time >= _t: # issue the _a - actions
if len(_a):
for a in _a:
res = a()
if results is not None: # get action. Store result
self._results_add(results, time / self.cases.timefac, a.args[0], a.args[1], a.args[2], res)
try:
_t, _a = next(_iter)
except StopIteration:
_t, _a = 10 * tstop, []
return (_t, _a)

# Note: final actions are included as _get at end time
# print("ACTIONS_SET", settings['actions_set')
# print("ACTIONS_GET", settings['actions_get')
# print("ACTIONS_STEP", settings['actions_step')
act_step = self.act_get.get(-1, None)
tstart = int(self.special["startTime"] * self.cases.timefac)
tstart : int = int(self.special["startTime"] * self.cases.timefac)
time = tstart
tstop = int(self.special["stopTime"] * self.cases.timefac)
tstep = int(self.special["stepSize"] * self.cases.timefac)
tstop : int = int(self.special["stopTime"] * self.cases.timefac)
tstep : int = int(self.special["stepSize"] * self.cases.timefac)

set_iter = self.act_set.items().__iter__() # iterator over set actions => time, action_list
try:
t_set, a_set = next(set_iter)
except StopIteration:
t_set, a_set = (float("inf"), []) # satisfy linter
get_iter = self.act_get.items().__iter__() # iterator over get actions => time, action_list
try:
t_get, a_get = next(get_iter)
except StopIteration:
t_get, a_get = (tstop + 1, [])
act_step = None
while True:
try:
t_get, a_get = next(get_iter)
except StopIteration:
t_get, a_get = (tstop + 1, [])
if t_get < 0:
act_step = a_get
else:
break
results = self._results_make_header()
print(f"BEFORE LOOP. SET: {time}:{t_set}")
for a in a_set:
print(f" {a.args[2]}={a.args[3]}")
print(f"BEFORE LOOP.GET: {time}:{t_get}")
for a in a_get:
print(f" {a.args[2]}={a()}")
while time < tstop:
print(f"CASE.run SET, {time}-{tstop}: {t_set}, {a_set}")
while time >= t_set: # issue the set actions
if len(a_set):
for a in a_set:
print(f"@{time}. Set actions type:{a.args[1]} refs:{a.args[2]}, values:{a.args[3]}")
a()
try:
t_set, a_set = next(set_iter)
except StopIteration:
t_set, a_set = 10 * tstop, []
print(f"@{time}. Next set actions: {t_set}, {a_set}")

# print(f"BEFORE LOOP. SET: {time}:{t_set}")
# for a in a_set:
# print(f" {a.func}, {a.args[2]}={a.args[3]}")
# print(f"BEFORE LOOP.GET: {time}:{t_get}")
# for a in a_get:
# print(f" {a.args[2]}={a()}")
# print(f"BEFORE LOOP.STEP: ")
# for a in act_step:
# print(f" {a}") #{a.args[2]}={a()}")
while True:
t_set, a_set = do_actions(t_set, a_set, set_iter, time)

if time <= tstart: # issue the current get actions (initial values)
self.cases.simulator.simulator.simulate_until(1) # one nano time step (ensure initialization)
t_get, a_get = do_actions(t_get, a_get, get_iter, time, results)

time += tstep
if time > tstop:
break
self.cases.simulator.simulator.simulate_until(time)

while time >= t_get: # issue the current get actions
print(f"CASE.run GET@{time}, {t_get}")
for a in a_get:
print(f"CASE.GET args@{time}: {a.args[2]}={a()}")
self._results_add(results, time / self.cases.timefac, a.args[0], a.args[1], a.args[2], a())
try:
t_get, a_get = next(get_iter)
except StopIteration:
t_get, a_get = 10 * tstop, []
t_get, a_get = do_actions(t_get, a_get, get_iter, time, results) # issue the current get actions

if act_step is not None: # there are step-always actions
for a in act_step:
Expand All @@ -589,7 +595,6 @@ def run(self, dump: bool | str = False):

self.cases.simulator.reset()
if dump:
print(f"saving to file {dump}")
self._results_save(results, dump)
self.results = results
return results
Expand Down
13 changes: 9 additions & 4 deletions case_study/simulator_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@
from libcosimpy.CosimManipulator import CosimManipulator # type: ignore
from libcosimpy.CosimObserver import CosimObserver # type: ignore

# from component_model.model import Model, model_from_fmu
# from component_model.variable import Variable

# type definitions
PyVal: TypeAlias = str | float | int | bool # simple python types / Json5 atom
Json5: TypeAlias = dict[str, "Json5Val"] # Json5 object
Expand Down Expand Up @@ -100,7 +97,7 @@ def __init__(
def path(self):
return self.sysconfig.resolve().parent if self.sysconfig is not None else None

def reset(self):
def reset(self): # , cases:Cases):
"""Reset the simulator interface, so that a new simulation can be run."""
assert isinstance(self.sysconfig, Path), "Simulator resetting does not work with explicitly supplied simulator."
assert self.sysconfig.exists(), "Simulator resetting does not work with explicitly supplied simulator."
Expand All @@ -112,6 +109,7 @@ def reset(self):
self.simulator = CosimExecution.from_osp_config_file(str(self.sysconfig))
assert self.simulator.add_manipulator(manipulator=self.manipulator), "Could not add manipulator object"
assert self.simulator.add_observer(observer=self.observer), "Could not add observer object"
# for case in cases:

def _simulator_from_config(self, file: Path):
"""Instantiate a simulator object through the a suitable configuration file.
Expand Down Expand Up @@ -244,6 +242,13 @@ def accept_as_alias(org: str) -> bool:
# var.append(sv)
return tuple(var)

def is_output_var(self, comp: int, ref: int) -> bool:
for idx in range(self.simulator.num_slave_variables(comp)):
struct = self.simulator.slave_variables(comp)[idx]
if struct.reference == ref:
return struct.causality == 2
return False

def get_variables(self, comp: str | int, single: int | str | None = None, as_numbers: bool = True) -> dict:
"""Get the registered variables for a given component from the simulator.
Expand Down
26 changes: 14 additions & 12 deletions tests/data/BouncingBall0/BouncingBall.cases
Original file line number Diff line number Diff line change
Expand Up @@ -14,32 +14,34 @@ variables : {
base : {
description : "Variable settings for the base case. All other cases are based on that",
spec: {
stepSize : 0.1,
stepSize : 0.01,
stopTime : '3',
g : -9.81,
e : 0.71,
e : 1.0,
h : 1.0,
}},
case1 : {
restitution : {
description : "Smaller coefficient of restitution e",
spec: {
e : 0.35,
e : 0.5,
}},
case2 : {
description : "Based case1 (e change), change also the gravity g",
parent : 'case1',
restitutionAndGravity : {
description : "Based restitution (e change), change also the gravity g",
parent : 'restitution',
spec : {
g : -1.5
}},
case3 : {
description : "Related directly to base case, larger e",
gravity : {
description : "Gravity like on the moon",
spec : {
e : 1.4
g : -1.5
}},
results : {
spec : [
e@0.0,
g@0.0,
h@0.0,
h@step,
v@1.0,
e,
g,
]}
}
Binary file modified tests/data/MobileCrane/MobileCrane.fmu
Binary file not shown.
Loading

0 comments on commit 8e61d30

Please sign in to comment.