Skip to content

Commit

Permalink
* Add modifiers, support for custom functions and support for paralle…
Browse files Browse the repository at this point in the history
…l subsystems, #77
  • Loading branch information
MBaranskiEBC committed Dec 8, 2019
1 parent 3de3df2 commit ceb43be
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 86 deletions.
4 changes: 2 additions & 2 deletions pyDMPC/ControlFramework/ControlledSystem.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import Init
import pyads

class PLCSys:

def __init__(self):
import pyads
self.plc_typ = pyads.PLCTYPE_REAL
self.ads_id = Init.ads_id
self.ads_port = Init.ads_port
self.connect()

def connect(self):
import pyads
self.contr_sys = pyads.Connection(self.ads_id, self.ads_port)
self.contr_sys.open()

Expand Down
23 changes: 12 additions & 11 deletions pyDMPC/ControlFramework/Experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,23 @@ def main():

sys.initialize()

try:
try:
for cur_time in range(0, 86400 , min_samp_inter):
sys.execute()
print(f"Time: {cur_time}")

sys.close_mod()
System.Bexmoc.close_cont_sys()
print("Success")

#try:
# try:
for cur_time in range(0, 86400 , min_samp_inter):
Init.custom()
sys.execute()
print(f"Time: {cur_time}")

sys.close_mod()
System.Bexmoc.close_cont_sys()
print("Success")
"""
except Exception as e:
sys.terminate()
print(getattr(e, 'message', repr(e)))
except KeyboardInterrupt:
sys.terminate()
print('Interrupted')

"""
if __name__=="__main__": main()
117 changes: 66 additions & 51 deletions pyDMPC/ControlFramework/Init.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
import time
import numpy as np
import requests
import scipy.io as sio

# Global paths
glob_lib_paths = [r'C:\Git\pyDMPC\pyDMPC\ModelicaModels\ModelicaModels',
r'C:\Git\modelica-buildings\Buildings',
r'C:\Git\AixLib-master\AixLib']
glob_res_path = r'C:\TEMP\dymola'
glob_dym_path = r'C:\Program Files\Dymola 2020\Modelica\Library\python_interface\dymola.egg'
glob_lib_paths = [r'D:\Git\pyDMPC\pyDMPC\ModelicaModels\ModelicaModels',
r'D:\Git\modelica-buildings\Buildings',
r'D:\Git\AixLib-master\AixLib']
glob_res_path = r'D:\TEMP'
glob_dym_path = r'C:\Program Files\Dymola 2018 FD01\Modelica\Library\python_interface\dymola.egg'

# Working directory
timestr = time.strftime("%Y%m%d_%H%M%S")
name_wkdir = r'pyDMPC_' + 'wkdir' + timestr

# Controlled system
contr_sys_typ = "Modelica"
ads_id = '5.59.199.202.1.1'
contr_sys_typ = "PLC"
ads_id = '5.53.34.234.1.1'
ads_port = 851
name_fmu = 'pyDMPCFMU_AHU.fmu'
orig_fmu_path = glob_res_path + '\\' + name_fmu
dest_fmu_path = glob_res_path + '\\' + name_wkdir + '\\' + name_fmu
time_incr = 120

# Number of subsystems
n = 2
n = 1

# States
inputs = [None for _ in range(n)]
Expand Down Expand Up @@ -51,8 +54,13 @@
command_names = [None for _ in range(n)]

# Modifiers
cost_fac = [None for _ in range(n)]
factors = [None for _ in range(n)]
cost_fac = [[1] for _ in range(n)]
state_factors = [[1] for _ in range(n)]
state_offsets = [[0] for _ in range(n)]
input_factors = [[1] for _ in range(n)]
input_offsets = [[0] for _ in range(n)]
output_factors = [[1] for _ in range(n)]
output_offsets = [[0] for _ in range(n)]

# Variation
min_var = [None for _ in range(n)]
Expand All @@ -69,55 +77,62 @@

# Subsystems
sys_id[0] = 0
name[0] = "Heater"
model_type[0] = "Scikit"
ups_neigh[0] = 1
input_names[0] = ["coolerTemperature.T"]
name[0] = "Hall-long"
model_type[0] = "Modelica"
#ups_neigh[0] = 2
#par_neigh[0] = [1]
input_names[0] = ["GVL.fAHUTempSUP"]
input_variables[0] = [r"variation.table[1, 2]"]
inputs[0] = [i for i in range(280, 325, 1)]
inputs[0] = [1]
#inputs[0] = [i for i in range(280, 325, 1)]
output_names[0] = ["supplyAirTemperature.T"]
set_points[0] = [303]
state_var_names[0] = ["heaterInitials[1].y"]
model_state_var_names[0] = ["mas1.k"]
mod_path[0] = "ModelicaModels.SubsystemModels.DetailedModels.Hall_long"
set_points[0] = [295]
state_var_names[0] = ["GVL.fAHUTempSUP"]
model_state_var_names[0] = ["volume.T_start"]
state_offsets[0] = [273]
#model_state_var_names[0] = ["AirVolumeFlow.k","volume.T_start", "concreteFloor.T"]
start[0] = 0.
stop[0] = 3600
incr[0] = 10.
opt_time[0] = 600
stop[0] = 2*24*3600
incr[0] = 100.
opt_time[0] = 6*3600
samp_time[0] = time_incr
lib_paths[0] = glob_lib_paths
res_path[0] = glob_res_path + "\\" + name_wkdir
dym_path[0] = glob_dym_path
mod_path[0] = f'{glob_res_path}\\heater'
command_names[0] = ["valveHeater"]
command_variables[0] = ["decisionVariables.table[1, 2]"]
commands[0] = [[i, i] for i in range(0, 100, 5)]
command_names[0] = ["GVL.fTemperatureAmbientADS"]
command_variables[0] = [r"decisionVariables.table[1, 2]"]
commands[0] = [[i] for i in range(8, 14, 3)]
traj_points[0] = []
traj_var[0] = []
cost_fac[0] = [0.1, 0.0, 1.0]

sys_id[1] = 1
name[1] = "Cooler"
model_type[1] = "Scikit"
downs_neigh[1] = [0]
input_names[1] = ["preHeaterTemperature.T"]
input_variables[1] = [r"variation.table[1, 2]"]
inputs[1] = [i for i in range(280, 325, 1)]
output_names[1] = ["supplyAirTemperature.T"]
set_points[1] = [303]
state_var_names[1] = ["coolerInitials[1].y"]
model_state_var_names[1] = ["hex.ele[1].mas.T"]
start[1] = 0.
stop[1] = 3600.
incr[1] = 10.
opt_time[1] = 600
samp_time[1] = time_incr
lib_paths[1] = glob_lib_paths
res_path[1] = glob_res_path + "\\" + name_wkdir
dym_path[1] = glob_dym_path
mod_path[1] = f'{glob_res_path}\\cooler'
command_names[1] = ["valveCooler"]
command_variables[1] = ["decisionVariables.table[1, 2]"]
commands[1] = [[i, i] for i in range(0, 100, 5)]
traj_points[1] = []
traj_var[1] = []
cost_fac[1] = [0.0, 1.0, 0]
def custom():
key = np.loadtxt(glob_res_path + "\\" + "key.txt", str)
url = (r"http://api.openweathermap.org/data/2.5/forecast?id=6553047&APPID=" +
str(key))

r = requests.get(url).json()

r = r['list']

for k in range(0,1000):

try:
dic = r[k]
tim = dic['dt']

mai = dic['main']
temp = float(mai['temp'])

if k == 0:
start_tim = tim
values = [[0.0,temp]]
else:
values += [[tim-start_tim,temp]]

except:
break

sio.savemat((res_path[0] +
'\\' + 'weather.mat'),{'InputTable' : np.array(values)})
18 changes: 16 additions & 2 deletions pyDMPC/ControlFramework/Modeling.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,12 @@ class Modifs:
"""

def __init__(self, sys_id):
self.factors = Init.factors[sys_id]
self.state_factors = Init.state_factors[sys_id]
self.state_offsets = Init.state_offsets[sys_id]
self.input_factors = Init.input_factors[sys_id]
self.input_offsets = Init.input_offsets[sys_id]
self.output_factors = Init.output_factors[sys_id]
self.output_offsets = Init.output_offsets[sys_id]


class Model:
Expand All @@ -149,6 +154,7 @@ def __init__(self, sys_id):
self.states = States(sys_id)
self.times = Times(sys_id)
self.paths = Paths(sys_id)
self.modifs = Modifs(sys_id)


class ModelicaMod(Model):
Expand Down Expand Up @@ -190,6 +196,7 @@ def del_dymola(cls):
def translate(self):
ModelicaMod.dymola.cd(self.paths.res_path)
print(self.paths.res_path)
print(self.paths.mod_path)
check = ModelicaMod.dymola.translateModel(self.paths.mod_path)
print("Translation successful " + str(check))

Expand All @@ -203,13 +210,20 @@ def simulate(self):
for i in range(1)]

times = [i*600 for i in range(1)]

print(times)
print(self.states.state_vars)
print(self.states.inputs)
print(self.states.commands)


if self.states.input_variables[0] == "external":
initialNames = (self.states.command_variables +
self.states.model_state_var_names + time_variables)
initialValues = (self.states.commands + self.states.state_vars + times)
else:
initialValues = (self.states.commands + self.states.inputs +
initialValues = (self.states.commands +
self.states.inputs +
self.states.state_vars + times)

initialNames = (command_variables +
Expand Down
18 changes: 10 additions & 8 deletions pyDMPC/ControlFramework/Subsystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ def interp_minimize(self, interp):

states = self.get_state_vars()
if states != []:
self.model.states.state_vars = states[0]
self.model.states.state_vars = states

if self.model.states.input_variables[0] != "external":
if self.inputs == []:
Expand Down Expand Up @@ -226,9 +226,9 @@ def interp_minimize(self, interp):
self.coup_vars_send = opt_outputs
self.command_send = opt_command

else:
self.coup_vars_send = opt_outputs[0]
self.command_send = opt_command[0]
#else:
# self.coup_vars_send = opt_outputs[0]
# self.command_send = opt_command[0]


def calc_cost(self, command, outputs):
Expand Down Expand Up @@ -288,8 +288,9 @@ def get_inputs(self):
inputs = []

if self.model.states.input_variables is not None:
for nam in self.model.states.input_names:
inputs.append(System.Bexmoc.read_cont_sys(nam))
for i, nam in enumerate(self.model.states.input_names):
inputs.append(System.Bexmoc.read_cont_sys(nam) +
self.model.modifs.input_offsets[i])

self.model.states.inputs = inputs

Expand All @@ -298,8 +299,9 @@ def get_state_vars(self):
states = []

if self.model.states.state_var_names is not None:
for nam in self.model.states.state_var_names:
states.append(System.Bexmoc.read_cont_sys(nam))
for i, nam in enumerate(self.model.states.state_var_names):
states.append(System.Bexmoc.read_cont_sys(nam) +
self.model.modifs.state_offsets[i])

return states

Expand Down
6 changes: 3 additions & 3 deletions pyDMPC/ControlFramework/System.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,9 @@ def write_cont_sys(cls, datapoint, value):
The the value of the data point to be written
"""

#print("datapoint: " + str(datapoint))
#print("value: " + str(value))
cls.contr_sys.write(datapoint, value)
print("datapoint: " + str(datapoint))
print("value: " + str(value))
#cls.contr_sys.write(datapoint, value)

@classmethod
def proceed(cls, cur_time, incr):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
within ModelicaModels.SubsystemModels.DetailedModels;
model Hall_long
extends ModelicaModels.SubsystemModels.DetailedModels.BaseClasses.HallBaseClass;
extends ModelicaModels.SubsystemModels.DetailedModels.BaseClasses.HallBaseClass(
decisionVariables(tableOnFile=false, table=[0.0,0.0]), weather(
table=[0.0,293],
tableOnFile=true,
smoothness=Modelica.Blocks.Types.Smoothness.LinearSegments,
fileName="../weather.mat"));

Modelica.Blocks.Sources.Constant Tnormal(k=273 + 22)
"Average Temperature of supply air or forecast"
Expand All @@ -10,20 +15,24 @@ model Hall_long
Modelica.Blocks.Sources.RealExpression realExpression(y=35 -
decisionVariables.y[1])
annotation (Placement(transformation(extent={{-106,-110},{-50,-92}})));
Modelica.Thermal.HeatTransfer.Components.ThermalConductor FloorConductor(G=10000)
"Conducts heat from floor to air"
annotation (Placement(transformation(extent={{98,-160},{118,-140}})));
Modelica.Blocks.Sources.CombiTimeTable variation(
extrapolation=Modelica.Blocks.Types.Extrapolation.HoldLastPoint,
tableName="tab1",
smoothness=Modelica.Blocks.Types.Smoothness.ConstantSegments,
columns={2},
fileName="decisionVariables.mat",
tableOnFile=false,
table=[0.0,0.0]) "Table with decision variables" annotation (Placement(
transformation(
extent={{-10,-10},{10,10}},
rotation=0,
origin={-130,-32})));
equation
connect(Tnormal.y, IntakeAirSource.T_in) annotation (Line(points={{-139,20},{
-120,20},{-120,24},{-102,24}}, color={0,0,127}));
connect(solar.y, SolarShare.u)
annotation (Line(points={{21,-40},{32.8,-40}}, color={0,0,127}));
connect(realExpression.y, waterTemperature.Celsius) annotation (Line(points={
{-47.2,-101},{-37.6,-101},{-37.6,-100},{-29.2,-100}}, color={0,0,127}));
connect(FloorConductor.port_a, concreteFloor.port)
annotation (Line(points={{98,-150},{70,-150},{70,-144}}, color={191,0,0}));
connect(volume.heatPort, FloorConductor.port_b) annotation (Line(points={{90,
-80},{80,-80},{80,-124},{134,-124},{134,-150},{118,-150}}, color={191,
0,0}));
annotation (experiment(StopTime=172800, Interval=10));
end Hall_long;

0 comments on commit ceb43be

Please sign in to comment.