def run_optimization(sim_res, time, price, pv, bldg, plot = True, usePV = True): """ This function runs an optimization problem """ from pyjmi.optimization.casadi_collocation import MeasurementData from collections import OrderedDict # get current directory curr_dir = os.path.dirname(os.path.abspath(__file__)); # if pv panels are not used then remove power if usePV == False: pv = np.zeros(np.shape(pv)) # compile FMU path = os.path.join(curr_dir,"..","Models","ElectricalNetwork.mop") model_name = compile_fmux('ElectricNetwork.ACnetworkBatteryMngmtOpt_Money', path, compiler_options={"enable_variable_scaling":True}) # Load the model model_casadi = CasadiModel(model_name) # Get the inputs that should be eliminated from the optimization variables eliminated = OrderedDict() data_price = np.vstack([t_data, price]) eliminated['price'] = data_price #data_Q = np.vstack([t_data, np.zeros(Npoints)]) #eliminated['Q_batt'] = data_Q data_pv1 = np.vstack([t_data, np.squeeze(pv[:,0])]) eliminated['P_pv1'] = data_pv1 data_pv2 = np.vstack([t_data, np.squeeze(pv[:,1])]) eliminated['P_pv2'] = data_pv2 data_pv3 = np.vstack([t_data, np.squeeze(pv[:,2])]) eliminated['P_pv3'] = data_pv3 data_bldg1 = np.vstack([t_data, -np.squeeze(bldg[:,0])]) eliminated['P_bldg1'] = data_bldg1 data_bldg2 = np.vstack([t_data, -np.squeeze(bldg[:,1])]) eliminated['P_bldg2'] = data_bldg2 data_bldg3 = np.vstack([t_data, -np.squeeze(bldg[:,2])]) eliminated['P_bldg3'] = data_bldg3 measurement_data = MeasurementData(eliminated = eliminated) # define the optimization problem opts = model_casadi.optimize_options() opts['n_e'] = 60 opts['measurement_data'] = measurement_data opts['init_traj'] = sim_res.result_data # get the results of the optimization res = model_casadi.optimize(options = opts) if plot: plotFunction(sim_res, res) return res
def run_optimization(sim_res, time, price, pv, bldg): """ This function runs an optimization problem """ from pyjmi.optimization.casadi_collocation import MeasurementData from collections import OrderedDict # get current directory curr_dir = os.path.dirname(os.path.abspath(__file__)) # compile FMU path = os.path.join(curr_dir, "..", "Models", "ElectricalNetwork.mop") model_name = compile_fmux( 'ElectricNetwork.NetworkBatteryMngmtOpt_Money', path, compiler_options={"enable_variable_scaling": True}) # Load the model model_casadi = CasadiModel(model_name) # Get the inputs that should be eliminated from the optimization variables eliminated = OrderedDict() data_price = np.vstack([t_data, price]) eliminated['price'] = data_price data_pv1 = np.vstack([t_data, np.squeeze(pv[:, 0])]) eliminated['pv1'] = data_pv1 data_pv2 = np.vstack([t_data, np.squeeze(pv[:, 1])]) eliminated['pv2'] = data_pv2 data_pv3 = np.vstack([t_data, np.squeeze(pv[:, 2])]) eliminated['pv3'] = data_pv3 data_bldg1 = np.vstack([t_data, np.squeeze(bldg[:, 0])]) eliminated['bldg1'] = data_bldg1 data_bldg2 = np.vstack([t_data, np.squeeze(bldg[:, 1])]) eliminated['bldg2'] = data_bldg2 data_bldg3 = np.vstack([t_data, np.squeeze(bldg[:, 2])]) eliminated['bldg3'] = data_bldg3 measurement_data = MeasurementData(eliminated=eliminated) # define the optimization problem opts = model_casadi.optimize_options() opts['n_e'] = 50 opts['measurement_data'] = measurement_data opts['init_traj'] = sim_res.result_data # get the results of the optimization res = model_casadi.optimize(options=opts) plotCompare(sim_res, res)
def run_optimization(sim_res, time, price, pv, bldg): """ This function runs an optimization problem """ from pyjmi.optimization.casadi_collocation import MeasurementData from collections import OrderedDict # get current directory curr_dir = os.path.dirname(os.path.abspath(__file__)); # compile FMU path = os.path.join(curr_dir,"..","Models","ElectricalNetwork.mop") model_name = compile_fmux('ElectricNetwork.NetworkBatteryMngmtOpt_Money', path, compiler_options={"enable_variable_scaling":True}) # Load the model model_casadi = CasadiModel(model_name) # Get the inputs that should be eliminated from the optimization variables eliminated = OrderedDict() data_price = np.vstack([t_data, price]) eliminated['price'] = data_price data_pv1 = np.vstack([t_data, np.squeeze(pv[:,0])]) eliminated['pv1'] = data_pv1 data_pv2 = np.vstack([t_data, np.squeeze(pv[:,1])]) eliminated['pv2'] = data_pv2 data_pv3 = np.vstack([t_data, np.squeeze(pv[:,2])]) eliminated['pv3'] = data_pv3 data_bldg1 = np.vstack([t_data, np.squeeze(bldg[:,0])]) eliminated['bldg1'] = data_bldg1 data_bldg2 = np.vstack([t_data, np.squeeze(bldg[:,1])]) eliminated['bldg2'] = data_bldg2 data_bldg3 = np.vstack([t_data, np.squeeze(bldg[:,2])]) eliminated['bldg3'] = data_bldg3 measurement_data = MeasurementData(eliminated = eliminated) # define the optimization problem opts = model_casadi.optimize_options() opts['n_e'] = 50 opts['measurement_data'] = measurement_data opts['init_traj'] = sim_res.result_data # get the results of the optimization res = model_casadi.optimize(options = opts) plotCompare(sim_res, res)
def run_demo(with_plots=True): """ Demonstrate how to solve a dynamic optimization problem based on a Van der Pol oscillator system. """ curr_dir = os.path.dirname(os.path.abspath(__file__)) jn = compile_fmux("VDP_pack.VDP_Opt2", curr_dir + "/files/VDP.mop") model = CasadiModel(jn) opts = model.optimize_options(algorithm='CasadiPseudoSpectralAlg') opts['n_cp'] = 50 #opts['IPOPT_options']['hessian_approximation'] = 'limited-memory' res = model.optimize(algorithm='CasadiPseudoSpectralAlg', options=opts) # Extract variable profiles x1 = res['x1'] x2 = res['x2'] u = res['u'] time = res['time'] assert N.abs(res.final('x1') - 8.64330006e-07) < 1e-3 assert N.abs(res.final('x2') + 3.68158852e-07) < 1e-3 if with_plots: # Plot plt.figure(1) plt.clf() plt.subplot(311) plt.plot(time, x1, 'x-') plt.grid() plt.ylabel('x1') plt.subplot(312) plt.plot(time, x2, 'x-') plt.grid() plt.ylabel('x2') plt.subplot(313) plt.plot(time, u, 'x-') plt.grid() plt.ylabel('u') plt.xlabel('time') plt.show()
def run_demo(with_plots=True): """ Demonstrate how to solve a dynamic optimization problem based on a Van der Pol oscillator system. """ curr_dir = os.path.dirname(os.path.abspath(__file__)); jn = compile_fmux("VDP_pack.VDP_Opt2", curr_dir+"/files/VDP.mop") model = CasadiModel(jn) opts = model.optimize_options(algorithm='CasadiPseudoSpectralAlg') opts['n_cp'] = 50 #opts['IPOPT_options']['hessian_approximation'] = 'limited-memory' res = model.optimize(algorithm='CasadiPseudoSpectralAlg',options=opts) # Extract variable profiles x1 = res['x1'] x2 = res['x2'] u = res['u'] time = res['time'] assert N.abs(res.final('x1') - 8.64330006e-07) < 1e-3 assert N.abs(res.final('x2') + 3.68158852e-07) < 1e-3 if with_plots: # Plot plt.figure(1) plt.clf() plt.subplot(311) plt.plot(time,x1,'x-') plt.grid() plt.ylabel('x1') plt.subplot(312) plt.plot(time,x2,'x-') plt.grid() plt.ylabel('x2') plt.subplot(313) plt.plot(time,u,'x-') plt.grid() plt.ylabel('u') plt.xlabel('time') plt.show()
def run_demo(with_plots=True): """ Demonstrate how to optimize a VDP oscillator using LocalDAECollocationAlgOld. """ # Compile and load model curr_dir = os.path.dirname(os.path.abspath(__file__)); jn = compile_fmux("VDP_pack.VDP_Opt2", curr_dir + "/files/VDP.mop") model = CasadiModel(jn) # Set algorithm options opts = model.optimize_options() opts['graph'] = "SX" # Optimize res = model.optimize(options=opts) # Extract variable profiles x1 = res['x1'] x2 = res['x2'] u = res['u'] time = res['time'] assert N.abs(res.final('x1')) < 1e-3 assert N.abs(res.final('x2')) < 1e-3 # Plot if with_plots: plt.figure(1) plt.clf() plt.subplot(3, 1, 1) plt.plot(time, x1) plt.grid() plt.ylabel('x1') plt.subplot(3, 1, 2) plt.plot(time, x2) plt.grid() plt.ylabel('x2') plt.subplot(3, 1, 3) plt.plot(time, u) plt.grid() plt.ylabel('u') plt.xlabel('time') plt.show()
def run_demo(with_plots=True): curr_dir = os.path.dirname(os.path.abspath(__file__)); jmu_name = compile_jmu("Orbital", curr_dir+"/files/Hohmann.mop") comp_opts = {"normalize_minimum_time_problems": False} # Disable minimum time normalization fmux_name = compile_fmux("HohmannTransfer", curr_dir+"/files/Hohmann.mop", compiler_options=comp_opts) # Optimization model = CasadiModel(fmux_name) opts = model.optimize_options(algorithm="CasadiPseudoSpectralAlg") opts["n_cp"] = 40 # Number of collocation points opts["n_e"] = 2 # Number of phases opts["free_phases"] = True # The phase boundary is allowed to be changed in time opts["phase_options"] = ["t1"] # The phase boundary is connected to variable t1 opts["link_options"] = [(1,"vy","dy1"),(1,"vx","dx1")] # Allow for discontinuities between phase 1 and 2 for vy and vx. # The discontinuities are connected by dy1 and dx1 # Optimize res_opt = model.optimize(algorithm="CasadiPseudoSpectralAlg", options=opts) # Get results dx1,dy1,dx2,dy2 = res_opt.final("dx1"), res_opt.final("dy1"), res_opt.final("dx2"), res_opt.final("dy2") r1,r2,my = res_opt.final("rStart"), res_opt.final("rFinal"), res_opt.final("my") tf,t1 = res_opt.final("time"), res_opt.final("t1") # Verify solution using theoretical results # Assert dv1 assert N.abs( N.sqrt(dx1**2+dy1**2) - N.sqrt(my/r1)*(N.sqrt(2*r2/(r1+r2))-1) ) < 1e-1 #Assert dv2 assert N.abs( N.sqrt(dx2**2+dy2**2) - N.sqrt(my/r2)*(1-N.sqrt(2*r1/(r1+r2))) ) < 1e-1 #Assert transfer time assert N.abs( tf-t1 - N.pi*((r1+r2)**3/(8*my))**0.5 ) < 1e-1 # Verify solution by simulation model = JMUModel(jmu_name) # Retrieve the options opts = model.simulate_options() opts["ncp"] = 100 opts["solver"] = "IDA" opts["initialize"] = False # Simulation of Phase 1 res = model.simulate(final_time=t1,options=opts) x_phase_1,y_phase_1 = res["x"], res["y"] # Simulation of Phase 2 model.set("vx", dx1 + res.final("vx")) model.set("vy", dy1 + res.final("vy")) res = model.simulate(start_time=t1,final_time=tf,options=opts) x_phase_2,y_phase_2 = res["x"], res["y"] # Simulation of Phase 3 (verify that we are still in orbit) model.set("vx", dx2 + res.final("vx")) model.set("vy", dy2 + res.final("vy")) res = model.simulate(start_time=tf, final_time=tf*2, options=opts) x_phase_3,y_phase_3 = res["x"], res["y"] if with_plots: # Plot Earth r = 1.0 xE = r*N.cos(N.linspace(0,2*N.pi,200)) yE = r*N.sin(N.linspace(0,2*N.pi,200)) plt.plot(xE,yE,label="Earth") # Plot Orbits r = res.final("rStart") xS = r*N.cos(N.linspace(0,2*N.pi,200)) yS = r*N.sin(N.linspace(0,2*N.pi,200)) plt.plot(xS,yS,label="Low Orbit") r = res.final("rFinal") xSE = r*N.cos(N.linspace(0,2*N.pi,200)) ySE = r*N.sin(N.linspace(0,2*N.pi,200)) plt.plot(xSE,ySE,label="High Orbit") # Plot Satellite trajectory x_sim=N.hstack((N.hstack((x_phase_1,x_phase_2)),x_phase_3)) y_sim=N.hstack((N.hstack((y_phase_1,y_phase_2)),y_phase_3)) plt.plot(x_sim,y_sim,"-",label="Satellite") # Plot Rocket Burns plt.arrow(x_phase_1[-1],y_phase_1[-1],0.5*dx1,0.5*dy1, width=0.01,label="dv1") plt.arrow(x_phase_2[-1],y_phase_2[-1],0.5*dx2,0.5*dy2, width=0.01,label="dv2") plt.legend() plt.show()
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 a 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 = load_fmu(init_fmu) 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 c_init_sim = init_res['cstr.c'] T_init_sim = init_res['cstr.T'] Tc_init_sim = init_res['cstr.Tc'] t_init_sim = init_res['time'] # 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 model fmux = compile_fmux("CSTR.CSTR_Opt2", file_path) # Load model cstr = CasadiModel(fmux) # Set reference values cstr.set('Tc_ref', Tc_0_B) cstr.set('c_ref', c_0_B) cstr.set('T_ref', T_0_B) # Set initial values cstr.set('cstr.c_init', c_0_A) cstr.set('cstr.T_init', T_0_A) # Set options opt_opts = cstr.optimize_options() opt_opts['n_e'] = 100 # Number of elements opt_opts['init_traj'] = init_res.result_data # Solve the optimal control problem res = cstr.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['c_ref'] T_ref = res['T_ref'] Tc_ref = res['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.8585429) < 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 res = sim_model.simulate(start_time=0., final_time=150., input=('Tc', opt_input)) # Extract variable profiles c_sim = res['c'] T_sim = res['T'] Tc_sim = res['Tc'] time_sim = res['time'] # 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, '--', lw=5) plt.plot(time_sim, c_sim, lw=2) plt.legend(('optimized', 'simulated')) plt.grid(True) plt.ylabel('Concentration') plt.title('Verification') plt.subplot(3, 1, 2) plt.plot(time_res, T_res, '--', lw=5) plt.plot(time_sim, T_sim, lw=2) plt.grid(True) plt.ylabel('Temperature') plt.subplot(3, 1, 3) plt.plot(time_res, Tc_res, '--', lw=5) plt.plot(time_sim, Tc_sim, lw=2) plt.grid(True) plt.ylabel('Cooling temperature') plt.xlabel('time') plt.show()
def run_demo(with_plots=True): curr_dir = os.path.dirname(os.path.abspath(__file__)) jmu_name = compile_jmu("Orbital", curr_dir + "/files/Hohmann.mop") comp_opts = { "normalize_minimum_time_problems": False } # Disable minimum time normalization fmux_name = compile_fmux("HohmannTransfer", curr_dir + "/files/Hohmann.mop", compiler_options=comp_opts) # Optimization model = CasadiModel(fmux_name) opts = model.optimize_options(algorithm="CasadiPseudoSpectralAlg") opts["n_cp"] = 40 # Number of collocation points opts["n_e"] = 2 # Number of phases opts[ "free_phases"] = True # The phase boundary is allowed to be changed in time opts["phase_options"] = [ "t1" ] # The phase boundary is connected to variable t1 opts["link_options"] = [ (1, "vy", "dy1"), (1, "vx", "dx1") ] # Allow for discontinuities between phase 1 and 2 for vy and vx. # The discontinuities are connected by dy1 and dx1 # Optimize res_opt = model.optimize(algorithm="CasadiPseudoSpectralAlg", options=opts) # Get results dx1, dy1, dx2, dy2 = res_opt.final("dx1"), res_opt.final( "dy1"), res_opt.final("dx2"), res_opt.final("dy2") r1, r2, my = res_opt.final("rStart"), res_opt.final( "rFinal"), res_opt.final("my") tf, t1 = res_opt.final("time"), res_opt.final("t1") # Verify solution using theoretical results # Assert dv1 assert N.abs( N.sqrt(dx1**2 + dy1**2) - N.sqrt(my / r1) * (N.sqrt(2 * r2 / (r1 + r2)) - 1)) < 1e-1 #Assert dv2 assert N.abs( N.sqrt(dx2**2 + dy2**2) - N.sqrt(my / r2) * (1 - N.sqrt(2 * r1 / (r1 + r2)))) < 1e-1 #Assert transfer time assert N.abs(tf - t1 - N.pi * ((r1 + r2)**3 / (8 * my))**0.5) < 1e-1 # Verify solution by simulation model = JMUModel(jmu_name) # Retrieve the options opts = model.simulate_options() opts["ncp"] = 100 opts["solver"] = "IDA" opts["initialize"] = False # Simulation of Phase 1 res = model.simulate(final_time=t1, options=opts) x_phase_1, y_phase_1 = res["x"], res["y"] # Simulation of Phase 2 model.set("vx", dx1 + res.final("vx")) model.set("vy", dy1 + res.final("vy")) res = model.simulate(start_time=t1, final_time=tf, options=opts) x_phase_2, y_phase_2 = res["x"], res["y"] # Simulation of Phase 3 (verify that we are still in orbit) model.set("vx", dx2 + res.final("vx")) model.set("vy", dy2 + res.final("vy")) res = model.simulate(start_time=tf, final_time=tf * 2, options=opts) x_phase_3, y_phase_3 = res["x"], res["y"] if with_plots: # Plot Earth r = 1.0 xE = r * N.cos(N.linspace(0, 2 * N.pi, 200)) yE = r * N.sin(N.linspace(0, 2 * N.pi, 200)) plt.plot(xE, yE, label="Earth") # Plot Orbits r = res.final("rStart") xS = r * N.cos(N.linspace(0, 2 * N.pi, 200)) yS = r * N.sin(N.linspace(0, 2 * N.pi, 200)) plt.plot(xS, yS, label="Low Orbit") r = res.final("rFinal") xSE = r * N.cos(N.linspace(0, 2 * N.pi, 200)) ySE = r * N.sin(N.linspace(0, 2 * N.pi, 200)) plt.plot(xSE, ySE, label="High Orbit") # Plot Satellite trajectory x_sim = N.hstack((N.hstack((x_phase_1, x_phase_2)), x_phase_3)) y_sim = N.hstack((N.hstack((y_phase_1, y_phase_2)), y_phase_3)) plt.plot(x_sim, y_sim, "-", label="Satellite") # Plot Rocket Burns plt.arrow(x_phase_1[-1], y_phase_1[-1], 0.5 * dx1, 0.5 * dy1, width=0.01, label="dv1") plt.arrow(x_phase_2[-1], y_phase_2[-1], 0.5 * dx2, 0.5 * dy2, width=0.01, label="dv2") plt.legend() plt.show()
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(algorithm="LocalDAECollocationAlg", 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 run_demo(with_plots=True): """ This example is based on a combined cycle power plant (CCPP). The model has 9 states, 128 algebraic variables and 1 control variable. The task is to minimize the time required to perform a warm start-up of the power plant. This problem has become highly industrially relevant during the last few years, due to an increasing need to improve power generation flexibility. The example consists of the following steps: 1. Simulating the system using a simple input trajectory. 2. Solving the optimal control problem using the result from the first step to initialize the non-linear program. 3. Verifying the result from the second step by simulating the system once more usng the optimized input trajectory. The model was developed by Francesco Casella and was published in @InProceedings{CFA2011, author = "Casella, Francesco and Donida, Filippo and {\AA}kesson, Johan", title = "Object-Oriented Modeling and Optimal Control: A Case Study in Power Plant Start-Up", booktitle = "18th IFAC World Congress", address = "Milano, Italy", year = 2011, month = aug } """ ### 1. Compute initial guess trajectories by means of simulation # Locate the Modelica and Optimica code file_paths = (os.path.join(get_files_path(), "CombinedCycle.mo"), os.path.join(get_files_path(), "CombinedCycleStartup.mop")) # Compile the optimization initialization model init_sim_fmu = compile_fmu("CombinedCycleStartup.Startup6Reference", file_paths) # Load the model init_sim_model = load_fmu(init_sim_fmu) # Simulate init_res = init_sim_model.simulate(start_time=0., final_time=10000.) # Extract variable profiles init_sim_plant_p = init_res['plant.p'] init_sim_plant_sigma = init_res['plant.sigma'] init_sim_plant_load = init_res['plant.load'] init_sim_time = init_res['time'] # Plot the initial guess trajectories if with_plots: plt.close(1) plt.figure(1) plt.subplot(3, 1, 1) plt.plot(init_sim_time, init_sim_plant_p * 1e-6) plt.ylabel('evaporator pressure [MPa]') plt.grid(True) plt.title('Initial guess obtained by simulation') plt.subplot(3, 1, 2) plt.plot(init_sim_time, init_sim_plant_sigma * 1e-6) plt.grid(True) plt.ylabel('turbine thermal stress [MPa]') plt.subplot(3, 1, 3) plt.plot(init_sim_time, init_sim_plant_load) plt.grid(True) plt.ylabel('input load [1]') plt.xlabel('time [s]') ### 2. Solve the optimal control problem # Compile model fmux = compile_fmux("CombinedCycleStartup.Startup6", file_paths) # Load model opt_model = CasadiModel(fmux) # Set options opt_opts = opt_model.optimize_options() opt_opts['n_e'] = 50 # Number of elements opt_opts['init_traj'] = init_res.result_data # Simulation result opt_opts['nominal_traj'] = init_res.result_data # Solve the optimal control problem opt_res = opt_model.optimize(options=opt_opts) # Extract variable profiles opt_plant_p = opt_res['plant.p'] opt_plant_sigma = opt_res['plant.sigma'] opt_plant_load = opt_res['plant.load'] opt_time = opt_res['time'] opt_input = N.vstack([opt_time, opt_plant_load]).T # Plot the optimized trajectories if with_plots: plt.close(2) plt.figure(2) plt.subplot(3, 1, 1) plt.plot(opt_time, opt_plant_p * 1e-6) plt.ylabel('evaporator pressure [MPa]') plt.grid(True) plt.title('Optimized trajectories') plt.subplot(3, 1, 2) plt.plot(opt_time, opt_plant_sigma * 1e-6) plt.grid(True) plt.ylabel('turbine thermal stress [MPa]') plt.subplot(3, 1, 3) plt.plot(opt_time, opt_plant_load) plt.grid(True) plt.ylabel('input load [1]') plt.xlabel('time [s]') # Verify solution for testing purposes try: import casadi except: pass else: cost = float(opt_res.solver.solver.output(casadi.NLP_SOLVER_F)) N.testing.assert_allclose(cost, 17492.465548193624, rtol=1e-5) ### 3. Simulate to verify the optimal solution # Compile model sim_fmu = compile_fmu("CombinedCycle.Optimization.Plants.CC0D_WarmStartUp", file_paths) # Load model sim_model = load_fmu(sim_fmu) # Simulate using optimized input sim_res = sim_model.simulate(start_time=0., final_time=4000., input=('load', opt_input)) # Extract variable profiles sim_plant_p = sim_res['p'] sim_plant_sigma = sim_res['sigma'] sim_plant_load = sim_res['load'] sim_time = sim_res['time'] # Plot the simulated trajectories if with_plots: plt.close(3) plt.figure(3) plt.subplot(3, 1, 1) plt.plot(opt_time, opt_plant_p * 1e-6, '--', lw=5) plt.hold(True) plt.plot(sim_time, sim_plant_p * 1e-6, lw=2) plt.ylabel('evaporator pressure [MPa]') plt.grid(True) plt.legend(('optimized', 'simulated'), loc='lower right') plt.title('Verification') plt.subplot(3, 1, 2) plt.plot(opt_time, opt_plant_sigma * 1e-6, '--', lw=5) plt.hold(True) plt.plot(sim_time, sim_plant_sigma * 1e-6, lw=2) plt.ylabel('turbine thermal stress [MPa]') plt.grid(True) plt.subplot(3, 1, 3) plt.plot(opt_time, opt_plant_load, '--', lw=5) plt.hold(True) plt.plot(sim_time, sim_plant_load, lw=2) plt.ylabel('input load [1]') plt.xlabel('time [s]') plt.grid(True) plt.show() # Verify solution for testing purposes N.testing.assert_allclose(opt_res.final('plant.p'), sim_res.final('p'), rtol=5e-3)
def run_demo(with_plots=True): """ Demonstrate how to solve a simple parameter estimation problem. """ # Locate model file curr_dir = os.path.dirname(os.path.abspath(__file__)); model_path = curr_dir + "/files/ParameterEstimation_1.mop" # Compile the model into an FMU and FMUX fmu = compile_fmu("ParEst.SecondOrder", model_path) fmux = compile_fmux("ParEst.ParEstCasADi", model_path) # Load the model sim_model = load_fmu(fmu) opt_model = CasadiModel(fmux) # Simulate model with nominal parameters sim_res = sim_model.simulate(final_time=10) # Extract nominal trajectories t_sim = sim_res['time'] x1_sim = sim_res['x1'] x2_sim = sim_res['x2'] # Get measurement data with 1 Hz and add measurement noise sim_model = load_fmu(fmu) meas_res = sim_model.simulate(final_time=10, options={'ncp': 10}) x1_meas = meas_res['x1'] noise = [0.01463904, 0.0139424, 0.09834249, 0.0768069, 0.01971631, -0.03827911, 0.05266659, -0.02608245, 0.05270525, 0.04717024, 0.0779514] t_meas = N.linspace(0, 10, 11) y_meas = x1_meas + noise if with_plots: # Plot simulation plt.close(1) plt.figure(1) plt.subplot(2, 1, 1) plt.plot(t_sim, x1_sim) plt.grid() plt.plot(t_meas, y_meas, 'x') plt.ylabel('x1') plt.subplot(2, 1, 2) plt.plot(t_sim, x2_sim) plt.grid() plt.ylabel('x2') plt.show() # Create MeasurementData object Q = N.array([[1.]]) unconstrained = OrderedDict() unconstrained['sys.y'] = N.vstack([t_meas, y_meas]) measurement_data = MeasurementData(Q=Q, unconstrained=unconstrained) # Set optimization options opts = opt_model.optimize_options() opts['measurement_data'] = measurement_data opts['n_e'] = 16 # Optimize opt_res = opt_model.optimize(options=opts) # Extract variable profiles x1_opt = opt_res['sys.x1'] x2_opt = opt_res['sys.x2'] w_opt = opt_res.final('sys.w') z_opt = opt_res.final('sys.z') t_opt = opt_res['time'] # Assert results assert N.abs(opt_res.final('sys.x1') - 1.) < 1e-2 assert N.abs(w_opt - 1.05) < 1e-2 assert N.abs(z_opt - 0.47) < 1e-2 # Plot optimization result if with_plots: plt.close(2) plt.figure(2) plt.subplot(2, 1, 1) plt.plot(t_opt, x1_opt, 'g') plt.plot(t_sim, x1_sim) plt.plot(t_meas, y_meas, 'x') plt.grid() plt.subplot(2, 1, 2) plt.plot(t_opt, x2_opt, 'g') plt.grid() plt.plot(t_sim, x2_sim) plt.show() print("** Optimal parameter values: **") print("w = %f" % w_opt) print("z = %f" % z_opt)
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 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 a 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 = load_fmu(init_fmu) 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 c_init_sim = init_res['cstr.c'] T_init_sim = init_res['cstr.T'] Tc_init_sim = init_res['cstr.Tc'] t_init_sim = init_res['time'] # 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 model fmux = compile_fmux("CSTR.CSTR_Opt2", file_path) # Load model cstr = CasadiModel(fmux) # Set reference values cstr.set('Tc_ref', Tc_0_B) cstr.set('c_ref', c_0_B) cstr.set('T_ref', T_0_B) # Set initial values cstr.set('cstr.c_init', c_0_A) cstr.set('cstr.T_init', T_0_A) # Set options opt_opts = cstr.optimize_options() opt_opts['n_e'] = 100 # 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 = cstr.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['c_ref'] T_ref = res['T_ref'] Tc_ref = res['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.8585429) < 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-2) # 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, '--', lw=5) plt.plot(time_sim, c_sim, lw=2) plt.legend(('optimized', 'simulated')) plt.grid(True) plt.ylabel('Concentration') plt.title('Verification') plt.subplot(3, 1, 2) plt.plot(time_res, T_res, '--', lw=5) plt.plot(time_sim, T_sim, lw=2) plt.grid(True) plt.ylabel('Temperature') plt.subplot(3, 1, 3) plt.plot(time_res, Tc_res, '--', lw=5) plt.plot(time_sim, Tc_sim, lw=2) plt.grid(True) plt.ylabel('Cooling temperature') plt.xlabel('time') plt.show()