def run_demo(with_plots=True): """ Demonstrate how to solve a minimum time dynamic optimization problem based on a Van der Pol oscillator system. """ file_paths = (os.path.join(get_files_path(), "JMExamples_opt.mop"), os.path.join(get_files_path(), "JMExamples.mo")) vdp = transfer_optimization_problem("JMExamples_opt.VDP_Opt_Min_Time", file_paths) res = vdp.optimize() # Extract variable profiles x1=res['x1'] x2=res['x2'] u=res['u'] t=res['time'] assert N.abs(res.final('finalTime') - 2.2811587) < 1e-3 if with_plots: # Plot plt.figure(1) plt.clf() plt.subplot(311) plt.plot(t,x1) plt.grid() plt.ylabel('x1') plt.subplot(312) plt.plot(t,x2) plt.grid() plt.ylabel('x2') plt.subplot(313) plt.plot(t,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 CasADiInterface. """ # Compile and load optimization problem from pyjmi import get_files_path, transfer_to_casadi_interface file_path = os.path.join(get_files_path(), "VDP.mop") op = transfer_to_casadi_interface("VDP_pack.VDP_Opt2", file_path) # Set algorithm options opts = op.optimize_options() opts['n_e'] = 30 # Optimize res = op.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): n_e = 20 delay_n_e = 5 horizon = 1.0 delay = horizon * delay_n_e / n_e # Compile and load optimization problem file_path = os.path.join(get_files_path(), "DelayedFeedbackOpt.mop") opt = transfer_optimization_problem("DelayTest", file_path) # Set value for u2(t) when t < delay opt.getVariable('u2').setAttribute('initialGuess', 0.25) # Set algorithm options opts = opt.optimize_options() opts['n_e'] = n_e # Set delayed feedback from u1 to u2 opts['delayed_feedback'] = {'u2': ('u1', delay_n_e)} # Optimize res = opt.optimize(options=opts) # Extract variable profiles x_res = res['x'] u1_res = res['u1'] u2_res = res['u2'] time_res = res['time'] # Plot results if with_plots: plt.plot(time_res, x_res, time_res, u1_res, time_res, u2_res) plt.hold(True) plt.plot(time_res + delay, u1_res, '--') plt.hold(False) plt.legend(('x', 'u1', 'u2', 'delay(u1)')) 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(): """ """ # Locate the model and file paths file_path = os.path.join(get_files_path(), "DrumBoiler.mop") model_name = "DrumBoilerpackage.DrumBoiler" # Load measurement data RCdata = get_test_data() measurements = RCdata['measurements'] time = RCdata['time'] # Extract control signal data from measurements inputs={} inputs['uc']= measurements.pop('uc') inputs['fc']= measurements.pop('fc') # Transfer model to Casadi interface op = transfer_optimization_problem(model_name, file_path, accept_model = True) op_opts = op.optimize_options() # Create greybox object GB = GreyBox(op, op_opts, measurements, inputs, time) # Set some variable attributes GB.set_variable_attribute(GB.get_noise_covariance_variable('E'), 'max', 100) GB.set_variable_attribute(GB.get_noise_covariance_variable('P'), 'max', 100) GB.set_variable_attribute('x10', 'initialGuess', 148) GB.set_variable_attribute('x20', 'initialGuess', 27.5) # Define null model free parameters and other parameters to free nullModelFree = set(['GreyBox_r_E', 'GreyBox_r_P', 'x10', 'x20']) optimizeParameters = set(["TD","TR","A4","distE","distP"]) # Define null model free parameters and other parameters to free nullModelFree = set(['GreyBox_r_E', 'GreyBox_r_P', 'x10', 'x20']) # Optimize null model identification = GB.identify(nullModelFree) # Create dictionaries for results testcases = [] for var in optimizeParameters: # Add var to set of free parameters testcases.append(identification.release([var])) print("=======================SUMMARY========================") results = identification.compare(testcases) # reference data nullModelReferenceCost = 5631.068823 #the cost from the null model reference = {'TD':{'cost':5466.596971, 'costred':164.471852, 'risk':0.000000},'TR':{'cost':5629.636935, 'costred':1.431888, 'risk':0.731872},'A4':{'cost':5630.900339, 'costred':0.168484, 'risk':0.996721} ,'distE':{'cost':4362.561987, 'costred':1268.506836, 'risk':0.000000},'distP':{'cost':4399.728897, 'costred':1231.339926, 'risk':0.000000}} #Create reference by running without framework tol = 1e-3 # Assert nullmodel assert(N.abs(identification.cost - nullModelReferenceCost) < tol) # Assert results for i, var in enumerate(optimizeParameters): assert(N.abs(results[i]['cost'] - reference[var]['cost']) < tol) assert(N.abs(results[i]['costred'] - reference[var]['costred']) < tol) assert(N.abs(results[i]['risk'] - reference[var]['risk']) < tol)
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) opts = sim_model.simulate_options() opts["CVode_options"]["maxh"] = 0.0 opts["ncp"] = 0 init_res = sim_model.simulate(start_time=0., final_time=150, options=opts) ### 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(list(x_k.keys()), list(x_k.values())) sim_res = sim_model.simulate(start_time=k*sample_period, final_time=(k+1)*sample_period, input=u_k, options=opts) # 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()
class_name = "Circuit" file_paths = "circuit.mo" opts = { 'eliminate_alias_variables': True, 'generate_html_diagnostics': True, 'variability_propagation': False } model = transfer_model(class_name, file_paths, compiler_options=opts) ncp = 500 * model.get('omega') init_fmu = load_fmu( compile_fmu(class_name, file_paths, compiler_options=opts)) elif problem == "vehicle": sim_res = ResultDymolaTextual( os.path.join(get_files_path(), "vehicle_turn_dymola.txt")) start_time = 0. final_time = sim_res.get_variable_data('time').t[-1] ncp = 500 if source != "Modelica": raise ValueError class_name = "Car" file_paths = os.path.join(get_files_path(), "vehicle_turn.mop") opts = {'generate_html_diagnostics': 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]
def run_demo(with_plots=True): """ This example is based on the multibody mechanics fourbar1 example from the Modelica Standard Library (MSL). The MSL example has been modified by adding a torque on the first revolute joint of the pendulum as a top-level input. The considered optimization problem is to control the translation along the prismatic joint at the other end of the closed kinematic loop. This example needs the linear solver MA57 to work. """ # Compile simulation model file_paths = (os.path.join(get_files_path(), "Fourbar1.mo"), os.path.join(get_files_path(), "Fourbar1.mop")) comp_opts = { 'inline_functions': 'all', 'dynamic_states': False, 'expose_temp_vars_in_fmu': True } model = load_fmu( compile_fmu('Fourbar1.Fourbar1Sim', file_paths, compiler_options=comp_opts)) # Load trajectories that are optimal subject to a smaller torque constraint and use to generate initial guess init_path = os.path.join(get_files_path(), "fourbar1_init.txt") init_res = LocalDAECollocationAlgResult( result_data=ResultDymolaTextual(init_path)) t = init_res['time'] u = init_res['u'] u_traj = ('u', N.transpose(N.vstack((t, u)))) sim_res = model.simulate(final_time=1.0, input=u_traj) # Set up optimization op = transfer_optimization_problem('Opt', file_paths, compiler_options=comp_opts) opts = op.optimize_options() opts['IPOPT_options']['linear_solver'] = "ma57" opts['IPOPT_options']['ma57_pivtol'] = 1e-3 opts['IPOPT_options']['ma57_automatic_scaling'] = "yes" opts['IPOPT_options']['mu_strategy'] = "adaptive" opts['n_e'] = 20 opts['init_traj'] = sim_res opts['nominal_traj'] = sim_res # Solve optimization problem res = op.optimize(options=opts) # Extract solution time = res['time'] s = res['fourbar1.j2.s'] phi = res['fourbar1.j1.phi'] u = res['u'] # Verify solution for testing purposes try: import casadi except: pass else: cost = float(res.solver.solver_object.output(casadi.NLP_SOLVER_F)) N.testing.assert_allclose(cost, 1.0455646e-03, rtol=5e-3) # Plot solution if with_plots: plt.close(1) plt.figure(1) plt.subplot(3, 1, 1) plt.plot(time, s) plt.ylabel('$s$') plt.xlabel('$t$') plt.grid() plt.subplot(3, 1, 2) plt.plot(time, s) plt.ylabel('$\phi$') plt.xlabel('$t$') plt.grid() plt.subplot(3, 1, 3) plt.plot(time, u) plt.ylabel('$u$') plt.xlabel('$t$') plt.grid() 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 is 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, separate_process=True) # 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 from pyjmi import transfer_to_casadi_interface op = transfer_to_casadi_interface("CombinedCycleStartup.Startup6", file_paths) # Set options opt_opts = op.optimize_options() opt_opts['n_e'] = 50 # Number of elements opt_opts['init_traj'] = init_res # Simulation result opt_opts['nominal_traj'] = init_res opt_opts['verbosity'] = 1 # Solve the optimal control problem opt_res = op.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_object.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): """ 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 some of the key features of the CasADi-based Moving Horizon Estimator (MHE). MHE solves a finite horizon optimization problem at every time step to generate an estimate of the next value of the states. The cost function used by the MHE is on the form cost = sum_{k = T-N}^{N-1}(w_kQ_k^{-1}w_k^T + v_kR_k^{-1}v_k^T) + Z(x_{T-N}) where w is the process noise, v the measurement noise and Z(...) the so called arrival cost term. The arrival cost term summarizes the information outside of the finite horizon of data in the sum. The arrival cost is approximated so that the size of the optimization does not grow with the time. Currently the approximation used is the EKF covariance update. Meaning that the arrival cost approximation is on the form Z^hat(x_{T-N}) = (x^bar_{T-N} - x^hat_{T-N})P_{T-N}^{-1} (x^bar_{T-N} - x^hat_{T-N})^T The example will demonstrate how one can use the MHE class to perform state estimation using a FMUModel object to generate measurement data. """ #Get the name and location of the Modelica package file_path = os.path.join(get_files_path(), "CSTR.mop") #Transfer the OptimizationProblem object, using the #"state_initial_equations" option to create new initial equations and new #parameters for those equations. This is required by the MHE class op = transfer_optimization_problem( 'CSTR.CSTR', file_path, accept_model=True, compiler_options={"state_initial_equations": True}) #Compile the FMU with the same option as for the OptimizationProblem fmu = compile_fmu('CSTR.CSTR', 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 continuous covariance matrices Q = N.array([[2.]]) R = N.array([[10., 0.], [0., 2.]]) #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(2) w = N.transpose(N.random.multivariate_normal(w_my, Q, nbr_of_points)) #Measurement noise N.random.seed(3) v = N.transpose(N.random.multivariate_normal(v_my, R, nbr_of_points)) ###Chose a control signal u = 280. + 25. * signal.square(2. * N.pi * time) ###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', 20.)] #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', 10.), ('T', 1.)] MHE_opts['measurement_cov'] = [(['c', 'T'], N.array([[1., 0.0], [0.0, 0.2]]))] #Error covariance matrix MHE_opts['P0_cov'] = [('c', 10.), ('T', 5.)] ##The initial guess of the states x_0_guess = dict([('c', 990.), ('T', 355.)]) #Initial value of the simulation x_0 = dict([('c', 1000.), ('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(op, x_0_guess, u_0, MHE_opts) #Decide the horizon length horizon = 8 ##Create the MHE object MHE_object = MHE(op, sample_time, horizon, x_0_guess, dx_0, c_0, MHE_opts) #Create a structure for saving the estimates 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 x_est_t = MHE_object.step(u_t, y_t) #Add the results to x_est for key in list(x_est.keys()): x_est[key].append(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(3, 1, 1) plt.plot(time, 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(('Concentration estimate', 'Simulated concentration', 'Measured concentration')) plt.grid() plt.ylabel('Concentration') plt.subplot(3, 1, 2) plt.plot(time, 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(('Temperature estimate', 'Simulated temperature', 'Measured temperature')) plt.grid() plt.ylabel('Temperature') plt.subplot(3, 1, 3) plt.step(time, u) plt.grid() plt.ylabel('Cooling temperature') plt.xlabel('time') plt.show()
def run_demo(with_plots=True): """ This example demonstrates the solution of optimal experimental design (OED) problems. The example is based on a fed-batch reactor with two states, one algebraic variable. The model has 4 parameters to be estimated based on discrete measurements of the two states. The design space consists of two piecewise constant inputs, which are to be designed in order to maximize the information content in the measurements according to the A-criterion. In order to evaluate the objective, the model is augmented with variables and equations for the sensitivities of all the nidek variables with respect to the unknown parameters using forward sensitivities, which allows the formulation of the Fisher information matrix. An initial guess of the solution is generated by simulating the system with constant input values. """ # Define outputs, parameters, and time points for needed sensitivities, and the experiment variance matrix sigma outputs = ['y1', 'y2'] parameters = ['theta1', 'theta2', 'theta3', 'theta4'] time_points = [2., 4., 6., 8., 10., 12., 14., 16., 18., 20.] sigma = N.array([[10., 0.], [0., 10.]]) # Define nominal input values used as initial guess u_1_nom = 0.1 u_2_nom = 15 # Simulate model with sensititivies to generate initial guess for optimization file_path = os.path.join(get_files_path(), "fed_batch_reactor.mop") model = load_fmu( compile_fmu('FedBatchReactor', file_path, compiler_options={"generate_ode_jacobian": True}, version=2.0)) sim_opts = model.simulate_options() sim_opts['sensitivities'] = parameters sim_opts['CVode_options']['rtol'] = 1e-8 sim_res = model.simulate(options=sim_opts, input=(('u1', 'u2'), lambda t: (u_1_nom, u_2_nom)), final_time=20.) # Compile optimization problem op = transfer_optimization_problem('FedBatchReactor_OED', file_path) # Transform the optimization problem into an OED problem op.setup_oed(outputs, parameters, sigma, time_points, "T") # Set solver options opts = op.optimize_options() opts['init_traj'] = sim_res # Initial guess opts['nominal_traj'] = sim_res opts['blocking_factors'] = 10 * [3] # Piecewise constant inputs opts['n_e'] = 30 # Number of collocation elements opts['IPOPT_options']['linear_solver'] = "ma27" opts['verbosity'] = 1 # Solve opt_res = op.optimize(options=opts) # Simulate optimal inputs to verify optimization discretization model.reset() sim_opts = model.simulate_options() sim_opts['sensitivities'] = parameters sim_opts['CVode_options']['rtol'] = 1e-8 res = model.simulate(options=sim_opts, input=opt_res.get_opt_input(), final_time=20.) # Extract solution time = res['time'] u1 = res['u1'] u2 = res['u2'] y1 = res['y1'] y2 = res['y2'] opt_time = opt_res['time'] opt_u1 = opt_res['u1'] opt_u2 = opt_res['u2'] opt_y1 = opt_res['y1'] opt_y2 = opt_res['y2'] # Verify solution 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, -1.311920e+07, rtol=1e-3) # Plot solution if with_plots: plt.close(1) plt.figure(1) lw = 1.5 ls = '-' plt.plot(time, y1, ls=ls, c='b', lw=lw) plt.plot(time, y2, ls=ls, c='g', lw=lw) plt.plot(time, u1, ls=ls, c='r', lw=lw) plt.plot(time, u2, ls=ls, c='c', lw=lw) ls = '--' plt.plot(opt_time, opt_y1, ls=ls, c='b', lw=lw) plt.plot(opt_time, opt_y2, ls=ls, c='g', lw=lw) plt.legend( ['y1 sim', 'y2 sim', 'u1 sim', 'u2 sim', 'y1 opt', 'y2 opt']) plt.show()
def run_demo(with_plots=True): """ Demonstrate symbolic elimination. """ # Compile and load optimization problem file_path = os.path.join(get_files_path(), "JMExamples_opt.mop") compiler_options = {'equation_sorting': True, 'automatic_tearing': True} op = transfer_optimization_problem("JMExamples_opt.EliminationExample", file_path, compiler_options) # Set up and perform elimination elim_opts = EliminationOptions() elim_opts['ineliminable'] = [ 'y1' ] # Provide list of variable names to not eliminate # Variables with any of the following properties are recommended to mark as ineliminable: # Potentially active bounds # Occurring in the objective or constraints # Numerically unstable pivots (difficult to predict) if with_plots: elim_opts['draw_blt'] = True elim_opts['draw_blt_strings'] = True op = BLTOptimizationProblem(op, elim_opts) # Optimize and extract solution res = op.optimize() x1 = res['x1'] x2 = res['x2'] y1 = res['y1'] u = res['u'] time = res['time'] # Plot if with_plots: plt.figure(1) plt.clf() plt.subplot(4, 1, 1) plt.plot(time, x1) plt.grid() plt.ylabel('x1') plt.subplot(4, 1, 2) plt.plot(time, x2) plt.grid() plt.ylabel('x2') plt.subplot(4, 1, 3) plt.plot(time, y1) plt.grid() plt.ylabel('y1') plt.subplot(4, 1, 4) plt.plot(time, u) plt.grid() plt.ylabel('u') plt.xlabel('time') plt.show() # Verify solution for testing purposes try: import casadi except: pass else: cost = float(res.solver.solver_object.getOutput('f')) N.testing.assert_allclose(cost, 1.0818134, rtol=1e-4)
(8, 7), (8, 8), ] else: class_name = "Circuit" file_paths = "circuit.mo" opts = { "eliminate_alias_variables": True, "generate_html_diagnostics": True, "variability_propagation": False, } model = transfer_model(class_name, file_paths, compiler_options=opts) ncp = 500 * model.get("omega") init_fmu = load_fmu(compile_fmu(class_name, file_paths, compiler_options=opts)) elif problem == "vehicle": sim_res = ResultDymolaTextual(os.path.join(get_files_path(), "vehicle_turn_dymola.txt")) start_time = 0.0 final_time = sim_res.get_variable_data("time").t[-1] ncp = 500 if source != "Modelica": raise ValueError class_name = "Car" file_paths = os.path.join(get_files_path(), "vehicle_turn.mop") opts = {"generate_html_diagnostics": 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)]
def run_demo(with_plots=True): """ This example is based on a single-track model of a car with tire dynamics. The optimization problem is to minimize the duration of a 90-degree turn with actuators on the steer angle and front and rear wheel torques. This example also demonstrates the usage of blocking factors, to enforce piecewise constant inputs. This example needs the linear solver MA27 to work. """ # Set up optimization mop_path = os.path.join(get_files_path(), "vehicle_turn.mop") op = transfer_optimization_problem('Turn', mop_path) opts = op.optimize_options() opts['IPOPT_options']['linear_solver'] = "ma27" opts['IPOPT_options']['tol'] = 1e-10 opts['n_e'] = 60 # Set blocking factors factors = {'delta_u': opts['n_e'] / 2 * [2], 'Twf_u': opts['n_e'] / 4 * [4], 'Twr_u': opts['n_e'] / 4 * [4]} rad2deg = 180. / (2*N.pi) du_bounds = {'delta_u': 2. / rad2deg} bf = BlockingFactors(factors, du_bounds=du_bounds) opts['blocking_factors'] = bf # Use Dymola simulation result as initial guess init_path = os.path.join(get_files_path(), "vehicle_turn_dymola.txt") init_guess = ResultDymolaTextual(init_path) opts['init_traj'] = init_guess # Solve optimization problem res = op.optimize(options=opts) # Extract solution time = res['time'] X = res['car.X'] Y = res['car.Y'] delta = res['delta_u'] Twf = res['Twf_u'] Twr = res['Twr_u'] Ri = op.get('Ri') Ro = op.get('Ro') # Verify result N.testing.assert_allclose(time[-1], 4.0118, rtol=5e-3) # Plot solution if with_plots: # Plot road plt.close(1) plt.figure(1) plt.plot(X, Y, 'b') xi = N.linspace(0., Ri, 100) xo = N.linspace(0., Ro, 100) yi = (Ri**8 - xi**8) ** (1./8.) yo = (Ro**8 - xo**8) ** (1./8.) plt.plot(xi, yi, 'r--') plt.plot(xo, yo, 'r--') plt.xlabel('X [m]') plt.ylabel('Y [m]') plt.legend(['position', 'road'], loc=3) # Plot inputs plt.close(2) plt.figure(2) plt.plot(time, delta * rad2deg, drawstyle='steps-post') plt.plot(time, Twf * 1e-3, drawstyle='steps-post') plt.plot(time, Twr * 1e-3, drawstyle='steps-post') plt.xlabel('time [s]') plt.legend(['delta [deg]', 'Twf [kN]', 'Twr [kN]'], loc=4) plt.show()
varis_str = ['$u_0$', '$u_1$', '$u_2$', '$u_L$', '$\dot i_L$', '$i_0$', '$i_1$', '$i_2$', '$i_3$'] edg_indices = [(0, 0), (1, 1), (1, 6), (2, 2), (2, 7), (3, 2), (3, 8), (4, 3), (4, 4), (5, 0), (5, 1), (5, 2), (6, 1), (6, 2), (6, 3), (7, 5), (7, 6), (8, 6), (8, 7), (8, 8)] else: caus_opts['tear_vars'] = ['i3'] caus_opts['tear_res'] = [7] class_name = "Circuit" file_paths = "circuit.mo" opts = {'eliminate_alias_variables': False} op = transfer_optimization_problem(class_name, file_paths, compiler_options=opts, accept_model=True) opt_opts = op.optimize_options() elif problem == "vehicle": caus_opts['uneliminable'] = ['car.Fxf', 'car.Fxr', 'car.Fyf', 'car.Fyr'] sim_res = ResultDymolaTextual(os.path.join(get_files_path(), "vehicle_turn_dymola.txt")) #~ sim_res = ResultDymolaTextual("vehicle_sol.txt") ncp = 500 if source != "Modelica": raise ValueError class_name = "Turn" file_paths = os.path.join(get_files_path(), "vehicle_turn.mop") compiler_opts = {'generate_html_diagnostics': True} op = transfer_optimization_problem(class_name, file_paths, compiler_options=compiler_opts) opt_opts = op.optimize_options() opt_opts['IPOPT_options']['linear_solver'] = "ma57" opt_opts['IPOPT_options']['tol'] = 1e-9 #~ opt_opts['IPOPT_options']['derivative_test'] = "only-second-order" #~ opt_opts['IPOPT_options']['hessian_approximation'] = "limited-memory" #~ opt_opts['order'] = "reverse"
def run_demo(with_plots=True): """ This example demonstrates how to solve parameter estimation problmes. The system is tanks with connected inlets and outlets. The objective is to estimate the outlet area of two of the tanks based on measurement data. """ # Compile and load FMU, which is used for simulation file_path = os.path.join(get_files_path(), "QuadTankPack.mop") model = load_fmu(compile_fmu('QuadTankPack.QuadTank', file_path)) # Transfer problem to CasADi Interface, which is used for estimation op = transfer_optimization_problem("QuadTankPack.QuadTank_ParEstCasADi", file_path) # Set initial states in model, which are stored in the optimization problem x_0_names = ['x1_0', 'x2_0', 'x3_0', 'x4_0'] x_0_values = op.get(x_0_names) model.set(x_0_names, x_0_values) # Load measurement data from file data_path = os.path.join(get_files_path(), "qt_par_est_data.mat") data = loadmat(data_path, 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.close(1) plt.figure(1) 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.close(2) plt.figure(2) 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])) # Simulate model response with nominal parameter values res_sim = model.simulate(input=(['u1', 'u2'], u), start_time=0., final_time=60.) # Load simulation result x1_sim = res_sim['x1'] x2_sim = res_sim['x2'] x3_sim = res_sim['x3'] x4_sim = res_sim['x4'] t_sim = res_sim['time'] u1_sim = res_sim['u1'] u2_sim = res_sim['u2'] # Check simulation results for testing purposes assert N.abs(res_sim.final('x1') - 0.05642485) < 1e-3 assert N.abs(res_sim.final('x2') - 0.05510478) < 1e-3 assert N.abs(res_sim.final('x3') - 0.02736532) < 1e-3 assert N.abs(res_sim.final('x4') - 0.02789808) < 1e-3 assert N.abs(res_sim.final('u1') - 6.0) < 1e-3 assert N.abs(res_sim.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') # Create external data object for optimization 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]) quad_pen = OrderedDict() quad_pen['x1'] = data_x1 quad_pen['x2'] = data_x2 quad_pen['u1'] = data_u1 quad_pen['u2'] = data_u2 external_data = ExternalData(Q=Q, quad_pen=quad_pen) # Set optimization options and optimize opts = op.optimize_options() opts['n_e'] = 60 # Number of collocation elements opts['external_data'] = external_data opts['init_traj'] = res_sim opts['nominal_traj'] = res_sim res = op.optimize(options=opts) # Solve estimation problem # Extract estimated values of parameters a1_opt = res.initial("a1") a2_opt = res.initial("a2") # Print and assert estimated 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]), a_ref, rtol=1e-4) # Load state profiles x1_opt = res["x1"] x2_opt = res["x2"] x3_opt = res["x3"] x4_opt = res["x4"] u1_opt = res["u1"] u2_opt = res["u2"] t_opt = res["time"] # Plot estimated trajectories 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 about moving a cart with an attached pendulum from one position to another, while starting and ending in steady state and avoiding an ellipticla obstacle for the pendulum. This example is a part of the third lab in the course FRTN05 Nonlinear Control and Servo systems at the Department of Automatic Control at Lund University, Sweden. In the lab, the trajectories generated by this script are realized by tracking them with linear MPC. The model has 4 states: Cart position and velocity, pendulum angle and angular velocity. A nearly optimal initial guess has been precomputed and is used in this script. The problem was developed by Pontus Giselsson and is published in @InProceedings{mod09pg, author = "Giselsson, Pontus and {\AA}kesson, Johan and Robertsson, Anders", title = "Optimization of a Pendulum System using {Optimica} and {Modelica}", booktitle = "7th International Modelica Conference 2009", address = "Como, Italy", year = 2009, month = sep, } """ # Create compiler and compile the pendulum model file_path = os.path.join(get_files_path(), "cart_pendulum.mop") pend_opt = transfer_optimization_problem("CartPendulum", file_path) # Define number of elements in the discretization grid and # number of collocation points in each element n_e = 150 n_cp = 3 # Initialize the optimization problem with precomputed initial guess result_file_path = os.path.join(get_files_path(), 'cart_pendulum_result.txt') init_res = ResultDymolaTextual(result_file_path) # Solve the optimization problem opts = pend_opt.optimize_options() opts['IPOPT_options']['max_iter'] = 1000 opts['IPOPT_options']['linear_solver'] = "mumps" opts['IPOPT_options']['tol'] = 1e-12 opts['n_e'] = n_e opts['n_cp'] = n_cp opts['init_traj'] = init_res res = pend_opt.optimize(options=opts) # Extract variable profiles and plot the results a_ref = res['a_ref'] x_p = res['x_p'] y_p = res['y_p'] t = res['time'] if with_plots: plt.close(1) plt.figure(1) plt.plot(t, a_ref) plt.grid() plt.title('Input signal to process ($a_{ref}$)') plt.xlabel('Time (s)') plt.ylabel('Acceleration $m/s^2$') plt.close(2) plt.figure(2) plt.plot(x_p, y_p) plt.grid() plt.title('Pendulum end-point path and obstacle') plt.xlabel('x-coordinate (m)') plt.ylabel('y-coordinate (m)') x_obst = N.linspace(-0.35, -0.25) y_obst = N.sqrt(1 - ((x_obst + 0.3) / 0.05)**2) * 0.3 - 0.4 x_track = N.linspace(-1.45, 0.1) y_track = N.zeros(N.size(x_track)) plt.plot(x_obst, y_obst) plt.plot(x_track, y_track, '--') plt.show()
with_plots = True #~ with_plots = False blt = True #~ blt = False caus_opts = sp.CausalizationOptions() #~ caus_opts['plots'] = True #~ caus_opts['draw_blt'] = True #~ caus_opts['solve_blocks'] = True #~ caus_opts['ad_hoc_scale'] = True #~ caus_opts['inline'] = False #~ caus_opts['closed_form'] = True #~ caus_opts['inline_solved'] = True caus_opts['uneliminable'] = ['car.Fxf', 'car.Fxr', 'car.Fyf', 'car.Fyr'] sim_res = ResultDymolaTextual( os.path.join(get_files_path(), "vehicle_turn_dymola.txt")) ncp = 500 class_name = "Turn" file_paths = os.path.join(get_files_path(), "vehicle_turn.mop") compiler_opts = {'generate_html_diagnostics': True} op = transfer_optimization_problem(class_name, file_paths, compiler_options=compiler_opts) opt_opts = op.optimize_options() opt_opts['IPOPT_options']['linear_solver'] = "ma27" opt_opts['IPOPT_options']['tol'] = 1e-9 opt_opts['IPOPT_options']['ma27_pivtol'] = 1e-4 opt_opts['IPOPT_options']['print_kkt_blocks_to_mfile'] = -1 opt_opts['IPOPT_options']['max_iter'] = 200 opt_opts['n_e'] = 37
plt.rcParams.update({'text.usetex': False}) with_plots = True with_plots = False expand_to_sx = True #~ expand_to_sx = False caus_opts = sp.CausalizationOptions() #~ caus_opts['plots'] = True #~ caus_opts['draw_blt'] = True #~ caus_opts['solve_blocks'] = True #~ 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]
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 range(1, 43): temperature = (ss_res.final('Temp[' + repr(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 range(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 range(1, 43): ref_model.set('xA_init[' + repr(i) + ']', break_res.final('xA[' + repr(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 compiler_options={"common_subexp_elim":False} op = transfer_optimization_problem("JMExamples_opt.Distillation4_Opt", file_name, compiler_options) # Set initial conditions for post breakdown op.set('Q_elec_ref', Q_ref) op.set('Vdot_L1_ref', L_vol_ref) for i in range(1, 43): op.set('xA_init[' + repr(i) + ']', break_res.final('xA[' + repr(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 range(1, 43): verif_model.set('xA_init[' + repr(i) + ']', break_res.final('xA[' + repr(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')
#~ formatter = matplotlib.ticker.ScalarFormatter(useOffset=False) formatter = matplotlib.ticker.ScalarFormatter() #~ formatter.set_powerlimits((-2,2)) problem = ["simple", "circuit", "vehicle", "double_pendulum", "ccpp", "dist4"][4] source = ["Modelica", "strings"][0] with_plots = True with_plots = False #~ blt = True #~ blt = False #~ full_blt = True if source != "Modelica": raise ValueError class_name = "CombinedCycleStartup.Startup6Reference" file_paths = (os.path.join(get_files_path(), "CombinedCycle.mo"), os.path.join(get_files_path(), "CombinedCycleStartup.mop")) opts = {'generate_html_diagnostics': True} model_fmu = load_fmu(compile_fmu(class_name, file_paths, compiler_options=opts)) final_time = 5000. opts = model_fmu.simulate_options() opts['CVode_options']['rtol'] = 1e-10 opts['CVode_options']['atol'] = 1e-10 sim_res = model_fmu.simulate(final_time=final_time, options=opts) eps = 1e-8 for i in xrange(2): if i == 0: linear_solver = "symbolicqr" title = "Symbolic QR" elif i == 1:
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. In addition, a set of algebraic variables is eliminated by means of BLt information 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 is 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, separate_process=True) # 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 from pyjmi import transfer_to_casadi_interface compiler_options = {'equation_sorting': True, "common_subexp_elim": False} op = transfer_to_casadi_interface("CombinedCycleStartup.Startup6", file_paths, compiler_options) # Set options opt_opts = op.optimize_options() opt_opts['n_e'] = 50 # Number of elements opt_opts['init_traj'] = init_res # Simulation result opt_opts['nominal_traj'] = init_res # variable elimination eliminables = op.getEliminableVariables() algebraics = op.getVariables(op.REAL_ALGEBRAIC) print "Number of algebraics: ", len(algebraics) print "Eliminating variables!" eliminable_algebraics = [a for a in algebraics if a in eliminables] variables_to_eliminate = list() variables_with_bounds = list() for v in eliminable_algebraics: if not v.hasAttributeSet("min") and not v.hasAttributeSet("max"): variables_to_eliminate.append(v) else: variables_with_bounds.append(v) # Elimination of unbounded variables op.markVariablesForElimination(variables_to_eliminate) # Elimination of bounded variables (skip elimination of plant.sigma) bounded_eliminations = [ v for v in variables_with_bounds if not v.getName() == "plant.sigma" ] op.markVariablesForElimination(bounded_eliminations) op.eliminateVariables() # Alternative way of eliminating variables however this method do not eliminate any bounded variables #op.eliminateAlgebraics() print "Done with elimination" eliminated_vars = op.getEliminatedVariables() print "Number of variables that were eliminated: ", len(eliminated_vars) # Solve the optimal control problem opt_res = op.optimize(options=opt_opts) # get output of one eliminated variable elim_var_name = eliminable_algebraics[5].getName() # 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_eliminated = opt_res[elim_var_name] 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(4, 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(4, 1, 2) plt.plot(opt_time, opt_plant_sigma * 1e-6) plt.grid(True) plt.ylabel('turbine thermal stress [MPa]') plt.subplot(4, 1, 3) plt.plot(opt_time, opt_plant_load) plt.grid(True) plt.ylabel('input load [1]') plt.xlabel('time [s]') plt.subplot(4, 1, 4) plt.plot(opt_time, opt_eliminated) plt.grid(True) plt.ylabel(elim_var_name) plt.xlabel('time [s]') # Verify solution 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, 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): """ 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 constr_x_est.keys(): constr_x_est[key].append(constr_x_est_t[key]) for key in 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 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 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()
opt_opts['IPOPT_options']['acceptable_constr_viol_tol'] = 1e-12 opt_opts['IPOPT_options']['acceptable_dual_inf_tol'] = 1e-12 opt_opts['IPOPT_options']['acceptable_compl_inf_tol'] = 1e-12 opt_opts['IPOPT_options']['linear_solver'] = "ma57" opt_opts['IPOPT_options']['ma57_pivtol'] = 1e-4 opt_opts['IPOPT_options']['ma27_pivtol'] = 1e-4 opt_opts['IPOPT_options']['ma97_u'] = 1e-4 opt_opts['IPOPT_options']['ma97_umax'] = 1e-2 opt_opts['IPOPT_options']['ma57_automatic_scaling'] = "yes" opt_opts['IPOPT_options']['mu_strategy'] = "adaptive" if problem == "vehicle": std_dev[problem] = 0.1 caus_opts = sp.CausalizationOptions() caus_opts['uneliminable'] = ['car.Fxf', 'car.Fxr', 'car.Fyf', 'car.Fyr'] class_name = "Turn" file_paths = os.path.join(get_files_path(), "vehicle_turn.mop") init_res = LocalDAECollocationAlgResult(result_data=ResultDymolaTextual('vehicle_sol.txt')) opt_opts['init_traj'] = init_res opt_opts['nominal_traj'] = init_res opt_opts['IPOPT_options']['max_cpu_time'] = 30 opt_opts['n_e'] = 60 # Set blocking factors factors = {'delta_u': opt_opts['n_e'] / 2 * [2], 'Twf_u': opt_opts['n_e'] / 4 * [4], 'Twr_u': opt_opts['n_e'] / 4 * [4]} rad2deg = 180. / (2*np.pi) du_bounds = {'delta_u': 2. / rad2deg} bf = BlockingFactors(factors, du_bounds=du_bounds) opt_opts['blocking_factors'] = bf
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'] + N.zeros(t_init_sim.shape) # make Tc_init_sim be a vector # 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['c_ref'][0] # extract constant value as first element T_ref = res['T_ref'][0] Tc_ref = res['Tc_ref'][0] # 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()
def run_demo(with_plots=True): """ This example solves the optimization problem from pyjmi.examples.ccpp using the Python-based symbolic elimination. """ # Load initial gues init_path = os.path.join(get_files_path(), "ccpp_init.txt") init_res = LocalDAECollocationAlgResult( result_data=ResultDymolaTextual(init_path)) # Compile model class_name = "CombinedCycleStartup.Startup6" file_paths = (os.path.join(get_files_path(), "CombinedCycle.mo"), os.path.join(get_files_path(), "CombinedCycleStartup.mop")) compiler_options = {'equation_sorting': True, 'automatic_tearing': True} op = transfer_optimization_problem("CombinedCycleStartup.Startup6", file_paths, compiler_options) # Set elimination options elim_opts = EliminationOptions() elim_opts['ineliminable'] = ['plant.sigma'] if with_plots: elim_opts['draw_blt'] = True # Eliminate algebraic variables op = BLTOptimizationProblem(op, elim_opts) # Set collocation options opt_opts = op.optimize_options() opt_opts['init_traj'] = init_res opt_opts['nominal_traj'] = init_res # Solve the optimal control problem opt_res = op.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'] # 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_object.getOutput('f')) N.testing.assert_allclose(cost, 17492.465548193624, rtol=1e-5)
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 is 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, separate_process=True) # 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 from pyjmi import transfer_to_casadi_interface op = transfer_to_casadi_interface("CombinedCycleStartup.Startup6", file_paths) # Set options opt_opts = op.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 = op.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): """ 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. """ # Load measurement data from file data_path = os.path.join(get_files_path(), "qt_par_est_data.mat") data = loadmat(data_path, 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.close(1) plt.figure(1) 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.close(2) plt.figure(2) 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 and load FMU model_path = os.path.join(get_files_path(), "QuadTankPack.mop") fmu_name = compile_fmu('QuadTankPack.Sim_QuadTank', model_path) model = load_fmu(fmu_name) # Simulate model response with nominal parameter values 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'] # Check simulation results for testing purposes 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') # Load optimization problem op = transfer_to_casadi_interface("QuadTankPack.QuadTank_ParEstCasADi", model_path) # Create measurement data object for optimization 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) # Set optimization options and optimize opts = op.optimize_options() opts['n_e'] = 60 opts['measurement_data'] = measurement_data opts['init_traj'] = res.result_data opts['nominal_traj'] = res.result_data res = op.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 estimated values of parameters a1_opt = res.final("qt.a1") a2_opt = res.final("qt.a2") # Print and assert estimated 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 estimated trajectories 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()
formatter = matplotlib.ticker.ScalarFormatter() #~ formatter.set_powerlimits((-2,2)) problem = ["simple", "circuit", "vehicle", "double_pendulum", "ccpp", "dist4"][4] source = ["Modelica", "strings"][0] with_plots = True with_plots = False #~ blt = True #~ blt = False #~ full_blt = True if source != "Modelica": raise ValueError class_name = "CombinedCycleStartup.Startup6Reference" file_paths = (os.path.join(get_files_path(), "CombinedCycle.mo"), os.path.join(get_files_path(), "CombinedCycleStartup.mop")) opts = {'generate_html_diagnostics': True} model_fmu = load_fmu(compile_fmu(class_name, file_paths, compiler_options=opts)) final_time = 5000. opts = model_fmu.simulate_options() opts['CVode_options']['rtol'] = 1e-10 opts['CVode_options']['atol'] = 1e-10 sim_res = model_fmu.simulate(final_time=final_time, options=opts) eps = 1e-8 for i in xrange(2): if i == 0: linear_solver = "symbolicqr" title = "Symbolic QR"
def run_demo(with_plots=True): """ This example is based on the multibody mechanics double pendulum example from the Modelica Standard Library (MSL). The MSL example has been modified by adding a torque on the first revolute joint of the pendulum as a top-level input. The considered optimization problem is to invert both pendulum bodies with bounded torque. This example needs linear solver MA27 to work. """ # Simulate system with linear state feedback to generate initial guess file_paths = (os.path.join(get_files_path(), "DoublePendulum.mo"), os.path.join(get_files_path(), "DoublePendulum.mop")) comp_opts = {'inline_functions': 'all', 'dynamic_states': False, 'expose_temp_vars_in_fmu': True, 'equation_sorting': True, 'automatic_tearing': True} init_fmu = load_fmu(compile_fmu("DoublePendulum.Feedback", file_paths, compiler_options=comp_opts)) init_res = init_fmu.simulate(final_time=3., options={'CVode_options': {'rtol': 1e-10}}) # Set up optimization op = transfer_optimization_problem('Opt', file_paths, compiler_options=comp_opts) opts = op.optimize_options() opts['IPOPT_options']['linear_solver'] = "ma27" opts['n_e'] = 100 opts['init_traj'] = init_res opts['nominal_traj'] = init_res # Symbolic elimination op = BLTOptimizationProblem(op) # Solve optimization problem res = op.optimize(options=opts) # Extract solution time = res['time'] phi1 = res['pendulum.revolute1.phi'] phi2 = res['pendulum.revolute2.phi'] u = res['u'] # Verify solution for testing purposes try: import casadi except: pass else: cost = float(res.solver.solver_object.output(casadi.NLP_SOLVER_F)) N.testing.assert_allclose(cost, 9.632883808252522, rtol=5e-3) # Plot solution if with_plots: plt.close(1) plt.figure(1) plt.subplot(2, 1, 1) plt.plot(time, phi1, 'b') plt.plot(time, phi2, 'r') plt.legend(['$\phi_1$', '$\phi_2$']) plt.ylabel('$\phi$') plt.xlabel('$t$') plt.grid() plt.subplot(2, 1, 2) plt.plot(time, u) plt.ylabel('$u$') plt.xlabel('$t$') plt.grid() plt.show()