def simulate_multiple_fmus(): """Simulate one CYMDIST FMU coupled to a GridDyn FMU. """ cymdist=load_fmu("CYMDIST.fmu", log_level=7) gridyn=load_fmu("GridDyn.fmu", log_level=7) models = [cymdist, gridyn] connections = [(gridyn, "VMAG_A", cymdist, "VMAG_A"), (gridyn, "VMAG_B", cymdist, "VMAG_B"), (gridyn, "VMAG_C", cymdist, "VMAG_C"), (gridyn, "VANG_A", cymdist, "VANG_A"), (gridyn, "VANG_B", cymdist, "VANG_B"), (gridyn, "VANG_C", cymdist, "VANG_C"), (cymdist, "KWA_800032440", gridyn, "KWA_800032440"), (cymdist, "KWB_800032440", gridyn, "KWB_800032440"), (cymdist, "KWC_800032440", gridyn, "KWC_800032440"), (cymdist, "KVARA_800032440", gridyn, "KVARA_800032440"), (cymdist, "KVARB_800032440", gridyn, "KVARB_800032440"), (cymdist, "KVARC_800032440", gridyn, "KVARC_800032440"),] coupled_simulation = Master (models, connections) opts=coupled_simulation.simulate_options() opts['step_size']=1.0 opts['logging']=True res=coupled_simulation.simulate(options=opts, start_time=0.0, final_time=1.0)
def load(self, fmu_path, output_dir): """Load the FMU for continued simulation in :meth:`continue_run`. """ import pyfmi if 'log_level' in self._options: self.fmu = pyfmi.load_fmu(fmu_path, log_level=self.log_level) else: self.fmu = pyfmi.load_fmu(fmu_path) # Initialize the fmu, only call setup_experiment for FMUs 2.0 try: self.fmu.setup_experiment() version = 2 except AttributeError: version = 1 self.fmu.initialize() # Copy the log file to the result directory log = '' if version == 1: log = self.fmu.get_identifier() if version == 2: log = self.fmu.get_name() log += '_log.txt' source = os.path.join(os.getcwd(), log) destination = os.path.join(output_dir, 'log%i.txt' % self.interval) move(source, destination)
def simulate_cymdist_griddyn_fmus(): """Simulate one CYMDIST FMU coupled to a dummy griddyn FMU. """ # Parameters which will be arguments of the function start_time = 0.0 stop_time = 0.1 step_size = 0.1 # Path to configuration file path_config="Z:\\thierry\\proj\\cyder_repo\\NO_SHARING\\CYMDIST\\config.json" cymdist_con_val_str = bytes(path_config, 'utf-8') cymdist=load_fmu("../fmus/CYMDIST/CYMDIST.fmu", log_level=7) griddyn=load_fmu("../fmus/griddyn/griddyn14bus.fmu", log_level=7) models = [cymdist, griddyn] connections = [(griddyn, "Bus11_VA", cymdist, "VMAG_A"), (griddyn, "Bus11_VB", cymdist, "VMAG_B"), (griddyn, "Bus11_VC", cymdist, "VMAG_C"), (griddyn, "Bus11_VAngleA", cymdist, "VANG_A"), (griddyn, "Bus11_VAngleB", cymdist, "VANG_B"), (griddyn, "Bus11_VAngleC", cymdist, "VANG_C"), (cymdist, "IA", griddyn, "Bus11_IA"), (cymdist, "IB", griddyn, "Bus11_IB"), (cymdist, "IC", griddyn, "Bus11_IC"), (cymdist, "IAngleA", griddyn, "Bus11_IAngleA"), (cymdist, "IAngleB", griddyn, "Bus11_IAngleB"), (cymdist, "IAngleC", griddyn, "Bus11_IAngleC")] coupled_simulation = Master (models, connections) opts=coupled_simulation.simulate_options() opts['step_size']=step_size # Get the configuration file cymdist_con_val_ref = cymdist.get_variable_valueref("_configurationFileName") cymdist.set("_saveToFile", 0) cymdist.set_string([cymdist_con_val_ref], [cymdist_con_val_str]) # Set the communication step size cymdist.set("_communicationStepSize", step_size) # Set the value of the multiplier griddyn.set('multiplier', 3.0) # Run simulation start = datetime.now() res=coupled_simulation.simulate(options=opts, start_time=start_time, final_time=stop_time) end = datetime.now() print('This is the voltage value (VMAG_A) in Cymdist' + str(res[cymdist]['VMAG_A'])) print('This is the current value (IA) in Cymdist' + str(res[cymdist]['IA'])) print('Ran a coupled CYMDIST/GridDyn simulation in ' + str((end - start).total_seconds()) + ' seconds.')
def test_ExtFuncShared(self): """ Test compiling a model with external functions in a shared library. Real, Integer, and Boolean arrays. """ fmu_name = compile_fmu(self.cpath, self.fpath, compiler_options={'variability_propagation':True}) model = load_fmu(fmu_name) s_ceval = model.get('s') res = model.simulate() s_sim1 = res.final('s') fmu_name = compile_fmu(self.cpath, self.fpath, compiler_options={'variability_propagation':False}) model = load_fmu(fmu_name) res = model.simulate() s_sim2 = res.final('s') nose.tools.assert_equals(s_sim1, s_sim2)
def run_demo(with_plots=True): curr_dir = os.path.dirname(os.path.abspath(__file__)); class_name = 'ExtFunctions.transposeSquareMatrix' mofile = os.path.join(curr_dir, 'files', 'ExtFunctions.mo') # Compile and load model fmu_name = compile_fmu(class_name, mofile) model = load_fmu(fmu_name) # Simulate res = model.simulate() # Get result data b1_1 = res['b_out[1,1]'] b1_2 = res['b_out[1,2]'] b2_1 = res['b_out[2,1]'] b2_2 = res['b_out[2,2]'] t = res['time'] assert N.abs(res.final('b_out[1,1]') - 1) < 1e-6 assert N.abs(res.final('b_out[1,2]') - 3) < 1e-6 assert N.abs(res.final('b_out[2,1]') - 2) < 1e-6 assert N.abs(res.final('b_out[2,2]') - 4) < 1e-6 if with_plots: fig = p.figure() p.clf() p.plot(t, b1_1, label='b1_1') p.plot(t, b1_2, label='b1_2') p.plot(t, b2_1, label='b2_1') p.plot(t, b2_2, label='b2_2') p.legend() p.grid() p.show()
def run_demo(with_plots=True): """ This example shows how to simulate a system that contains switches. The example model is simple in the sense that no reinitialization of the variables is needed at the event points. """ curr_dir = os.path.dirname(os.path.abspath(__file__)); class_name = 'IfExpExamples.IfExpExample2' mofile = curr_dir+'/files/IfExpExamples.mo' fmu_name = compile_fmu(class_name, mofile) # Load the dynamic library and XML data model = load_fmu(fmu_name) # Simulate res = model.simulate(final_time=5.0) # Get results x = res['x'] u = res['u'] t = res['time'] assert N.abs(res.final('x') - 3.5297217) < 1e-3 assert N.abs(res.final('u') - (-0.2836621)) < 1e-3 if with_plots: fig = p.figure() p.plot(t, x, t, u) p.legend(('x','u')) p.show()
def simulate_single_griddyn_fmu(): """Simulate one griddyn FMU. """ # Parameters which will be arguments of the function start_time = 0.0 stop_time = 0.1 griddyn=load_fmu("../../../../NO_SHARING/griddyn/Test/griddyn.fmu", log_level=7) # Set the inputs opts=griddyn.simulate_options() opts['ncp']=1.0 # Set the model name reference to be completed in Python API griddyn.set("power", 10) # Run simulation start = datetime.now() res=griddyn.simulate(start_time=start_time, final_time=stop_time, options=opts) end = datetime.now() print('This is the time value ' + str(res['time'])) print('This is the load value ' + str(res['load'])) print('Ran a single GridDyn simulation in ' + str((end - start).total_seconds()) + ' seconds.')
def run_demo(with_plots=True): """ Demonstrates how to use an JMODELICA generated FMU for sensitivity calculations. """ curr_dir = os.path.dirname(os.path.abspath(__file__)); fmu_name = compile_fmu("Robertson", curr_dir+"/files/Robertson.mo") model = load_fmu(fmu_name) # Get and set the options opts = model.simulate_options() opts['sensitivities'] = ["p1","p2","p3"] opts['ncp'] = 400 #Simulate res = model.simulate(final_time=4, options=opts) dy1dp1 = res['dy1/dp1'] dy2dp1 = res['dy2/dp1'] time = res['time'] nose.tools.assert_almost_equal(dy1dp1[40], -0.35590, 3) nose.tools.assert_almost_equal(dy2dp1[40], 3.9026e-04, 6) if with_plots: plt.plot(time, dy1dp1, time, dy2dp1) plt.legend(('dy1/dp1', 'dy2/dp1')) plt.show()
def run_demo(with_plots=True): """ Demonstrates how to simulate an FMU with an input function. See also simulation_with_input.py """ fmu_name = O.path.join(path_to_fmus_me1,'SecondOrder.fmu') # Create input object input_object = ('u', N.cos) # Load the dynamic library and XML data model = load_fmu(fmu_name) # Simulate res = model.simulate(final_time=30, input=input_object, options={'ncp':3000}) x1_sim = res['x1'] x2_sim = res['x2'] u_sim = res['u'] time_sim = res['time'] assert N.abs(res.final('x1') - (-1.646485144)) < 1e-3 assert N.abs(res.final('x2')*1.e1 - (-7.30591626709)) < 1e-3 assert N.abs(res.final('u')*1.e1 - (1.54251449888)) < 1e-3 if with_plots: fig = p.figure() p.subplot(2,1,1) p.plot(time_sim, x1_sim, time_sim, x2_sim) p.subplot(2,1,2) p.plot(time_sim, u_sim) p.show()
def run_demo(with_plots=True): curr_dir = os.path.dirname(os.path.abspath(__file__)); class_name = 'ExtFunctions.addTwo' mofile = os.path.join(curr_dir, 'files', 'ExtFunctions.mo') # Compile and load model fmu_name = compile_fmu(class_name, mofile) model = load_fmu(fmu_name) # Simulate res = model.simulate() # Load result data sim_a = res['a'] sim_b = res['b'] sim_c = res['c'] t = res['time'] assert N.abs(res.final('a') - 1) < 1e-6 assert N.abs(res.final('b') - 2) < 1e-6 assert N.abs(res.final('c') - 3) < 1e-6 if with_plots: fig = p.figure() p.clf() p.subplot(3,1,1) p.plot(t, sim_a) p.subplot(3,1,2) p.plot(t, sim_b) p.subplot(3,1,3) p.plot(t, sim_c) p.show()
def run_demo(with_plots=True): """ An example on how to simulate a model using the DAE simulator. The result can be compared with that of sim_rlc.py which has solved the same problem using dymola. Also writes information to a file. """ curr_dir = os.path.dirname(os.path.abspath(__file__)); class_name = 'RLC_Circuit' mofile = curr_dir+'/files/RLC_Circuit.mo' fmu_name = compile_fmu(class_name, mofile) rlc = load_fmu(fmu_name) res = rlc.simulate(final_time=30) sine_y = res['sine.y'] resistor_v = res['resistor.v'] inductor1_i = res['inductor1.i'] t = res['time'] assert N.abs(res.final('resistor.v') - 0.159255008028) < 1e-3 if with_plots: fig = p.figure() p.plot(t, sine_y, t, resistor_v, t, inductor1_i) p.legend(('sine.y','resistor.v','inductor1.i')) p.show()
def run_demo(with_plots=True): """ Demonstrates how to simulate an FMU with an input function. See also simulation_with_input.py """ fmu_name = O.path.join(path_to_fmus, "SecondOrder.fmu") # Create input object input_object = ("u", N.cos) # Load the dynamic library and XML data model = load_fmu(fmu_name) # Simulate res = model.simulate(final_time=30, input=input_object, options={"ncp": 3000}) x1_sim = res["x1"] x2_sim = res["x2"] u_sim = res["u"] time_sim = res["time"] assert N.abs(x1_sim[-1] - (-1.646485144)) < 1e-3 assert N.abs(x2_sim[-1] * 1.0e1 - (-7.30591626709)) < 1e-3 assert N.abs(u_sim[-1] * 1.0e1 - (1.54251449888)) < 1e-3 if with_plots: fig = p.figure() p.subplot(2, 1, 1) p.plot(time_sim, x1_sim, time_sim, x2_sim) p.subplot(2, 1, 2) p.plot(time_sim, u_sim) p.show()
def f1(x): model = load_fmu(fmu_name) # We need to scale the inputs x down since they are scaled up # versions of a1 and a2 (x = scalefactor*[a1 a2]) a1 = x[0]/1e6 a2 = x[1]/1e6 # Set new values for a1 and a2 into the model model.set('qt.a1',a1) model.set('qt.a2',a2) # Create options object and set verbosity to zero to disable printouts opts = model.simulate_options() opts['CVode_options']['verbosity'] = 0 # Simulate model response with new parameters a1 and a2 res = model.simulate(input=(['u1','u2'],u),start_time=0.,final_time=60,options=opts) # Load simulation result x1_sim = res['qt.x1'] x2_sim = res['qt.x2'] t_sim = res['time'] # Evaluate the objective function y_meas = N.vstack((y1_meas,y2_meas)) y_sim = N.vstack((x1_sim,x2_sim)) obj = dfo.quad_err(t_meas,y_meas,t_sim,y_sim) return obj
def run_demo(with_plots=True, version="2.0"): # Compile model fmu_name = compile_fmu("IBPSA.Fluid.FixedResistances.Examples.PlugFlowPipe","C:\My_Libs\modelica-ibpsa\IBPSA") fmu_name=("IBPSA_Fluid_FixedResistances_Examples_PlugFlowPipe.fmu") #print("FMU compiled",fmu_name) print(fmu_name) # Load model pipe = load_fmu(fmu_name) print("FMU loaded", pipe) res = pipe.simulate(final_time=100) x1 = res['Tin.offset'] x2 = res['sou.m_flow'] t = res['time'] plt.figure(1) plt.plot(t, x1, t, x2) plt.legend(('Tin (K)','mdot (kg/s)')) plt.title('Pipe') plt.ylabel('y axis') plt.xlabel('Time (s)') plt.show()
def run_demo(with_plots=True): """ Distillation2 model """ curr_dir = os.path.dirname(os.path.abspath(__file__)); fmu_name = compile_fmu("JMExamples.Distillation.Distillation2", curr_dir+"/files/JMExamples.mo") dist2 = load_fmu(fmu_name) res = dist2.simulate(final_time=7200) # Extract variable profiles x16 = res['x[16]'] x32 = res['x[32]'] t = res['time'] print "t = ", repr(N.array(t)) print "x16 = ", repr(N.array(x16)) print "x32 = ", repr(N.array(x32)) if with_plots: # Plot plt.figure(1) plt.plot(t,x16,t,x32) plt.grid() plt.ylabel('x') plt.xlabel('time') plt.show()
def furuta_dfo_cost(x): # We need to scale the inputs x down since they are scaled up # versions of the parameters (x = scalefactor*[param1 param2]) armFrictionCoefficient = x[0]/1e3 pendulumFrictionCoefficient = x[1]/1e3 model = load_fmu(os.path.join(curr_dir, '..', 'examples', 'files', 'FMUs', 'Furuta.fmu')) # Set new parameter values into the model model.set('armFriction', armFrictionCoefficient) model.set('pendulumFriction', pendulumFrictionCoefficient) # Create options object and set verbosity to zero to disable printouts opts = model.simulate_options() opts['CVode_options']['verbosity'] = 0 # Simulate model response with new parameter values res = model.simulate(start_time=0., final_time=40, options=opts) # Load simulation result phi_sim = res['armJoint.phi'] theta_sim = res['pendulumJoint.phi'] t_sim = res['time'] # Evaluate the objective function y_meas = N.vstack((phi_meas, theta_meas)) y_sim = N.vstack((phi_sim, theta_sim)) obj = dfo.quad_err(t_meas, y_meas, t_sim, y_sim) return obj
def test_ExtFuncStatic(self): """ Test compiling a model with external functions in a static library. """ cpath = "ExtFunctionTests.ExtFunctionTest1" fmu_name = compile_fmu(cpath, TestExternalStatic.fpath) model = load_fmu(fmu_name)
def run_demo(with_plots=True): """ An example on how to simulate a model using the ODE simulator. """ curr_dir = os.path.dirname(os.path.abspath(__file__)); file_name = os.path.join(curr_dir,'files','VDP.mop') fmu_name = compile_fmu("JMExamples.VDP.VDP", curr_dir+"/files/JMExamples.mo") model = load_fmu(fmu_name) opts = model.simulate_options() opts["CVode_options"]["rtol"] = 1e-6 res = model.simulate(final_time=10, options=opts) assert N.abs(res.final('x1') - 7.34186386e-01) < 1e-3 assert N.abs(res.final('x2') + 1.58202722) < 1e-3 x1 = res['x1'] x2 = res['x2'] if with_plots: plt.figure() plt.plot(x2, x1) plt.legend(('x1(x2)')) plt.show()
def run_demo(with_plots=True): """ Demonstrates how to use PyFMI for simulation of Co-Simulation FMUs (version 1.0). """ fmu_name = O.path.join(path_to_fmus,'bouncingBall.fmu') model = load_fmu(fmu_name) res = model.simulate(final_time=2.) # Retrieve the result for the variables h_res = res['h'] v_res = res['v'] t = res['time'] assert N.abs(res.final('h') - (0.0424044)) < 1e-2 # Plot the solution if with_plots: # Plot the height fig = P.figure() P.clf() P.subplot(2,1,1) P.plot(t, h_res) P.ylabel('Height (m)') P.xlabel('Time (s)') # Plot the velocity P.subplot(2,1,2) P.plot(t, v_res) P.ylabel('Velocity (m/s)') P.xlabel('Time (s)') P.suptitle('FMI Bouncing Ball') P.show()
def run_demo(with_plots=True): """ An example on how to simulate a model using a DAE simulator with Assimulo. The model used is made by Maja Djačić. """ curr_dir = os.path.dirname(os.path.abspath(__file__)); m_name = 'SolAngles' mofile = curr_dir+'/files/SolAngles.mo' fmu_name = compile_fmu(m_name, mofile) model = load_fmu(fmu_name) res = model.simulate(final_time=86400.0, options={'ncp':86400}) theta = res['theta'] azim = res['azim'] N_day = res['N_day'] time = res['time'] assert N.abs(res.final('theta') - 90.28737353) < 1e-3 # Plot results if with_plots: p.figure(1) p.plot(time, theta) p.xlabel('time [s]') p.ylabel('theta [deg]') p.title('Angle of Incidence on Surface') p.grid() p.show()
def test_inlined_switches(self): """ Test a model that need in-lined switches to initialize. """ path = os.path.join(get_files_path(), 'Modelica', 'event_init.mo') fmu_name = compile_fmu('Init', path) model = load_fmu(fmu_name) model.initialize() assert N.abs(model.get("x") - (-2.15298995)) < 1e-3
def simulate(self): ''' TODO: LOG all command omc ''' # tic= timeit.default_timer() # Simulation process with JModelica fullMoFile= self.moPath+ '/'+ self.moFile fullMoLib= self.libPath+ '/'+ self.libFile '''build the fmu block from the modelica model ''' # fmu_name= compile_fmu(self.moModel, absolutePath, # compiler_options = {'extra_lib_dirs':self.libPath}) fmu_name= compile_fmu(self.moModel, [fullMoFile, fullMoLib]) ''' Load the model ''' model_fmu= load_fmu(fmu_name) ''' Load the list of options for the JModelica compiler ''' opts = model_fmu.simulate_options() opts['solver']= self.config.getSolver() opts['ncp']= self.config.getNcp() # for key,value in simOpt.getOptions().items(): # print key,value # opts[key] = value print opts result = model_fmu.simulate(start_time= self.config.getStartTime(), final_time= self.config.getStopTime(), options=opts) # toc= timeit.default_timer() # print 'Simulation time ', toc- tic return result
def run_demo(with_plots=True): """ Example demonstrating how to use index reduction. """ curr_dir = os.path.dirname(os.path.abspath(__file__)); # Compile model fmu_name = compile_fmu("Pendulum_pack.PlanarPendulum", curr_dir+"/files/Pendulum_pack.mop",compiler='optimica') # Load model model = load_fmu(fmu_name) # Options opts = model.simulate_options() opts["CVode_options"]["rtol"] = 1e-6 # Load result file res = model.simulate(final_time=10., options=opts) x = res['x'] st = res['st'] ct = res['ct'] err = res['err'] y = res['y'] vx = res['vx'] vy = res['vy'] t = res['time'] maxerr = N.max(err) if maxerr > 1e-6: print "Maximum error: ", maxerr assert maxerr < 1e-4 assert N.abs(res.final('x') - 0.38735171) < 1e-3 assert N.abs(res.final('st') - 0.38733358) < 1e-3 assert N.abs(res.final('ct') + 0.92193964) < 1e-3 assert N.abs(res.final('err') - 1.96716163e-05) < 1e-3 assert N.abs(res.final('y') + 0.92193202) < 1e-3 assert N.abs(res.final('vx') - 6.04839823e-01) < 1e-3 assert N.abs(res.final('vy') - 2.54124747e-01) < 1e-3 if with_plots: plt.figure(1) plt.subplot(3,1,1) plt.plot(t,x,t,y) plt.grid(True) plt.legend(['x','y']) plt.subplot(3,1,2) plt.plot(t,vx,t,vy) plt.grid(True) plt.legend(['vx','vy']) plt.subplot(3,1,3) plt.plot(t,err) plt.grid(True) plt.legend(['err']) plt.xlabel('time [s]') plt.show()
def run_demo(with_plots=True): """ Simulation of a model that predicts the blood glucose levels of a type-I diabetic. The objective is to predict the relationship between insulin injection and blood glucose levels. Reference: S. M. Lynch and B. W. Bequette, Estimation based Model Predictive Control of Blood Glucose in Type I Diabetes: A Simulation Study, Proc. 27th IEEE Northeast Bioengineering Conference, IEEE, 2001. S. M. Lynch and B. W. Bequette, Model Predictive Control of Blood Glucose in type I Diabetics using Subcutaneous Glucose Measurements, Proc. ACC, Anchorage, AK, 2002. """ curr_dir = os.path.dirname(os.path.abspath(__file__)) fmu_name1 = compile_fmu("JMExamples.BloodGlucose.BloodGlucose1", os.path.join(curr_dir, "files", "JMExamples.mo")) bg = load_fmu(fmu_name1) opts = bg.simulate_options() opts["CVode_options"]["rtol"] = 1e-6 res = bg.simulate(final_time=400, options=opts) # Extract variable profiles G = res["G"] X = res["X"] I = res["I"] t = res["time"] assert N.abs(res.final("G") - 19.77650) < 1e-4 assert N.abs(res.final("X") - 14.97815) < 1e-4 assert N.abs(res.final("I") - 2.7) < 1e-4 if with_plots: plt.figure(1) plt.subplot(2, 2, 1) plt.plot(t, G) plt.title("Plasma Glucose Conc") plt.grid(True) plt.ylabel("Plasma Glucose Conc. (mmol/L)") plt.xlabel("time") plt.subplot(2, 2, 2) plt.plot(t, X) plt.title("Plasma Insulin Conc.") plt.grid(True) plt.ylabel("Plasma Insulin Conc. (mu/L)") plt.xlabel("time") plt.subplot(2, 2, 3) plt.plot(t, I) plt.title("Plasma Insulin Conc.") plt.grid(True) plt.ylabel("Plasma Insulin Conc. (mu/L)") plt.xlabel("time") plt.show()
def __reset_model(self): """ Loads the model / resets it if it's loaded. """ if self.fmu == None: self.fmu = load_fmu(self.fmu_path) else: self.fmu.reset()
def test_ModelicaUtilities(self): """ Test compiling a model with external functions using the functions in ModelicaUtilities. """ fpath = path(get_files_path(), 'Modelica', "ExtFunctionTests.mo") cpath = "ExtFunctionTests.ExtFunctionTest3" jmu_name = compile_fmu(cpath, fpath) model = load_fmu(jmu_name)
def test_ExtFuncSharedCeval(self): """ Test compiling a model with external functions in a shared library. Constant evaluation during compilation. """ cpath = "ExtFunctionTests.ExtFunctionTest1" fmu_name = compile_fmu(cpath, TestExternalShared.fpath, compiler_options={'variability_propagation':True}) model = load_fmu(fmu_name) nose.tools.assert_equals(model.get('c'), 3)
def test_ExtFuncShared(self): """ Test compiling a model with external functions in a shared library. Simple. """ cpath = "ExtFunctionTests.ExtFunctionTest1" fmu_name = compile_fmu(cpath, TestExternalShared.fpath, compiler_options={'variability_propagation':False}) model = load_fmu(fmu_name) res = model.simulate() nose.tools.assert_equals(res.final('c'), 3)
def test_ExtFuncBool(self): """ Test compiling a model with external functions in a shared library. Boolean arrays. """ fmu_name = compile_fmu(self.cpath, self.fpath, compiler_options={'variability_propagation':False}) model = load_fmu(fmu_name) model.simulate() fmu_name = compile_fmu(self.cpath, self.fpath, compiler_options={'variability_propagation':True}) model2 = load_fmu(fmu_name) model2.simulate() trueInd = {1,2,3,5,8} falseInd = {4,6,7} for i in trueInd: assert(model.get('res[' + str(i) + ']')) assert(model2.get('res[' + str(i) + ']')) for i in falseInd: assert(not model.get('res[' + str(i) + ']')) assert(not model2.get('res[' + str(i) + ']'))
def test_simulate(self): cpath = 'Asserts.ModelicaError' fmu_name = compile_fmu(cpath, TestModelicaError.fpath) model = load_fmu(fmu_name) try: model.simulate(final_time = 3) assert False, 'Simulation not stopped by calls to ModelicaError()' except CVodeError, e: assert abs(e.t - 2.0) < 0.01, 'Simulation stopped at wrong time'
def run_demo(): """ Demonstrate how to parse a log file from a JModelica FMU. """ curr_dir = os.path.dirname(os.path.abspath(__file__)) file_name = os.path.join(curr_dir, 'files', 'LoggerTest.mo') fmu_name = compile_fmu( 'LoggerTest', file_name, compiler_log_level='i', compiler_options={'generate_only_initial_system': True}) log_file_name = 'LoggerTest_log.txt' m = load_fmu(fmu_name, log_file_name=log_file_name) m.set_debug_logging(True) m.set('_log_level', 6) m.set_fmil_log_level(5) # Play around with the model m.set('u1', 3) print 'u1' + str(m.get('u1')) print 'x1' + str(m.get('x1')) print 'y1' + str(m.get('y1')) print 'z1' + str(m.get('z1')) m.set('y1', 0.) m.initialize() print "model initialized" print 'u1' + str(m.get('u1')) print 'x1' + str(m.get('x1')) print 'y1' + str(m.get('y1')) print 'z1' + str(m.get('z1')) m.set('u1', 4) print "Input set" print 'u1' + str(m.get('u1')) print 'x1' + str(m.get('x1')) print 'y1' + str(m.get('y1')) print 'z1' + str(m.get('z1')) m.get_derivatives() m.set('y1', 0.5) print "Set initial value of y1" print 'x1' + str(m.get('x1')) print 'y1' + str(m.get('y1')) print 'z1' + str(m.get('z1')) m.set('p', 0.5) print "Set initial value of p" print 'x1' + str(m.get('x1')) print 'y1' + str(m.get('y1')) print 'z1' + str(m.get('z1')) # Parse the log file and print some of its contents # Extract the log file XML contents into a pure XML file dest_xml_file_name = 'LoggerTest_log.xml' extract_jmi_log(dest_xml_file_name, log_file_name) # Parse the entire XML log log = parse_jmi_log(log_file_name) print print 'Top log node: log =', log print 'Unnamed sub nodes: log.nodes = [' for node in log.nodes: print ' ', node, ',' print ']' print 'Time of first solve: log.nodes[0].t =', log.nodes[0].t # Gather information pertaining to equation solves solves = gather_solves(log) print print 'Number of solver invocations:', len(solves) print 'Time of first solve:', solves[0].t print 'Number of block solves in first solver invocation:', len( solves[0].block_solves) print 'Names of iteration variables in first block solve:', solves[ 0].block_solves[0].variables print 'Min bounds in first block solve:', solves[0].block_solves[0].min print 'Max bounds in first block solve:', solves[0].block_solves[0].max print 'Initial residual scaling in first block solve:', solves[ 0].block_solves[0].initial_residual_scaling print 'Number of iterations in first block solve:', len( solves[0].block_solves[0].iterations) print print 'First iteration in first block solve: ' print ' Iteration variables:', solves[0].block_solves[0].iterations[0].ivs print ' Scaled residuals:', solves[0].block_solves[0].iterations[ 0].residuals print ' Jacobian:\n', solves[0].block_solves[0].iterations[0].jacobian print ' Jacobian updated in iteration:', solves[0].block_solves[ 0].iterations[0].jacobian_updated print ' Residual scaling factors:', solves[0].block_solves[0].iterations[ 0].residual_scaling print ' Residual scaling factors_updated:', solves[0].block_solves[ 0].iterations[0].residual_scaling_updated print ' Scaled residual norm:', solves[0].block_solves[0].iterations[ 0].scaled_residual_norm
def run_demo(with_plots=True): """ This example is based on the Hicks-Ray Continuously Stirred Tank Reactors (CSTR) system. The system has two states, the concentration and the temperature. The control input to the system is the temperature of the cooling flow in the reactor jacket. The chemical reaction in the reactor is exothermic, and also temperature dependent; high temperature results in high reaction rate. The problem is solved using the CasADi-based collocation algorithm. The steps performed correspond to those demonstrated in example pyjmi.examples.cstr, where the same problem is solved using the default JMI algorithm. FMI is used for initialization and simulation purposes. The following steps are demonstrated in this example: 1. How to solve the initialization problem. The initialization model has equations specifying that all derivatives should be identically zero, which implies that a stationary solution is obtained. Two stationary points, corresponding to different inputs, are computed. We call the stationary points A and B respectively. Point A corresponds to operating conditions where the reactor is cold and the reaction rate is low, whereas point B corresponds to a higher temperature where the reaction rate is high. 2. How to generate an initial guess for a direct collocation method by means of simulation with a constant input. The trajectories resulting from the simulation are used to initialize the variables in the transcribed NLP. 3. An optimal control problem is solved where the objective is to transfer the state of the system from stationary point A to point B. The challenge is to ignite the reactor while avoiding uncontrolled temperature increase. 4. Finally the system is simulated using the optimal control profile. This step is important in order to verify that the approximation in the transcription step is sufficiently accurate. """ ### 1. Solve the initialization problem # Locate the Modelica and Optimica code file_path = os.path.join(get_files_path(), "CSTR.mop") # Compile the stationary initialization model into an FMU init_fmu = compile_fmu("CSTR.CSTR_Init", file_path) # Load the FMU init_model = load_fmu(init_fmu) # Set input for Stationary point A Tc_0_A = 250 init_model.set('Tc', Tc_0_A) # Solve the initialization problem using FMI init_model.initialize() # Store stationary point A [c_0_A, T_0_A] = init_model.get(['c', 'T']) # Print some data for stationary point A print(' *** Stationary point A ***') print('Tc = %f' % Tc_0_A) print('c = %f' % c_0_A) print('T = %f' % T_0_A) # Set inputs for Stationary point B init_model.reset() # reset the FMU so that we can initialize it again Tc_0_B = 280 init_model.set('Tc', Tc_0_B) # Solve the initialization problem using FMI init_model.initialize() # Store stationary point B [c_0_B, T_0_B] = init_model.get(['c', 'T']) # Print some data for stationary point B print(' *** Stationary point B ***') print('Tc = %f' % Tc_0_B) print('c = %f' % c_0_B) print('T = %f' % T_0_B) ### 2. Compute initial guess trajectories by means of simulation # Compile the optimization initialization model init_sim_fmu = compile_fmu("CSTR.CSTR_Init_Optimization", file_path) # Load the model init_sim_model = load_fmu(init_sim_fmu) # Set initial and reference values init_sim_model.set('cstr.c_init', c_0_A) init_sim_model.set('cstr.T_init', T_0_A) init_sim_model.set('c_ref', c_0_B) init_sim_model.set('T_ref', T_0_B) init_sim_model.set('Tc_ref', Tc_0_B) # Simulate with constant input Tc init_res = init_sim_model.simulate(start_time=0., final_time=150.) # Extract variable profiles t_init_sim = init_res['time'] c_init_sim = init_res['cstr.c'] T_init_sim = init_res['cstr.T'] Tc_init_sim = init_res['cstr.Tc'] # Plot the initial guess trajectories if with_plots: plt.close(1) plt.figure(1) plt.hold(True) plt.subplot(3, 1, 1) plt.plot(t_init_sim, c_init_sim) plt.grid() plt.ylabel('Concentration') plt.title('Initial guess obtained by simulation') plt.subplot(3, 1, 2) plt.plot(t_init_sim, T_init_sim) plt.grid() plt.ylabel('Temperature') plt.subplot(3, 1, 3) plt.plot(t_init_sim, Tc_init_sim) plt.grid() plt.ylabel('Cooling temperature') plt.xlabel('time') plt.show() ### 3. Solve the optimal control problem # Compile and load optimization problem op = transfer_optimization_problem("CSTR.CSTR_Opt2", file_path) # Set reference values op.set('Tc_ref', Tc_0_B) op.set('c_ref', float(c_0_B)) op.set('T_ref', float(T_0_B)) # Set initial values op.set('cstr.c_init', float(c_0_A)) op.set('cstr.T_init', float(T_0_A)) # Set options opt_opts = op.optimize_options() opt_opts['n_e'] = 19 # Number of elements opt_opts['init_traj'] = init_res.result_data opt_opts['nominal_traj'] = init_res.result_data opt_opts['IPOPT_options']['tol'] = 1e-10 # Solve the optimal control problem res = op.optimize(options=opt_opts) # Extract variable profiles c_res = res['cstr.c'] T_res = res['cstr.T'] Tc_res = res['cstr.Tc'] time_res = res['time'] c_ref = res.final('c_ref') # extract constant value as last element T_ref = res.final('T_ref') Tc_ref = res.final('Tc_ref') # Verify solution for testing purposes try: import casadi except: pass else: cost = float(res.solver.solver.output(casadi.NLP_SOLVER_F)) assert (N.abs(cost / 1.e3 - 1.86162353098) < 1e-3) # Plot the results if with_plots: plt.close(2) plt.figure(2) plt.hold(True) plt.subplot(3, 1, 1) plt.plot(time_res, c_res) plt.plot([time_res[0], time_res[-1]], [c_ref, c_ref], '--') plt.grid() plt.ylabel('Concentration') plt.title('Optimized trajectories') plt.subplot(312) plt.plot(time_res, T_res) plt.plot([time_res[0], time_res[-1]], [T_ref, T_ref], '--') plt.grid() plt.ylabel('Temperature') plt.subplot(313) plt.plot(time_res, Tc_res) plt.plot([time_res[0], time_res[-1]], [Tc_ref, Tc_ref], '--') plt.grid() plt.ylabel('Cooling temperature') plt.xlabel('time') plt.show() ### 4. Simulate to verify the optimal solution # Compile model sim_fmu = compile_fmu("CSTR.CSTR", file_path) # Load model sim_model = load_fmu(sim_fmu) # Get optimized input (_, opt_input) = res.solver.get_opt_input() # Set initial values sim_model.set('c_init', c_0_A) sim_model.set('T_init', T_0_A) # Simulate using optimized input sim_opts = sim_model.simulate_options() sim_opts['CVode_options']['rtol'] = 1e-6 sim_opts['CVode_options']['atol'] = 1e-8 res = sim_model.simulate(start_time=0., final_time=150., input=('Tc', opt_input), options=sim_opts) # Extract variable profiles c_sim = res['c'] T_sim = res['T'] Tc_sim = res['Tc'] time_sim = res['time'] # Verify results N.testing.assert_array_less(abs(c_res[-1] - c_sim[-1]) / c_res[-1], 5e-1) # Plot the results if with_plots: plt.close(3) plt.figure(3) plt.hold(True) plt.subplot(3, 1, 1) plt.plot(time_res, c_res, '--') plt.plot(time_sim, c_sim) plt.legend(('optimized', 'simulated')) plt.grid(True) plt.ylabel('Concentration') plt.title('Verification') plt.subplot(3, 1, 2) plt.plot(time_res, T_res, '--') plt.plot(time_sim, T_sim) plt.grid(True) plt.ylabel('Temperature') plt.subplot(3, 1, 3) plt.plot(time_res, Tc_res, '--') plt.plot(time_sim, Tc_sim) plt.grid(True) plt.ylabel('Cooling temperature') plt.xlabel('time') plt.show()
from pymodelica import compile_fmu from pyfmi import load_fmu import matplotlib.pyplot as P import matplotlib.dates as md import pandas as pd import numpy as N import matplotlib.ticker as mtick fmu_name = compile_fmu("MultizoneVAV.UncertaintyModels.VAVReheat.Guideline36_deterministic", jvm_args='-Xmx4g', compiler_options={"generate_html_diagnostics":True},compiler_log_level='error') model= load_fmu(fmu_name,log_level=7) dayOfYear_start=7*(24*60*60) hourOfDay_start=0*(60*60) minuteOfHour_start=0*(60) daySimRange=0*(24*60*60) hourSimRange=12*(60*60) minuteSimRange=0*(60) sim_Start = dayOfYear_start+hourOfDay_start+minuteOfHour_start SimulationRange = daySimRange+hourSimRange+minuteSimRange res=model.simulate(start_time=sim_Start, final_time=sim_Start+SimulationRange) # Convert from K to C conv_K_C=273.15 # Time t=res['time'] timestamps = pd.to_datetime(t, unit='s') # Physical zone air temperature for the two thermal zones without noise
L_d = ot.Uniform(250.0, 260.0) I_d = ot.Beta(2.5, 4.0-2.5, 310.0, 450.0) distribution = ot.ComposedDistribution([E_d, F_d, I_d, L_d]) x = distribution.getMean() f = model.getFunction() y = f(x) ott.assert_almost_equal(y, [12.3369]) # script script = myStudy.getPythonScript() print('script=', script) exec(script) # compare with pyfmi directly if 0: import pyfmi import otfmi # print(path_fmu) model_fmu = model_fmu = otfmi.FMUFunction( path_fmu, inputs_fmu=['E', 'F', 'I', 'L'], outputs_fmu='y') ml = pyfmi.load_fmu(path_fmu) vars = ml.get_model_variables() for var in vars.values(): print(var.name, var.value_reference) # print(ml.get_real(var.value_reference))
def run_demo(with_plots=True): """ This example is based on the Hicks-Ray Continuously Stirred Tank Reactors (CSTR) system. The system has two states, the concentration and the temperature. The control input to the system is the temperature of the cooling flow in the reactor jacket. The chemical reaction in the reactor is exothermic, and also temperature dependent; high temperature results in high reaction rate. This example serves to illustrate how constraints can be added when using the CasADi-based Moving Horizon Estimator (MHE). Shows the importance of constraints when working close to a physical constraint by comparing the unconstrained MHE with the constrained one. Constraints are added by simply extending a Modelica or Optimica model and adding the constraint or by creating a Constraint to the OptimizationProblem object using setPathConstraints. The usage of point constraints is not supported and can give unpredictable results. """ #Get the name and location of the Modelica package file_path = os.path.join(get_files_path(), "CSTR.mop") #Transfer the unconstrained OptimizationProblem from the model #using "state_initial_equations" and "accept_model" unconstr_op = transfer_optimization_problem( 'CSTR.CSTR_mhe_model', file_path, accept_model=True, compiler_options={"state_initial_equations": True}) #Transfer the constrained OptimizationProblem from the Optimica model #using "state_initial_equations" constr_op = transfer_optimization_problem( 'CSTR.CSTR_mhe', file_path, accept_model=False, compiler_options={"state_initial_equations": True}) #The constraint could instead have been added using the following: #c_var = op.getVariable('c').getVar() #constr = mc.Constraint(c_var, MX(0), mc.Constraint.GEQ) #op.setPathConstraints([constr]) #Compile the FMU with the same option as for the OptimizationProblem fmu = compile_fmu('CSTR.CSTR_mhe_model', file_path, compiler_options={"state_initial_equations": True}) #Load the FMU model = load_fmu(fmu) #Define the time interval and the number of points sim_time = 3. nbr_of_points = 31 #Calculate the corresponding sample time sample_time = sim_time / (nbr_of_points - 1) #Create an array of the time points time = N.linspace(0., sim_time, nbr_of_points) ###Create noise for the measurement data #Create the discrete covariance matrices Q = N.array([[20.]]) R = N.array([[10., 0.], [0., 1.]]) #The expectations w_my = N.array([0.]) v_my = N.array([0., 0.]) ##Get the noise sequences #Process noise #Use same seed for consistent results N.random.seed(3) w = N.transpose(N.random.multivariate_normal(w_my, Q, nbr_of_points)) #Measurement noise N.random.seed(188) v = N.transpose(N.random.multivariate_normal(v_my, R, nbr_of_points)) ###Chose a control signal u = 350. * N.ones(nbr_of_points) ###Define the inputs for the MHE object ##See the documentation of the MHEOptions for more details #Create the options object MHE_opts = MHEOptions() #Process noise covariance MHE_opts['process_noise_cov'] = [('Tc', 200.)] #The names of the input signals acting as control signals MHE_opts['input_names'] = ['Tc'] #Chose what variables are measured and their covariance structure #The two definitions below are equivalent MHE_opts['measurement_cov'] = [('c', 1.), ('T', 0.1)] MHE_opts['measurement_cov'] = [(['c', 'T'], N.array([[1., 0.0], [0.0, 0.1]]))] #Error covariance matrix MHE_opts['P0_cov'] = [('c', 10.), ('T', 5.)] ##The initial guess of the states x_0_guess = dict([('c', 0.), ('T', 352.)]) #Initial value of the simulation x_0 = dict([('c', 0.), ('T', 350.)]) ##Use mhe_initial_values module or some equivalent method to get the #initial values of the state derivatives and the algebraic variables #Control signal for time step zero u_0 = {'Tc': u[0]} (dx_0, c_0) = initv.optimize_for_initial_values(unconstr_op, x_0_guess, u_0, MHE_opts) #Decide the horizon length horizon = 8 ##Create the MHE objects unconstr_MHE_object = MHE(unconstr_op, sample_time, horizon, x_0_guess, dx_0, c_0, MHE_opts) constr_MHE_object = MHE(constr_op, sample_time, horizon, x_0_guess, dx_0, c_0, MHE_opts) #Create a structure for saving the estimates unconstr_x_est = {'c': [x_0_guess['c']], 'T': [x_0_guess['T']]} constr_x_est = {'c': [x_0_guess['c']], 'T': [x_0_guess['T']]} #Create a structure for saving the simulated data x = {'c': [x_0['c']], 'T': [x_0['T']]} #Create the structure for the measured data y = {'c': [], 'T': []} #Loop over estimation and simulation for t in range(1, nbr_of_points): #Create the measurement data from the simulated data and added noise y['c'].append(x['c'][-1] + v[0, t - 1]) y['T'].append(x['T'][-1] + v[1, t - 1]) #Create list of tuples with (name, measurement) structure y_t = [('c', y['c'][-1]), ('T', y['T'][-1])] #Create list of tuples with (name, input) structure u_t = [('Tc', u[t - 1])] #Estimate constr_x_est_t = constr_MHE_object.step(u_t, y_t) unconstr_x_est_t = unconstr_MHE_object.step(u_t, y_t) #Add the results to x_est for key in list(constr_x_est.keys()): constr_x_est[key].append(constr_x_est_t[key]) for key in list(unconstr_x_est.keys()): unconstr_x_est[key].append(unconstr_x_est_t[key]) ###Prepare the simulation #Create the input object u_traj = N.transpose(N.vstack((0., u[t]))) input_object = ('Tc', u_traj) #Set the initial values of the states for (key, list) in list(x.items()): model.set('_start_' + key, list[-1]) #Simulate with one communication point to get the #value at the right point res = model.simulate(final_time=sample_time, input=input_object, options={'ncp': 1}) #Extract the state values from the result object for key in list(x.keys()): x[key].append(res[key][-1]) #reset the FMU model.reset() #Add the last measurement y['c'].append(x['c'][-1] + v[0, -1]) y['T'].append(x['T'][-1] + v[1, -1]) if with_plots: plt.close('MHE') plt.figure('MHE') plt.subplot(2, 1, 1) plt.plot(time, constr_x_est['c']) plt.plot(time, unconstr_x_est['c']) plt.plot(time, x['c'], ls='--', color='k') plt.plot(time, y['c'], ls='-', marker='+', mfc='k', mec='k', mew=1.) plt.legend(('Constrained concentration estimate', 'Unconstrained concentration estimate', 'Simulated concentration', 'Measured concentration')) plt.grid() plt.ylabel('Concentration') plt.subplot(2, 1, 2) plt.plot(time, constr_x_est['T']) plt.plot(time, unconstr_x_est['T']) plt.plot(time, x['T'], ls='--', color='k') plt.plot(time, y['T'], ls='-', marker='+', mfc='k', mec='k', mew=1.) plt.legend(('Constrained temperature estimate', 'Unconstrained temperature estimate', 'Simulated temperature', 'Measured temperature')) plt.grid() plt.ylabel('Temperature') plt.show()
from pymodelica import compile_fmu from pyfmi import load_fmu import matplotlib.pyplot as plt import numpy as np fmu_name = 'IEEE_39_Buses' name = compile_fmu(fmu_name, fmu_name + ".mo") print('Loading model...............') print('.........................................') model = load_fmu(fmu_name + '.fmu') opts = model.simulate_options() opts['solver'] = 'CVode' # Not necessary, default solver is CVode #opts["ncp"] = 200 #Specify that 1000 output points should be returned # opts['ncp'] = 1000 # Changing the number of communication points. opts['CVode_options'][ 'discr'] = 'Adams' # Change from using BDF to Adams / quicker #opts['initialize'] = False # initialize the model opts['CVode_options']['atol'] = 1.0e-6 # Options specific for CVode opts['CVode_options']['rtol'] = 1.0e-3 # Options specific for CVode # opts['CVode_options']['atol'] = 1.0e-6 # Options specific for CVode #opts['filter'] =['line_4_5.P12','line_4_5.Q12'] #opts['result_handling']='memory' #Specifies options # sim.discr = 'Adams' #Sets the discretization method # sim.iter = 'FixedPoint' #Sets the iteration method # sim.rtol = 1.e-8 #Sets the relative tolerance
def run_demo(with_plots=True, use_ma57=True, latex_plots=False): """ This example is based on a binary distillation column. The model has 42 states, 1083 algebraic variables and 2 control variables. The task is to get back to the desired steady-state after a short reflux breakdown. The example consists of the following steps: 1. Find the desired steady state by simulating ad infinitum with constant inputs. 2. Simulate the short reflux breakdown. 3. Simulate post-breakdown with constant inputs to generate an initial guess. 4. Solve the optimal control problem to get back to the desired steady state after the breakdown. 5. Verify the optimal trajectories by simulation. The model was developed in Moritz Diehl's PhD thesis: @PHDTHESIS{diehl2002phd, author = {Diehl, Moritz}, title = {Real-Time Optimization for Large Scale Nonlinear Processes}, school = {Heidelberg University}, year = {2002}, type = {Ph.{D}. thesis} } The Modelica implementation was based on the MATLAB implementation from John Hedengren's nonlinear model library available at: http://www.hedengren.net/research/models.htm This example needs one of the linear solvers MA27 or MA57 to work. The precense of MA27 or MA57 is not detected in the example, so if only MA57 is present, then True must be passed in the use_ma57 argument. """ ### 1. Find the desired steady state by simulating with constant inputs # Compile model file_name = (os.path.join(get_files_path(), "JMExamples.mo"), os.path.join(get_files_path(), "JMExamples_opt.mop")) ss_fmu = compile_fmu("JMExamples.Distillation.Distillation4", file_name) ss_model = load_fmu(ss_fmu) # Set constant input and simulate [L_vol_ref] = ss_model.get('Vdot_L1_ref') [Q_ref] = ss_model.get('Q_elec_ref') ss_res = ss_model.simulate(final_time=500000., input=(['Q_elec', 'Vdot_L1'], lambda t: [Q_ref, L_vol_ref])) # Extract results ss_T_14 = ss_res['Temp[28]'] T_14_ref = ss_T_14[-1] ss_T_28 = ss_res['Temp[14]'] T_28_ref = ss_T_28[-1] ss_L_vol = ss_res['Vdot_L1'] ss_Q = ss_res['Q_elec'] ss_t = ss_res['time'] abs_zero = ss_model.get('absolute_zero') L_fac = 1e3 * 3.6e3 Q_fac = 1e-3 print('T_14_ref: %.6f' % T_14_ref) print('T_28_ref: %.6f' % T_28_ref) # Plot simulation if with_plots: # Plotting options plt.rcParams.update({ 'font.serif': ['Times New Roman'], 'text.usetex': latex_plots, 'font.family': 'serif', 'axes.labelsize': 20, 'legend.fontsize': 16, 'xtick.labelsize': 12, 'font.size': 20, 'ytick.labelsize': 14 }) pad = 2 padplus = plt.rcParams['axes.labelsize'] / 2 # Define function for custom axis scaling in plots def scale_axis(figure=plt, xfac=0.01, yfac=0.05): """ Adjust the axis. The size of the axis is first changed to plt.axis('tight') and then scaled by (1 + xfac) horizontally and (1 + yfac) vertically. """ (xmin, xmax, ymin, ymax) = figure.axis('tight') if figure == plt: figure.xlim(xmin - xfac * (xmax - xmin), xmax + xfac * (xmax - xmin)) figure.ylim(ymin - yfac * (ymax - ymin), ymax + yfac * (ymax - ymin)) else: figure.set_xlim(xmin - xfac * (xmax - xmin), xmax + xfac * (xmax - xmin)) figure.set_ylim(ymin - yfac * (ymax - ymin), ymax + yfac * (ymax - ymin)) # Define function for plotting the important quantities def plot_solution(t, T_28, T_14, Q, L_vol, fig_index, title): plt.close(fig_index) fig = plt.figure(fig_index) fig.subplots_adjust(wspace=0.35) ax = fig.add_subplot(2, 2, 1) bx = fig.add_subplot(2, 2, 2) cx = fig.add_subplot(2, 2, 3, sharex=ax) dx = fig.add_subplot(2, 2, 4, sharex=bx) width = 3 ax.plot(t, T_28 + abs_zero, lw=width) ax.hold(True) ax.plot(t[[0, -1]], 2 * [T_28_ref + abs_zero], 'g--') ax.hold(False) ax.grid() if latex_plots: label = '$T_{28}$ [$^\circ$C]' else: label = 'T28' ax.set_ylabel(label, labelpad=pad) plt.setp(ax.get_xticklabels(), visible=False) scale_axis(ax) bx.plot(t, T_14 + abs_zero, lw=width) bx.hold(True) bx.plot(t[[0, -1]], 2 * [T_14_ref + abs_zero], 'g--') bx.hold(False) bx.grid() if latex_plots: label = '$T_{14}$ [$^\circ$C]' else: label = 'T14' ax.set_ylabel(label, labelpad=pad) plt.setp(bx.get_xticklabels(), visible=False) scale_axis(bx) cx.plot(t, Q * Q_fac, lw=width) cx.hold(True) cx.plot(t[[0, -1]], 2 * [Q_ref * Q_fac], 'g--') cx.hold(False) cx.grid() if latex_plots: ylabel = '$Q$ [kW]' xlabel = '$t$ [s]' else: ylabel = 'Q' xlabel = 't' cx.set_ylabel(ylabel, labelpad=pad) cx.set_xlabel(xlabel) scale_axis(cx) dx.plot(t, L_vol * L_fac, lw=width) dx.hold(True) dx.plot(t[[0, -1]], 2 * [L_vol_ref * L_fac], 'g--') dx.hold(False) dx.grid() if latex_plots: ylabel = '$L_{\Large \mbox{vol}}$ [l/h]' xlabel = '$t$ [s]' else: ylabel = 'L' xlabel = 't' dx.set_ylabel(ylabel, labelpad=pad) dx.set_xlabel(xlabel) scale_axis(dx) fig.suptitle(title) plt.show() # Call plot function plot_solution(ss_t, ss_T_28, ss_T_14, ss_Q, ss_L_vol, 1, 'Simulated trajectories to find steady state') # Plot steady state temperatures plt.close(2) plt.figure(2) plt.hold(True) for i in xrange(1, 43): temperature = (ss_res.final('Temp[' + ` i ` + ']') + ss_res.initial('absolute_zero')) plt.plot(temperature, 43 - i, 'ko') plt.title('Steady state temperatures') if latex_plots: label = '$T$ [$^\circ$C]' else: label = 'T' plt.xlabel(label) plt.ylabel('Tray index [1]') ### 2. Simulate the short reflux breakdown # Compile model model_fmu = compile_fmu("JMExamples.Distillation.Distillation4", file_name) break_model = load_fmu(model_fmu) # Set initial values break_model.set('Q_elec_ref', Q_ref) break_model.set('Vdot_L1_ref', L_vol_ref) for i in xrange(1, 43): break_model.set('xA_init[%d]' % i, ss_res.final('xA[%d]' % i)) # Define input function for broken reflux def input_function(time): if time < 700.: return [Q_ref, L_vol_ref] else: return [Q_ref, 0.5 / 1000. / 3600.] # Simulate and extract results break_res = break_model.simulate(final_time=1000., input=(['Q_elec', 'Vdot_L1'], input_function)) break_T_14 = break_res['Temp[28]'] break_T_28 = break_res['Temp[14]'] break_L_vol = break_res['Vdot_L1'] break_Q = break_res['Q_elec'] break_t = break_res['time'] # Plot simulation if with_plots: plot_solution(break_t, break_T_28, break_T_14, break_Q, break_L_vol, 3, 'Simulated short reflux breakdown') ### 3. Simulate post-breakdown with constant inputs to find initial guess # Compile the model ref_model = load_fmu(model_fmu) # Set initial conditions for post breakdown ref_model.set('Q_elec_ref', Q_ref) ref_model.set('Vdot_L1_ref', L_vol_ref) for i in xrange(1, 43): ref_model.set('xA_init[' + ` i ` + ']', break_res.final('xA[' + ` i ` + ']')) # Simulate ref_res = ref_model.simulate(final_time=5000., input=(['Q_elec', 'Vdot_L1'], lambda t: [Q_ref, L_vol_ref])) # Extract results ref_T_14 = ref_res['Temp[28]'] ref_T_28 = ref_res['Temp[14]'] ref_L_vol = ref_res['Vdot_L1'] ref_Q = ref_res['Q_elec'] ref_t = ref_res['time'] # Plot initial guess if with_plots: plot_solution(ref_t, ref_T_28, ref_T_14, ref_Q, ref_L_vol, 4, 'Initial guess') ### 4. Solve optimal control problem # Compile optimization problem op = transfer_optimization_problem("JMExamples_opt.Distillation4_Opt", file_name) # Set initial conditions for post breakdown op.set('Q_elec_ref', Q_ref) op.set('Vdot_L1_ref', L_vol_ref) for i in xrange(1, 43): op.set('xA_init[' + ` i ` + ']', break_res.final('xA[' + ` i ` + ']')) # Set optimization options and solve opts = op.optimize_options() opts['init_traj'] = ref_res opts['nominal_traj'] = ref_res opts['n_e'] = 15 opts['IPOPT_options']['linear_solver'] = "ma57" if use_ma57 else "ma27" opts['IPOPT_options']['mu_init'] = 1e-3 opt_res = op.optimize(options=opts) # Extract results opt_T_14 = opt_res['Temp[28]'] opt_T_28 = opt_res['Temp[14]'] opt_L_vol = opt_res['Vdot_L1'] opt_Q = opt_res['Q_elec'] opt_t = opt_res['time'] # Plot if with_plots: plot_solution(opt_t, opt_T_28, opt_T_14, opt_Q, opt_L_vol, 5, 'Optimal control') # Verify cost for testing purposes try: import casadi except: pass else: cost = float(opt_res.solver.solver_object.output(casadi.NLP_SOLVER_F)) N.testing.assert_allclose(cost, 4.611038777467e-02, rtol=1e-2) ### 5. Verify optimization discretization by simulation verif_model = load_fmu(model_fmu) # Set initial conditions for post breakdown verif_model.set('Q_elec_ref', Q_ref) verif_model.set('Vdot_L1_ref', L_vol_ref) for i in xrange(1, 43): verif_model.set('xA_init[' + ` i ` + ']', break_res.final('xA[' + ` i ` + ']')) # Simulate with optimal input verif_res = verif_model.simulate(final_time=5000., input=opt_res.get_opt_input()) # Extract results verif_T_14 = verif_res['Temp[28]'] verif_T_28 = verif_res['Temp[14]'] verif_L_vol = verif_res['Vdot_L1'] verif_Q = verif_res['Q_elec'] verif_t = verif_res['time'] # Plot verifying simulation if with_plots: plot_solution(verif_t, verif_T_28, verif_T_14, verif_Q, verif_L_vol, 6, 'Simulation with optimal input')
# Using a list to exclude non-workdays for heatload data non_workdays_file = r'L:\HVAC_ModelicaModel_Data\Commercial and Residential Hourly Load Profiles for all TMY3 Locations in the United States\SF_smalloffice_weekends+holidays.csv' non_workdays = np.loadtxt(non_workdays_file) hlparam_names = ['RoomLoadData', 'RoomLoadData2', 'RoomLoadData3'] n_rooms = len(hlparam_names) hldays_set = [] for i in range(n_rooms): # hldays = days # hldays = check_workday(days,non_workdays,max_d=2) hldays = neighbor_days2(days, non_workdays, max_d=2, max_days=max_days) hldays_set.append(hldays) for i, day in enumerate(days): model = load_fmu( fmu ) # if fmu already compiled, can use model = load_fmu(fileName+'.fmu') # model.set('_log_level', 6) LoadWeatherData(model, weather_file, day=day) # set weather data # LoadHeatLoadData(model,load_file,day = hldays[i]) # set room heat load data multi_hldays = [hldays_set[j][i] for j in range(n_rooms) ] # set multiple room heat load data LoadMultiHeatLoadData(model, load_files, days=multi_hldays, param_names=hlparam_names, scale_factor=0.7) opts = model.simulate_options() opts['ncp'] = data_points # Changing the number of communication points res = model.simulate(start_time=start_time, final_time=final_time,
def simulate_cymdist_griddyn14bus_fmus(): """Simulate coupled GridDyn and CYMDIST FMUs. """ # Simulation parameters start_time = 0.0 stop_time = 300 step_size = 300 # Path to the CYMDIST configuration file path_config=os.path.abspath("config.json") # Conversion to byte for PyFMI cymdist_con_val_str = bytes(path_config, 'utf-8') griddyn_input_valref=[] griddyn_output_valref=[] griddyn_output_values=[] cymdist_input_valref=[] cymdist_output_valref=[] cymdist_output_values=[] cymdist = load_fmu("../fmus/CYMDIST/CYMDIST.fmu", log_level=7) griddyn=load_fmu("../fmus/griddyn/griddyn14bus.fmu", log_level=7) cymdist.setup_experiment(start_time=start_time, stop_time=stop_time) griddyn.setup_experiment(start_time=start_time, stop_time=stop_time) # Define the inputs cymdist_input_names = ['VMAG_A', 'VMAG_B', 'VMAG_C', 'VANG_A', 'VANG_B', 'VANG_C'] cymdist_output_names = ['IA', 'IB', 'IC', 'IAngleA', 'IAngleB', 'IAngleC'] griddyn_input_names = ['Bus11_IA', 'Bus11_IB', 'Bus11_IC', 'Bus11_IAngleA', 'Bus11_IAngleB', 'Bus11_IAngleC'] griddyn_output_names = ['Bus11_VA', 'Bus11_VB', 'Bus11_VC', 'Bus11_VAngleA', 'Bus11_VAngleB', 'Bus11_VAngleC'] # Get the value references of griddyn inputs for elem in griddyn_input_names: griddyn_input_valref.append(griddyn.get_variable_valueref(elem)) # Get the value references of griddyn outputs for elem in griddyn_output_names: griddyn_output_valref.append(griddyn.get_variable_valueref(elem)) # Get the value references of cymdist inputs for elem in cymdist_input_names: cymdist_input_valref.append(cymdist.get_variable_valueref(elem)) # Get the value references of cymdist outputs for elem in cymdist_output_names: cymdist_output_valref.append(cymdist.get_variable_valueref(elem)) # Set the flag to save the results cymdist.set("_saveToFile", 0) # Get the initial outputs from griddyn # Get value reference of the configuration file cymdist_con_val_ref = cymdist.get_variable_valueref("_configurationFileName") # Set the configuration file cymdist.set_string([cymdist_con_val_ref], [cymdist_con_val_str]) # Set the value of the multiplier griddyn.set('multiplier', 3.0) # Initialize the FMUs cymdist.initialize() griddyn.initialize() # Call event update prior to entering continuous mode. cymdist.event_update() cymdist.enter_continuous_time_mode() # Co-simulation loop for tim in np.arange(start_time, stop_time, step_size): cnt+=1 # Get the outputs from griddyn griddyn_output_values = (griddyn.get_real(griddyn_output_valref)) # set the time in cymdist cymdist.time = tim # Set the inputs of cymdist cymdist.set_real(cymdist_input_valref, griddyn_output_values) # Get the outputs of cymdist cymdist_output_values = (cymdist.get_real(cymdist_output_valref)) # Terminate FMUs cymdist.terminate() griddyn.terminate()
def simulateFMU(inputFileName, outputFileName): ''' Read an input file of a specific format, update setting values, simulate the FMU, and output results. *Note* - Current flexibility, i.e., for time depedent inputs is not handled but could be by modifying/expanding this file or perhaps creating a RAVEN interface specifically for pyfmi or, preferably, the FMI standard. inputFileName = 'referenceInput.txt' (default) outputFileName = 'results.csv' (default) Format of inputFileName: Requires - 1) the location and name of the FMU <--- Only one, must be the first line 2) variables to be set by RAVEN <--- May include any number 3) and variables to be output to RAVEN <--- May include any number Example: fmuName = 'PATHTOFMU/myFMU.fmu' <--- Must be the first line!!! sigma = $RAVEN-sigma$ rho = $RAVEN-rho$ lorenzSystem.x lorenzSystem.y ''' # Read the input file with open(inputFileName, 'r') as f: lines = f.readlines() # Extract file name of FMU if "fmuName" in lines[0]: fmuName = ''.join(re.findall("'([^']*')", lines[0])).replace("'", "") else: raise ValueError( 'fmuName must be specified in first line of input file. Found instead:\n', lines[0]) # Load the FMU model = load_fmu(str(fmuName)) # Initialize dictionaries results = {} for i, line in enumerate(lines): if i == 0: # Skip first line which contains fmuName pass elif '=' in line: # Set the new model parameters key, value = line.replace(' ', '').strip().split('=') model.set(key, value) #results[key] = None <-- gives warnings when run with raven. Can't add variables not specified in raven .xml file? else: # Generate key for variable to be saved key = line.replace(' ', '').strip() results[key] = None # Simulate res = model.simulate() # Write results to dictionary for key in results.keys(): results[key] = res[key] # Save results to csv (column - variable, row - values) pd.DataFrame(results).to_csv(outputFileName, index=False)
def test_load_fmu(self): """Load an fmu.""" model = pyfmi.load_fmu(self.path_fmu)
def run_demo(with_plots=True): """ Demonstrates how to use an JMODELICA generated FMU for sensitivity calculations and compares against finite differences. Model and original code by Niklas Andersson """ curr_dir = os.path.dirname(os.path.abspath(__file__)); #Compile the model fmu_name = compile_fmu("SEIRSmodel", curr_dir+"/files/SEIRSmodel.mo") #Sensitivity parameters senspars = [5,6,7,8] parnames = ['p%d'%sp for sp in senspars] #Simulation interval t0 = 2002. tf = 2007. fmodel = load_fmu(fmu_name,enable_logging=False) # Get and set the options fopts = fmodel.simulate_options() fopts['CVode_options']['atol'] = 1.0e-6 fopts['CVode_options']['rtol'] = 1.0e-6 fopts['sensitivities'] = parnames fopts['ncp'] = 500 #Simulate fres = fmodel.simulate(t0,tf, options=fopts) #Get the result dEdpt_fmu = N.array([fres['dE/dp%d' % (i)] for i in senspars]).T #Calculate Finite Differences theta0 = N.array([fmodel.get(name) for name in parnames]) fopts['sensitivities'] = [] fopts['ncp'] = 0 dEdpt_findiff_fmu = sensfunc(objectfun_fmu,theta0,fmu_name,parnames,t0,tf,fopts,N.linspace(t0,tf,501.)) #Maximum relative errors for ii,sp in enumerate(senspars): err = N.max(N.abs(dEdpt_fmu[:,ii]-dEdpt_findiff_fmu[:,ii])/N.max(dEdpt_fmu[:,ii])) assert err < 1.0, str(err) + " not less than " + str(1.0) #Plotting if with_plots: for ii,sp in enumerate(senspars): plt.figure(1) plt.subplot(len(senspars),1,ii) plt.hold(True) plt.plot(fres['time'],dEdpt_fmu[:,ii],'x-') plt.plot(fres['time'],dEdpt_findiff_fmu[:,ii],'o-') plt.legend(['fmu-sens','fmu-findiff']) plt.figure(2) plt.hold(True) plt.semilogy(fres['time'],N.abs(dEdpt_fmu[:,ii]-dEdpt_findiff_fmu[:,ii])/N.max(dEdpt_fmu[:,ii]),label=parnames[ii]) plt.legend() plt.grid(True) plt.xlabel("Time [s]") plt.title("Comparison of sensitivities calculated by CVodes and by Finite differences") plt.show()
def __init__( self, max_power: float, design_altitude: float, design_speed: float, fuel_type: float, strokes_nb: float, prop_layout: float, ): """ Parametric Internal Combustion engine. It computes engine characteristics using fuel type, motor architecture and constant propeller efficiency using analytical model from following sources: :param max_power: maximum delivered mechanical power of engine (units=W) :param design_altitude: design altitude for cruise (units=m) :param design_speed: design altitude for cruise (units=m/s) :param fuel_type: 1.0 for gasoline and 2.0 for diesel engine and 3.0 for Jet Fuel :param strokes_nb: can be either 2-strockes (=2.0) or 4-strockes (=4.0) :param prop_layout: propulsion position in nose (=3.0) or wing (=1.0) """ if fuel_type == 1.0: self.ref = { "max_power": 132480, "length": 0.83, "height": 0.57, "width": 0.85, "mass": 136, } # Lycoming IO-360-B1A else: self.ref = { "max_power": 160000, "length": 0.859, "height": 0.659, "width": 0.650, "mass": 205, } # TDA CR 1.9 16V self.prop_layout = prop_layout self.max_power = max_power self.design_altitude = design_altitude self.design_speed = design_speed self.fuel_type = fuel_type self.strokes_nb = strokes_nb self.idle_thrust_rate = 0.01 # Declare sub-components attribute self.engine = Engine(power_SL=max_power) self.nacelle = None self.propeller = None # This dictionary is expected to have a Mixture coefficient for all EngineSetting values self.mixture_values = { EngineSetting.TAKEOFF: 1.5, EngineSetting.CLIMB: 1.5, EngineSetting.CRUISE: 1.0, EngineSetting.IDLE: 1.0, } # ... so check that all EngineSetting values are in dict unknown_keys = [ key for key in EngineSetting if key not in self.mixture_values.keys() ] if unknown_keys: raise FastUnknownEngineSettingError("Unknown flight phases: %s", unknown_keys) # Define the FMU model used # noinspection PyProtectedMember self.model = load_fmu( pth.join(resources.__path__._path[0], PROPULSION_FMU))
# Create an optimizer object based on the template and a model optimizer_1 = template_optimizer.optimizer(model_1) # Create an observer object based on the template and a model observer_1 = template_observer.observer(model_1) # Create a simulator object based on the template and a model simulator_1 = template_simulator.simulator(model_1) # Create a configuration configuration_1 = core_do_mpc.configuration(model_1, optimizer_1, observer_1, simulator_1) # Set up the solvers configuration_1.setup_solver() # Load FMU created from compile_fmu() or EnergyPlusToFMU modelName = 'RKF' model_fmu = load_fmu(modelName + '.fmu') # Load options opts = model_fmu.simulate_options() # Set number of timesteps opts['ncp'] = numSteps # Manually initialize opts['initialize'] = False model_fmu.initialize(configuration_1.simulator.t0_sim * 60, configuration_1.optimizer.t_end * 60) """ ---------------------------- do-mpc: MPC loop ---------------------------- """ start_time = time.time()
# Setup of Modelica etc import numpy as np import matplotlib.pyplot as plt from pymodelica import compile_fmu from pyfmi import load_fmu # Define model file name and class name model_name = 'BIOPROCESS.BatchWithNoise' model_file = 'br13.mo' # Compile model fmu_model = compile_fmu(model_name, model_file) # Load model model = load_fmu(fmu_model) # Simulation time simulationTime = 7.0 # Specification of acceptable batch t_final_max = 6.0 # h X_final_min = 5.0 # g/L # Initial values - changes from the model default values model.set('bioreactor.V_0', 1.0) model.set('bioreactor.VX_0', 2.0) model.set('bioreactor.VS_0', 10.0) model.set('bioreactor.VP_0', 0.0) # Parameters
def run_demo(with_plots=True): """ This example demonstrates how to solve parameter estimation problmes. The data used in the example was recorded by Kristian Soltesz at the Department of Automatic Control. """ curr_dir = os.path.dirname(os.path.abspath(__file__)); # Load measurement data from file data = loadmat(curr_dir+'/files/qt_par_est_data.mat',appendmat=False) # Extract data series t_meas = data['t'][6000::100,0]-60 y1_meas = data['y1_f'][6000::100,0]/100 y2_meas = data['y2_f'][6000::100,0]/100 y3_meas = data['y3_d'][6000::100,0]/100 y4_meas = data['y4_d'][6000::100,0]/100 u1 = data['u1_d'][6000::100,0] u2 = data['u2_d'][6000::100,0] # Plot measurements and inputs if with_plots: plt.figure(1) plt.clf() plt.subplot(2,2,1) plt.plot(t_meas,y3_meas) plt.title('x3') plt.grid() plt.subplot(2,2,2) plt.plot(t_meas,y4_meas) plt.title('x4') plt.grid() plt.subplot(2,2,3) plt.plot(t_meas,y1_meas) plt.title('x1') plt.xlabel('t[s]') plt.grid() plt.subplot(2,2,4) plt.plot(t_meas,y2_meas) plt.title('x2') plt.xlabel('t[s]') plt.grid() plt.figure(2) plt.clf() plt.subplot(2,1,1) plt.plot(t_meas,u1) plt.hold(True) plt.title('u1') plt.grid() plt.subplot(2,1,2) plt.plot(t_meas,u2) plt.title('u2') plt.xlabel('t[s]') plt.hold(True) plt.grid() # Build input trajectory matrix for use in simulation u = N.transpose(N.vstack((t_meas,u1,u2))) # compile FMU fmu_name = compile_fmu('QuadTankPack.Sim_QuadTank', curr_dir+'/files/QuadTankPack.mop') # Load model model = load_fmu(fmu_name) # Simulate model response with nominal parameters res = model.simulate(input=(['u1','u2'],u),start_time=0.,final_time=60) # Load simulation result x1_sim = res['qt.x1'] x2_sim = res['qt.x2'] x3_sim = res['qt.x3'] x4_sim = res['qt.x4'] t_sim = res['time'] u1_sim = res['u1'] u2_sim = res['u2'] assert N.abs(res.final('qt.x1') - 0.05642485) < 1e-3 assert N.abs(res.final('qt.x2') - 0.05510478) < 1e-3 assert N.abs(res.final('qt.x3') - 0.02736532) < 1e-3 assert N.abs(res.final('qt.x4') - 0.02789808) < 1e-3 assert N.abs(res.final('u1') - 6.0) < 1e-3 assert N.abs(res.final('u2') - 5.0) < 1e-3 # Plot simulation result if with_plots: plt.figure(1) plt.subplot(2,2,1) plt.plot(t_sim,x3_sim) plt.subplot(2,2,2) plt.plot(t_sim,x4_sim) plt.subplot(2,2,3) plt.plot(t_sim,x1_sim) plt.subplot(2,2,4) plt.plot(t_sim,x2_sim) plt.figure(2) plt.subplot(2,1,1) plt.plot(t_sim,u1_sim,'r') plt.subplot(2,1,2) plt.plot(t_sim,u2_sim,'r') # Compile the Optimica model to an XML file model_name = compile_fmux("QuadTankPack.QuadTank_ParEstCasADi", curr_dir+"/files/QuadTankPack.mop") # Load the model model_casadi=CasadiModel(model_name) """ The collocation algorithm minimizes, if the parameter_estimation_data option is set, a quadrature approximation of the integral \int_{t_0}^{t_f} (y(t)-y^{meas}(t))^T Q (y(t)-y^{meas}(t)) dt The measurement data is given as a matrix where the first column is time and the following column contains data corresponding to the variable names given in the measured_variables list. Notice that input trajectories used in identification experiments are handled using the errors in variables method, i.e., deviations from the measured inputs are penalized in the cost function, rather than forcing the inputs to follow the measurement profile exactly. The weighting matrix Q may be used to express that inputs are typically more reliable than than measured outputs. """ # Create measurement data Q = N.diag([1., 1., 10., 10.]) data_x1 = N.vstack([t_meas, y1_meas]) data_x2 = N.vstack([t_meas, y2_meas]) data_u1 = N.vstack([t_meas, u1]) data_u2 = N.vstack([t_meas, u2]) unconstrained = OrderedDict() unconstrained['qt.x1'] = data_x1 unconstrained['qt.x2'] = data_x2 unconstrained['u1'] = data_u1 unconstrained['u2'] = data_u2 measurement_data = MeasurementData(Q=Q, unconstrained=unconstrained) opts = model_casadi.optimize_options() opts['n_e'] = 60 opts['measurement_data'] = measurement_data res = model_casadi.optimize(options=opts) # Load state profiles x1_opt = res["qt.x1"] x2_opt = res["qt.x2"] x3_opt = res["qt.x3"] x4_opt = res["qt.x4"] u1_opt = res["qt.u1"] u2_opt = res["qt.u2"] t_opt = res["time"] # Extract optimal values of parameters a1_opt = res.final("qt.a1") a2_opt = res.final("qt.a2") # Print and assert optimal parameter values print('a1: ' + str(a1_opt*1e4) + 'cm^2') print('a2: ' + str(a2_opt*1e4) + 'cm^2') a_ref = [0.02656702, 0.02713898] N.testing.assert_allclose(1e4 * N.array([a1_opt, a2_opt]), [0.02656702, 0.02713898], rtol=1e-4) # Plot if with_plots: plt.figure(1) plt.subplot(2,2,1) plt.plot(t_opt,x3_opt,'k') plt.subplot(2,2,2) plt.plot(t_opt,x4_opt,'k') plt.subplot(2,2,3) plt.plot(t_opt,x1_opt,'k') plt.subplot(2,2,4) plt.plot(t_opt,x2_opt,'k') plt.figure(2) plt.subplot(2,1,1) plt.plot(t_opt,u1_opt,'k') plt.subplot(2,1,2) plt.plot(t_opt,u2_opt,'k') plt.show()
def load(cls, path): model_name = basename(path) logger.debug('Loading model "%s"', model_name) model = cls(load_fmu(path, log_file_name=datetime.now().strftime(f'%Y-%m-%d_{model_name}.txt'))) logger.debug('Successfully loaded model "%s"', model_name) return model
def run_simulator (self, tool): ''' Function for running FMUs exported from Dymola, JModelica, and OpenModelica with PyFMI. ''' try: from pyfmi import load_fmu except BaseException: print ('PyFMI not installed. Test will not be be run.') return if (tool=='openmodelica' and platform.system().lower() == 'linux'): print ('tool={!s} is not supported on Linux'.format(tool)) return else: # Export FMUs which are needed to run the cases. if tool == 'openmodelica': modPat = 'OPENMODELICALIBRARY' mosT = MOS_TEMPLATE_PATH_OPENMODELICA elif tool == 'dymola': modPat = 'MODELICAPATH' mosT = MOS_TEMPLATE_PATH_DYMOLA elif tool == 'jmodelica': # Unset environment variable if (os.environ.get('MODELICAPATH') is not None): del os.environ['MODELICAPATH'] modPat = None mosT = MOS_TEMPLATE_PATH_JMODELICA for version in ['2']: if (tool == 'openmodelica' or tool == 'jmodelica'): version = str(float(version)) for api in ['me']: if (tool == 'openmodelica' and version == '1.0' and api == 'cs'): print ( 'tool={!s} with FMI version={!s} and FMI API={!s} is not supported.'.format( tool, version, api)) continue for cs_xml in ['true']: if (version == '1'): continue Simulator_Test = simulator.SimulatorToFMU( '', XML_INPUT_FILE, SimulatorToFMU_LIB_PATH, MO_TEMPLATE_PATH, mosT, XSD_FILE_PATH, '27', python_scripts_path, version, api, tool, None, modPat, cs_xml, 'true', None) print ( 'Export the simulator with tool={!s}, FMI version={!s}, FMI API={!s}'.format( tool, version, api)) start = datetime.now() Simulator_Test.print_mo() Simulator_Test.generate_fmu() Simulator_Test.clean_temporary() Simulator_Test.rewrite_fmu() end = datetime.now() print( 'Export the simulator as an FMU in {!s} seconds.'.format( (end - start).total_seconds())) fmu_path = os.path.join( script_path, '..', 'fmus', tool, platform.system().lower()) print( 'Copy simulator.fmu to {!s}.'.format(fmu_path)) shutil.copy2('simulator.fmu', fmu_path) fmu_path = os.path.join( script_path, '..', 'fmus', tool, platform.system().lower(), 'simulator.fmu') # Parameters which will be arguments of the function start_time = 0.0 stop_time = 5.0 print ('Starting the simulation with {!s}'.format(tool)) start = datetime.now() simulator_input_valref = [] simulator_output_valref = [] sim_mod = load_fmu(fmu_path, log_level=7) sim_mod.setup_experiment( start_time=start_time, stop_time=stop_time) # Define the inputs simulator_input_names = ['v'] simulator_input_values = [220.0] simulator_output_names = ['i'] # Get the value references of simulator inputs for elem in simulator_input_names: simulator_input_valref.append( sim_mod.get_variable_valueref(elem)) # Get the value references of simulator outputs for elem in simulator_output_names: simulator_output_valref.append( sim_mod.get_variable_valueref(elem)) # Set the flag to save the results sim_mod.set('_saveToFile', 'false') # Initialize the FMUs sim_mod.initialize() # Call event update prior to entering continuous mode. sim_mod.event_update() # Enter continuous time mode sim_mod.enter_continuous_time_mode() sim_mod.set_real(simulator_input_valref, simulator_input_values) end = datetime.now() print( 'Ran a single Simulator simulation with {!s} FMU={!s} in {!s} seconds.'.format( tool, fmu_path, (end - start).total_seconds())) if not (tool=='openmodelica'): # PyFMI fails to get the output of an OpenModelica FMU self.assertEqual( sim_mod.get_real( sim_mod.get_variable_valueref('i')), 1.0, 'Values are not matching.') # Terminate FMUs sim_mod.terminate()
pymodelica.environ['JVM_ARGS'] = '-Xmx4096m' sys.stdout.flush() ###################################################################### # Compile fmu fmu_name = compile_fmu(model, version="2.0", compiler_log_level='warning', compiler_options = {"generate_html_diagnostics" : False, "nle_solver_tol_factor": 1e-2}) ###################################################################### # Load model mod = load_fmu(fmu_name, log_level=3) ###################################################################### # Retrieve and set solver options x_nominal = mod.nominal_continuous_states opts = mod.simulate_options() #Retrieve the default options opts['solver'] = 'CVode' opts['ncp'] = 5000 if opts['solver'].lower() == 'cvode': # Set user-specified tolerance if it is smaller than the tolerance in the .mo file rtol = 1.0e-6 x_nominal = mod.nominal_continuous_states if len(x_nominal) > 0:
from pymodelica import compile_fmu from pyfmi import load_fmu libPath = r'C:\Users\vmg\Documents\Modelica\TRANSFORM-Library/TRANSFORM' modelName = 'TRANSFORM.Math.Examples.ComplexMath.check_csqrt' fmu = compile_fmu(modelName, libPath, target='cs') model = load_fmu(fmu) opts = model.simulate_options() opts['time_limit'] = 60 results = model.simulate(options=opts)
#~ caus_opts['inline'] = False #~ caus_opts['closed_form'] = True caus_opts['dense_tol'] = 1e10 caus_opts['inline_solved'] = True sim_res = ResultDymolaTextual( os.path.join(get_files_path(), "vehicle_turn_dymola.txt")) #~ sim_res = ResultDymolaTextual("opt_asphalt.txt") start_time = 0. final_time = sim_res.get_variable_data('time').t[-1] ncp = 100 class_name = "Car" file_paths = os.path.join(get_files_path(), "vehicle_turn.mop") opts = {'generate_html_diagnostics': True, 'state_initial_equations': True} model = transfer_model(class_name, file_paths, compiler_options=opts) init_fmu = load_fmu(compile_fmu(class_name, file_paths, compiler_options=opts)) # Create input data # This would have worked if one input was not constant... #~ columns = [0] #~ columns += [sim_res.get_column(input_var.getName()) for input_var in model.getVariables(model.REAL_INPUT)] #~ input = sim_res.get_data_matrix()[:, columns] input_matrix = sim_res.get_variable_data("time").x.reshape([-1, 1]) for input_var in model.getVariables(model.REAL_INPUT): input_data = sim_res.get_variable_data(input_var.getName()).x.reshape( [-1, 1]) if len(input_data) <= 2: input_data = np.array(input_matrix.shape[0] * [input_data[-1]]).reshape([-1, 1]) input_matrix = np.hstack([input_matrix, input_data])
] print(sys.version) print( all(os.path.isfile(os.path.join(moLib, "package.mo")) for moLib in moLibs)) print(os.getcwd()) # <codecell> compile model to fmu from pymodelica import compile_fmu model_name = 'BuildingSystems.Applications.ClimateAnalyses.FreeFloatingTemperature' my_fmu = compile_fmu(model_name, moLibs) # <codecell> simulate the fmu and store results from pyfmi import load_fmu myModel = load_fmu(my_fmu) opts = myModel.simulate_options() opts['solver'] = "CVode" opts['ncp'] = 8760 opts['result_handling'] = "file" opts["CVode_options"]['discr'] = 'BDF' opts['CVode_options']['iter'] = 'Newton' opts['CVode_options']['maxord'] = 5 opts['CVode_options']['atol'] = 1e-5 opts['CVode_options']['rtol'] = 1e-5 res = myModel.simulate(start_time=0.0, final_time=31530000.0, options=opts) #res = myModel.simulate(start_time=0.0, final_time=31536000.0, options=opts) # <codecell> plotting of the results
from pymodelica import compile_fmu from pyfmi import load_fmu import matplotlib.pyplot as plt from pyjmi.common.plotting import plot_gui # or pyfmi.common.plotting import plot_gui model_name = 'TestSys.HVACv6a_3room' mo_file1 = 'C:\Users\James\OneDrive\Documents\Berkeley\HVAC\Modelica\Test\TestSys\TestSys' mo_file2 = 'C:\Users\James\Desktop\Buildings 4.0.0' mo_files = mo_file1 + ',' + mo_file2 # Compile fmu fmu = compile_fmu(model_name, mo_files) # Load fmu model = load_fmu(fmu) # if already compiled fmu, can use fmu from file and save time from recompiling model = load_fmu(model_name.replace('.', '_') + '.fmu') # model = load_fmu('TestSys_HVACv3a_weather_load.fmu') # make sure working directory is correct # model parameters setting model.set(param, param_val) # res = model.simulate(final_time = 3600.) # res = model.simulate(start_time = 0., final_time = 3600.) opts = model.simulate_options() # opts['solver'] = 'RodasODE'#'RungeKutta34'#'Radau5ODE'#'CVode' opts['ncp'] = 1440 # Changing the number of communication points res = model.simulate(options=opts, start_time=0., final_time=86400.) plot_gui.startGUI()
def run_demo(with_plots=True): """ This example is based on the Hicks-Ray Continuously Stirred Tank Reactors (CSTR) system. The system has two states, the concentration and the temperature. The control input to the system is the temperature of the cooling flow in the reactor jacket. The chemical reaction in the reactor is exothermic, and also temperature dependent; high temperature results in high reaction rate. The problem is solved using the CasADi-based collocation algorithm through the MPC-class. FMI is used for initialization and simulation purposes. The following steps are demonstrated in this example: 1. How to generate an initial guess for a direct collocation method by means of simulation with a constant input. The trajectories resulting from the simulation are used to initialize the variables in the transcribed NLP, in the first sample(optimization). 2. An optimal control problem is defined where the objective is to transfer the state of the system from stationary point A to point B. An MPC object for the optimization problem is created. After each sample the NLP is updated with an estimate of the states in the next sample. The estimate is done by simulating the model for one sample period with the optimal input calculated in the optimization as input. To each estimate a normally distributed noise, with the mean 0 and standard deviation 0.5% of the nominal value of each state, is added. The MPC object uses the result from the previous optimization as initial guess for the next optimization (for all but the first optimization, where the simulation result from #1 is used instead). (3.) If with_plots is True we compile the same optimization problem again and define the options so that the op has the same options and resolution as the op we solved through the MPC-class. By same resolution we mean that both op should have the same mesh and blocking factors. This allows us to compare the MPC-results to an open loop optimization. Note that the MPC-results contains noise while the open loop optimization does not. """ ### 1. Compute initial guess trajectories by means of simulation # Locate the Modelica and Optimica code file_path = os.path.join(get_files_path(), "CSTR.mop") # Compile and load the model used for simulation sim_fmu = compile_fmu("CSTR.CSTR_MPC_Model", file_path, compiler_options={"state_initial_equations": True}) sim_model = load_fmu(sim_fmu) # Define stationary point A and set initial values and inputs c_0_A = 956.271352 T_0_A = 250.051971 sim_model.set('_start_c', c_0_A) sim_model.set('_start_T', T_0_A) sim_model.set('Tc', 280) init_res = sim_model.simulate(start_time=0., final_time=150) ### 2. Define the optimal control problem and solve it using the MPC class # Compile and load optimization problem op = transfer_optimization_problem( "CSTR.CSTR_MPC", file_path, compiler_options={"state_initial_equations": True}) # Define MPC options sample_period = 3 # s horizon = 33 # Samples on the horizon n_e_per_sample = 1 # Collocation elements / sample n_e = n_e_per_sample * horizon # Total collocation elements finalTime = 150 # s number_samp_tot = int(finalTime / sample_period) # Total number of samples to do # Create blocking factors with quadratic penalty and bound on 'Tc' bf_list = [n_e_per_sample] * (horizon / n_e_per_sample) factors = {'Tc': bf_list} du_quad_pen = {'Tc': 500} du_bounds = {'Tc': 30} bf = BlockingFactors(factors, du_bounds, du_quad_pen) # Set collocation options opt_opts = op.optimize_options() opt_opts['n_e'] = n_e opt_opts['n_cp'] = 2 opt_opts['init_traj'] = init_res opt_opts['blocking_factors'] = bf if with_plots: # Compile and load a new instance of the op to compare the MPC results # with an open loop optimization op_open_loop = transfer_optimization_problem( "CSTR.CSTR_MPC", file_path, compiler_options={"state_initial_equations": True}) op_open_loop.set('_start_c', float(c_0_A)) op_open_loop.set('_start_T', float(T_0_A)) # Copy options from MPC optimization open_loop_opts = copy.deepcopy(opt_opts) # Change n_e and blocking_factors so op_open_loop gets the same # resolution as op open_loop_opts['n_e'] = number_samp_tot bf_list_ol = [n_e_per_sample] * (number_samp_tot / n_e_per_sample) factors_ol = {'Tc': bf_list_ol} bf_ol = BlockingFactors(factors_ol, du_bounds, du_quad_pen) open_loop_opts['blocking_factors'] = bf_ol open_loop_opts['IPOPT_options']['print_level'] = 0 constr_viol_costs = {'T': 1e6} # Create the MPC object MPC_object = MPC(op, opt_opts, sample_period, horizon, constr_viol_costs=constr_viol_costs, noise_seed=1) # Set initial state x_k = {'_start_c': c_0_A, '_start_T': T_0_A} # Update the state and optimize number_samp_tot times for k in range(number_samp_tot): # Update the state and compute the optimal input for next sample period MPC_object.update_state(x_k) u_k = MPC_object.sample() # Reset the model and set the new initial states before simulating # the next sample period with the optimal input u_k sim_model.reset() sim_model.set(x_k.keys(), x_k.values()) sim_res = sim_model.simulate(start_time=k * sample_period, final_time=(k + 1) * sample_period, input=u_k) # Extract state at end of sample_period from sim_res and add Gaussian # noise with mean 0 and standard deviation 0.005*(state_current_value) x_k = MPC_object.extract_states(sim_res, mean=0, st_dev=0.005) # Extract variable profiles MPC_object.print_solver_stats() complete_result = MPC_object.get_complete_results() c_res_comp = complete_result['c'] T_res_comp = complete_result['T'] Tc_res_comp = complete_result['Tc'] time_res_comp = complete_result['time'] # Verify solution for testing purposes try: import casadi except: pass else: Tc_norm = N.linalg.norm(Tc_res_comp) / N.sqrt(len(Tc_res_comp)) assert (N.abs(Tc_norm - 311.7362) < 1e-3) c_norm = N.linalg.norm(c_res_comp) / N.sqrt(len(c_res_comp)) assert (N.abs(c_norm - 653.5369) < 1e-3) T_norm = N.linalg.norm(T_res_comp) / N.sqrt(len(T_res_comp)) assert (N.abs(T_norm - 328.0852) < 1e-3) # Plot the results if with_plots: ### 3. Solve the original optimal control problem without MPC res = op_open_loop.optimize(options=open_loop_opts) c_res = res['c'] T_res = res['T'] Tc_res = res['Tc'] time_res = res['time'] # Get reference values Tc_ref = op.get('Tc_ref') T_ref = op.get('T_ref') c_ref = op.get('c_ref') # Plot plt.close('MPC') plt.figure('MPC') plt.subplot(3, 1, 1) plt.plot(time_res_comp, c_res_comp) plt.plot(time_res, c_res) plt.plot([time_res[0], time_res[-1]], [c_ref, c_ref], '--') plt.legend( ('MPC with noise', 'Open-loop without noise', 'Reference value')) plt.grid() plt.ylabel('Concentration') plt.title('Simulated trajectories') plt.subplot(3, 1, 2) plt.plot(time_res_comp, T_res_comp) plt.plot(time_res, T_res) plt.plot([time_res[0], time_res[-1]], [T_ref, T_ref], '--') plt.grid() plt.ylabel('Temperature [C]') plt.subplot(3, 1, 3) plt.step(time_res_comp, Tc_res_comp) plt.step(time_res, Tc_res) plt.plot([time_res[0], time_res[-1]], [Tc_ref, Tc_ref], '--') plt.grid() plt.ylabel('Cooling temperature [C]') plt.xlabel('time') plt.show()
def test_simulate(self): """Simulate an fmu.""" model = pyfmi.load_fmu(self.path_fmu) model.simulate(options={'silent_mode': True})
index=True) #===================================================================== # Generate variables from model #===================================================================== # Initialize data frame df = gen.create_df() file_name = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'BESTESTHydronic') class_name = 'BESTESTHydronic.TestCase' # Compile the model to generate the data fmu_path = compile_fmu(file_name=file_name, class_name=class_name) # Load FMU model = load_fmu(fmu_path) # Set number of communication points options = model.simulate_options() options['ncp'] = len(gen.time) - 1 # Simulate res = model.simulate(start_time=gen.time[0], final_time=gen.time[-1], options=options) keysMap = {} # Occupancy schedules keysMap['Occupancy[1]'] = 'yOcc.y'
def test_reset(self): """Reset an fmu.""" model = pyfmi.load_fmu(self.path_fmu) model.simulate(options={'silent_mode': True}) model.reset() model.simulate(options={'silent_mode': True})
import os from collections import OrderedDict from scipy.io.matlab.mio import loadmat import numpy as N from pymodelica import compile_fmu from pyfmi import load_fmu from pyjmi import transfer_optimization_problem from pyjmi.optimization.casadi_collocation import ExternalData from sklearn.metrics import r2_score import json import scipy.interpolate as interpolate # Compile and load FMU, which is used for simulation model = load_fmu(compile_fmu('OrderReduction.RCOrderReduction', "OrderReduction.mop")) # Transfer problem to CasADi Interface, which is used for estimation op = transfer_optimization_problem("OrderReduction.reduceOrder", "OrderReduction.mop") # get the model order n = int(model.get('n')) print(n) #model.set_integer('n', n) ## experiment time startTime = 0 finalTime = 172800 ## Load measurement data from file meas = pd.read_csv('LTM_2days.csv', index_col=[0])
sys.exit(1) # Find the model variable output list file if present if args.var is not None: # Use specified variable output list file model_var = os.path.abspath(args.var) if not os.path.isfile(model_var): print('Error: Specified variable output list file not found:', model_var) sys.exit(1) else: # Look for default variable output list file model_var = os.path.join(model_dir, model + '.var') if os.path.isfile(model_var): args.var = model_var # Load the FMU try: fmu = load_fmu(model_fmu, log_level=args.log) except Exception as err: if err: print('Error: ' + str(err)) print('FMU file: ' + model_fmu) sys.exit(1) fmu.set_max_log_size(2073741824) # = 2*1024^3 (about 2GB) # Set simulation options opt = fmu.simulate_options() opt['solver'] = args.solver if args.res == 'memory': # In-memory results: Signal files generated after simulation opt['result_handling'] = 'memory' elif args.res == 'binary': # Binary .mat results file opt['result_handling'] = 'binary' opt['result_file_name'] = model + '.mat' elif args.res == 'csv': # CSV results file
def __init__(self, time_step: float = 1e-4, time_start: float = 0, reward_fun: Callable[[List[str], np.ndarray], float] = lambda cols, obs: 1, log_level: int = logging.WARNING, solver_method: str = 'LSODA', max_episode_steps: Optional[int] = 200, model_params: Optional[Dict[str, Union[Callable[[float], float], float]]] = None, model_input: Optional[Sequence[str]] = None, model_output: Optional[Union[dict, Sequence[str]]] = None, model_path: str = '../fmu/grid.network.fmu', viz_mode: Optional[str] = 'episode', viz_cols: Optional[Union[str, List[Union[str, PlotTmpl]]]] = None, history: EmptyHistory = FullHistory()): """ Initialize the Environment. The environment can only be used after reset() is called. :param time_step: step size of the simulation in seconds :param time_start: offset of the time in seconds :param reward_fun: The function receives as a list of variable names and a np.ndarray of the values of the current observation. The separation is mainly for performance reasons, such that the resolution of data indices can be cached. It must return the reward of this timestep as float. It should return np.nan or -np.inf or None in case of a failiure. It should have no side-effects :param log_level: logging granularity. see logging in stdlib :param solver_method: solver of the scipy.integrate.solve_ivp function :param max_episode_steps: maximum number of episode steps. The end time of the episode is calculated by the time resolution and the number of steps. If set to None, the environment will never finish because of step sizes, but it might still stop because of system failiure (-inf reward) :param model_params: parameters of the FMU. dictionary of variable names and scalars or callables. If a callable is provided it is called every time step with the current time. This callable must return a float that is passed to the fmu. :param model_input: list of strings. Each string representing a FMU input variable. :param model_output: nested dictionaries containing nested lists of strings. The keys of the nested dictionaries will be flattened down and appended to their children and finally prepended to the strings in the nested lists. The strings final strings represent variables from the FMU and the nesting of the lists conveys structure used in the visualisation >>> {'inverter': {'condensator': ['i', 'v']}} results in >>> ['inverter.condensator.i', 'inverter.condensator.v'] :param model_path: Path to the FMU :param viz_mode: specifies how and if to render - 'episode': render after the episode is finished - 'step': render after each time step - None: disable visualization :param viz_cols: enables specific columns while plotting - None: all columns will be used for vizualization (default) - string: will be interpret as regex. all fully matched columns names will be enabled - list of strings: Each string might be a unix-shell style wildcard like "*.i" to match all data series ending with ".i". - list of PlotTmpl: Each template will result in a plot :param history: history to store observations and measurement (from the agent) after each step """ if model_input is None: raise ValueError( 'Please specify model_input variables from your OM FMU.') if model_output is None: raise ValueError( 'Please specify model_output variables from your OM FMU.') if viz_mode not in self.viz_modes: raise ValueError( f'Please select one of the following viz_modes: {self.viz_modes}' ) self.viz_mode = viz_mode logger.setLevel(log_level) self.solver_method = solver_method # load model from fmu model_name = basename(model_path) logger.debug("Loading model {}".format(model_name)) self.model: FMUModelME2 = load_fmu( model_path, log_file_name=datetime.now().strftime( f'%Y-%m-%d_{model_name}.txt')) logger.debug("Successfully loaded model {}".format(model_name)) # if you reward policy is different from just reward/penalty - implement custom step method self.reward = reward_fun self._failed = False # Parameters required by this implementation self.max_episode_steps = max_episode_steps self.time_start = time_start self.time_step_size = time_step self.time_end = np.inf if max_episode_steps is None \ else self.time_start + max_episode_steps * self.time_step_size # if there are parameters, we will convert all scalars to constant functions. model_params = model_params or dict() # the "partial" is needed because of some absurd python behaviour https://stackoverflow.com/a/34021333/13310191 self.model_parameters = { var: (val if callable(val) else partial(lambda t, val_: val_, val_=val)) for var, val in model_params.items() } self.sim_time_interval = None self._state = [] self.measurement = [] self.record_states = viz_mode == 'episode' self.history = history self.history.cols = model_output self.model_input_names = model_input # variable names are flattened to a list if they have specified in the nested dict manner) self.model_output_names = self.history.cols self.viz_col_tmpls = [] if viz_cols is None: logger.info( 'Provide the option "viz_cols" if you wish to select only specific plots. ' 'The default behaviour is to plot all data series') self.viz_col_regex = '.*' elif isinstance(viz_cols, list): # strings are glob patterns that can be used in the regex patterns, tmpls = [], [] for elem in viz_cols: if isinstance(elem, str): patterns.append(translate(elem)) elif isinstance(elem, PlotTmpl): tmpls.append(elem) else: raise ValueError( '"viz_cols" list must contain only strings or PlotTmpl objects not' f' {type(viz_cols)}') self.viz_col_regex = '|'.join(patterns) self.viz_col_tmpls = tmpls elif isinstance(viz_cols, str): # is directly interpret as regex self.viz_col_regex = viz_cols else: raise ValueError( '"viz_cols" must be one type Optional[Union[str, List[Union[str, PlotTmpl]]]]' f'and not {type(viz_cols)}') # OpenAI Gym requirements d_i, d_o = len(self.model_input_names), len(self.model_output_names) self.action_space = gym.spaces.Box(low=np.full(d_i, -np.inf), high=np.full(d_i, np.inf)) self.observation_space = gym.spaces.Box(low=np.full(d_o, -np.inf), high=np.full(d_o, np.inf))