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): 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): """ 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()