Esempio n. 1
0
    def test_du_bounds(self):
        """
        Test with blocking_factor du_bounds.
        """
        op = transfer_to_casadi_interface(
            "CSTR.CSTR_MPC",
            self.cstr_file_path,
            compiler_options={"state_initial_equations": True})
        op.set('_start_c', float(self.c_0_A))
        op.set('_start_T', float(self.T_0_A))

        # Set options collocation
        n_e = 50
        opt_opts = op.optimize_options()
        opt_opts['n_e'] = n_e
        opt_opts['IPOPT_options']['print_level'] = 0

        # Define some MPC-options
        sample_period = 3
        horizon = 50
        seed = 7

        # Define blocking factors
        bl_list = [1] * horizon
        factors = {'Tc': bl_list}
        du_bounds = {'Tc': 5}
        bf = BlockingFactors(factors=factors, du_bounds=du_bounds)
        opt_opts['blocking_factors'] = bf

        # Create MPC-object
        MPC_object = MPC(op,
                         opt_opts,
                         sample_period,
                         horizon,
                         noise_seed=seed,
                         initial_guess='trajectory')

        MPC_object.update_state()
        u_k1 = MPC_object.sample()

        res = MPC_object.get_results_this_sample()

        Tc = res['Tc']

        prev_value = Tc[0]
        largest_delta = 0

        for value in Tc:
            delta = value - prev_value
            if delta > largest_delta:
                largest_delta = delta
            prev_value = value

        assert largest_delta < 5, "Value {} is not less than {}".format(
            largest_delta, 5)
Esempio n. 2
0
    def test_get_results_this_sample(self):
        """
        Test that get_results_this_sample returns the optimization result for
        this optimization.
        """
        op = transfer_to_casadi_interface(
            "CSTR.CSTR_MPC",
            self.cstr_file_path,
            compiler_options={"state_initial_equations": True})
        op.set('_start_c', float(self.c_0_A))
        op.set('_start_T', float(self.T_0_A))

        # Set options collocation
        n_e = 50
        opt_opts = op.optimize_options()
        opt_opts['n_e'] = n_e
        opt_opts['IPOPT_options']['print_level'] = 0

        # Define some MPC-options
        sample_period = 3
        horizon = 50
        seed = 7
        cvc = {'T': 1e6}

        # Define blocking factors
        bl_list = [1] * horizon
        factors = {'Tc': bl_list}
        bf = BlockingFactors(factors=factors)
        opt_opts['blocking_factors'] = bf

        # Create MPC-object
        MPC_object = MPC(op,
                         opt_opts,
                         sample_period,
                         horizon,
                         constr_viol_costs=cvc,
                         noise_seed=seed)

        MPC_object.update_state()
        u_k1 = MPC_object.sample()
        result1 = MPC_object.get_results_this_sample()
        N.testing.assert_equal(0, result1['time'][0])
        N.testing.assert_equal(sample_period * horizon, result1['time'][-1])

        MPC_object.update_state()
        u_k2 = MPC_object.sample()
        result2 = MPC_object.get_results_this_sample()
        N.testing.assert_equal(sample_period, result2['time'][0])
        N.testing.assert_equal(sample_period * (horizon + 1),
                               result2['time'][-1])
Esempio n. 3
0
    def test_warm_start_options(self):
        """ 
        Test that the warm start options are activated.
        """
        op = transfer_to_casadi_interface(
            "CSTR.CSTR_MPC",
            self.cstr_file_path,
            compiler_options={"state_initial_equations": True})
        op.set('_start_c', float(self.c_0_A))
        op.set('_start_T', float(self.T_0_A))

        # Set options collocation
        n_e = 50
        opt_opts = op.optimize_options()
        opt_opts['n_e'] = n_e
        opt_opts['IPOPT_options']['print_level'] = 0

        # Define some MPC-options
        sample_period = 3
        horizon = 50
        cvc = {'T': 1e6}

        # Create MPC-object
        MPC_object = MPC(op,
                         opt_opts,
                         sample_period,
                         horizon,
                         initial_guess='trajectory',
                         constr_viol_costs=cvc)
        MPC_object.update_state({
            '_start_c': 587.47543496,
            '_start_T': 345.64619542
        })
        u_k1 = MPC_object.sample()
        MPC_object.update_state()
        u_k2 = MPC_object.sample()

        N.testing.assert_(MPC_object.collocator.warm_start)
        wsip =\
         MPC_object.collocator.solver_object.getOption('warm_start_init_point')
        mu_init = MPC_object.collocator.solver_object.getOption('mu_init')
        prl = MPC_object.collocator.solver_object.getOption('print_level')

        N.testing.assert_(wsip == 'yes')
        N.testing.assert_equal(mu_init, 1e-3)
        N.testing.assert_equal(prl, 0)
Esempio n. 4
0
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()
Esempio n. 5
0
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()
Esempio n. 6
0
    def test_softening_bounds(self):
        """
        Test the automatic softening of hard variable bounds.
        """
        op = transfer_to_casadi_interface(
            "CSTR.CSTR_MPC",
            self.cstr_file_path,
            compiler_options={"state_initial_equations": True})

        # Set options collocation
        n_e = 50
        opt_opts = op.optimize_options()
        opt_opts['n_e'] = n_e

        # Define some MPC-options
        sample_period = 3
        horizon = 50
        seed = 7

        # Define blocking factors
        bl_list = [1] * horizon
        factors = {'Tc': bl_list}
        bf = BlockingFactors(factors=factors)
        opt_opts['blocking_factors'] = bf
        opt_opts['IPOPT_options']['print_level'] = 0

        cvc = {'T': 1e6}
        originalPathConstraints = op.getPathConstraints()

        # Create MPC-object
        MPC_object = MPC(op,
                         opt_opts,
                         sample_period,
                         horizon,
                         constr_viol_costs=cvc,
                         noise_seed=seed)

        # Assert that an optimization with an initial value outside of bounds
        # succeeds
        MPC_object.update_state({'_start_c': self.c_0_A, '_start_T': 355})
        MPC_object.sample()
        N.testing.assert_(
            'Solve_Succeeded',
            MPC_object.collocator.solver_object.getStat('return_status'))
Esempio n. 7
0
    def test_auto_bl_factors(self):
        """
        Test blocking factors generated in the mpc-class.
        """
        op = transfer_to_casadi_interface(
            "CSTR.CSTR_MPC",
            self.cstr_file_path,
            compiler_options={"state_initial_equations": True})

        # Set options collocation
        n_e = 50
        opt_opts = op.optimize_options()
        opt_opts['n_e'] = n_e
        opt_opts['IPOPT_options']['print_level'] = 0

        # Define some MPC-options
        sample_period = 3
        horizon = 50

        # Create MPC-object
        MPC_object_auto = MPC(op, opt_opts, sample_period, horizon)
        MPC_object_auto.update_state()
        MPC_object_auto.sample()
        res_auto = MPC_object_auto.get_results_this_sample()

        opt_opts_auto = op.optimize_options()
        opt_opts_auto['n_e'] = n_e
        opt_opts_auto['IPOPT_options']['print_level'] = 0
        bf_list = [1] * horizon
        factors = {'Tc': bf_list}
        bf = BlockingFactors(factors)
        opt_opts_auto['blocking_factors'] = bf

        MPC_object = MPC(op, opt_opts_auto, sample_period, horizon)
        MPC_object.update_state()
        MPC_object.sample()
        res = MPC_object.get_results_this_sample()

        # Assert that res_auto['Tc'] and res['Tc'] are equal
        N.testing.assert_array_equal(res_auto['Tc'], res['Tc'])
Esempio n. 8
0
    def test_infeasible_start(self):
        """
        Test that the MPC class throws an exception if the first optimization 
        is unsuccessful.
        """
        op = transfer_to_casadi_interface(
            "CSTR.CSTR_MPC",
            self.cstr_file_path,
            compiler_options={"state_initial_equations": True})

        # Set options collocation
        n_e = 50
        opt_opts = op.optimize_options()
        opt_opts['n_e'] = n_e
        opt_opts['IPOPT_options']['print_level'] = 0

        # Define some MPC-options
        sample_period = 3
        horizon = 50
        cvc = {'T': 1e6}

        # Define blocking factors
        bl_list = [1] * horizon
        factors = {'Tc': bl_list}
        bf = BlockingFactors(factors=factors)
        opt_opts['blocking_factors'] = bf

        # Create MPC-object
        MPC_object = MPC(op,
                         opt_opts,
                         sample_period,
                         horizon,
                         constr_viol_costs=cvc)

        # Test with infeasible problem
        MPC_object.update_state({'_start_c': 900, '_start_T': 700})

        N.testing.assert_raises(Exception, MPC_object.sample)
Esempio n. 9
0
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)
Esempio n. 10
0
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)
Esempio n. 11
0
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()
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)
Esempio n. 13
0
    def test_eliminated_variables(self):
        """ 
        Test that the results when using eliminated variables are the same as when not using them.
        """
        # Compile and load the model used for simulation
        sim_fmu = compile_fmu(
            "CSTR.CSTR_MPC_Model",
            self.cstr_file_path,
            compiler_options={"state_initial_equations": True})
        sim_model = load_fmu(sim_fmu)

        # Compile and load the model with eliminated variables used for simulation
        sim_fmu_elim = compile_fmu("CSTR.CSTR_elim_vars_MPC_Model",
                                   self.cstr_file_path,
                                   compiler_options={
                                       "state_initial_equations": True,
                                       'equation_sorting': True,
                                       'automatic_tearing': False
                                   })
        sim_model_elim = load_fmu(sim_fmu_elim)

        # Define stationary point A and set initial values and inputs
        c_0_A = 956.271352
        T_0_A = 250.051971
        sim_model.set('_start_c', c_0_A)
        sim_model.set('_start_T', T_0_A)
        sim_model.set('Tc', 280)
        init_res = sim_model.simulate(start_time=0., final_time=150)

        # Compile and load optimization problems
        op = transfer_to_casadi_interface("CSTR.CSTR_MPC",
                                          self.cstr_file_path,
                                          compiler_options={
                                              "state_initial_equations": True,
                                              "common_subexp_elim": False
                                          })
        op_elim = transfer_to_casadi_interface("CSTR.CSTR_elim_vars_MPC",
                                               self.cstr_file_path,
                                               compiler_options={
                                                   "state_initial_equations":
                                                   True,
                                                   'equation_sorting': True,
                                                   'automatic_tearing': False,
                                                   "common_subexp_elim": False
                                               })

        # Define MPC options
        sample_period = 5  # s
        horizon = 10  # Samples on the horizon
        n_e_per_sample = 1  # Collocation elements / sample
        n_e = n_e_per_sample * horizon  # Total collocation elements
        finalTime = 50  # s
        number_samp_tot = 5  # 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': 50}
        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

        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)

            # 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
        complete_result = MPC_object.get_complete_results()

        op_elim.eliminateAlgebraics()

        assert (len(op_elim.getEliminatedVariables()) == 2)

        opt_opts_elim = op_elim.optimize_options()
        opt_opts_elim['n_e'] = n_e
        opt_opts_elim['n_cp'] = 2
        opt_opts_elim['init_traj'] = init_res

        # Create the MPC object with eliminated variables
        MPC_object_elim = MPC(op_elim,
                              opt_opts_elim,
                              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_elim.update_state(x_k)
            u_k = MPC_object_elim.sample()

            # Reset the model and set the new initial states before simulating
            # the next sample period with the optimal input u_k
            sim_model_elim.reset()
            sim_model_elim.set(list(x_k.keys()), list(x_k.values()))
            sim_res = sim_model_elim.simulate(start_time=k * sample_period,
                                              final_time=(k + 1) *
                                              sample_period,
                                              input=u_k)

            # Extract state at end of sample_period from sim_res and add Gaussian
            # noise with mean 0 and standard deviation 0.005*(state_current_value)
            x_k = MPC_object_elim.extract_states(sim_res, mean=0, st_dev=0.005)

        # Extract variable profiles
        complete_result_elim = MPC_object_elim.get_complete_results()

        N.testing.assert_array_almost_equal(complete_result['c'],
                                            complete_result_elim['c'])
        N.testing.assert_array_almost_equal(complete_result['T'],
                                            complete_result_elim['T'])
        N.testing.assert_array_almost_equal(complete_result['Tc'],
                                            complete_result_elim['Tc'])
Esempio n. 14
0
    def test_infeasible_return_input(self):
        """
        Test that the input returned from an unsuccessful optimization is the 
        next input in the last successful optimization.
        """
        op = transfer_to_casadi_interface(
            "CSTR.CSTR_MPC",
            self.cstr_file_path,
            compiler_options={"state_initial_equations": True})

        # Set options collocation
        n_e = 50
        opt_opts = op.optimize_options()
        opt_opts['n_e'] = n_e
        opt_opts['IPOPT_options']['print_level'] = 0

        # Define some MPC-options
        sample_period = 3
        horizon = 50
        seed = 7
        cvc = {'T': 1e6}

        # Define blocking factors
        bl_list = [1] * horizon
        factors = {'Tc': bl_list}
        bf = BlockingFactors(factors=factors)
        opt_opts['blocking_factors'] = bf

        # Create MPC-object
        MPC_object = MPC(op,
                         opt_opts,
                         sample_period,
                         horizon,
                         constr_viol_costs=cvc,
                         noise_seed=seed,
                         create_comp_result=False,
                         initial_guess='trajectory')
        # NOTE: THIS NOT WORKING WITH initial_guess='shift'!!

        MPC_object.update_state({
            '_start_c': 587.47543496,
            '_start_T': 345.64619542
        })
        u_k1 = MPC_object.sample()
        result1 = MPC_object.get_results_this_sample()

        # Optimize with infeasible problem
        MPC_object.update_state({'_start_c': 900, '_start_T': 400})
        u_k2 = MPC_object.sample()

        # Assert that problem was infeasible and that the returned input is
        # the next input from the last succesful optimization
        N.testing.assert_(
            'Infeasible_Problem_Detected',
            MPC_object.collocator.solver_object.getStat('return_status'))

        N.testing.assert_almost_equal(u_k2[1](0)[0],
                                      result1['Tc'][4],
                                      decimal=10)

        # Assert that the returned resultfile is that of the last succesful
        # optimization
        result2 = MPC_object.get_results_this_sample()

        assert result1 == result2, "UNEQUAL VALUES. result1={}\nresult2={}".format(
            result1, result2)

        # Assert that problem was infeasible yet again and that the returned
        # input is the next (third) input from the last succesful optimization
        MPC_object.update_state({'_start_c': 900, '_start_T': 400})
        u_k3 = MPC_object.sample()

        N.testing.assert_(
            'Infeasible_Problem_Detected',
            MPC_object.collocator.solver_object.getStat('return_status'))

        N.testing.assert_almost_equal(u_k3[1](0)[0],
                                      result1['Tc'][7],
                                      decimal=10)
Esempio n. 15
0
    def test_du_quad_pen(self):
        """
        Test with blocking_factor du_quad_pen.
        """
        op = transfer_to_casadi_interface(
            "CSTR.CSTR_MPC",
            self.cstr_file_path,
            compiler_options={"state_initial_equations": True})
        op.set('_start_c', float(self.c_0_A))
        op.set('_start_T', float(self.T_0_A))

        # Set options collocation
        n_e = 50
        opt_opts = op.optimize_options()
        opt_opts['n_e'] = n_e
        opt_opts['IPOPT_options']['print_level'] = 0

        # Define some MPC-options
        sample_period = 3
        horizon = 50
        seed = 7

        # Define blocking factors
        bl_list = [1] * horizon
        factors = {'Tc': bl_list}
        bf = BlockingFactors(factors=factors)
        opt_opts['blocking_factors'] = bf

        # Create MPC-object without du_quad_pen
        MPC_object = MPC(op,
                         opt_opts,
                         sample_period,
                         horizon,
                         noise_seed=seed,
                         initial_guess='trajectory')

        MPC_object.update_state()
        MPC_object.sample()
        res = MPC_object.get_results_this_sample()

        # Create MPC-object with du_quad_pen
        opt_opts_quad = op.optimize_options()
        opt_opts_quad['n_e'] = n_e
        opt_opts_quad['IPOPT_options']['print_level'] = 0
        bf_list = [1] * horizon
        factors = {'Tc': bf_list}
        du_quad_pen = {'Tc': 100}
        bf = BlockingFactors(factors, du_quad_pen=du_quad_pen)
        opt_opts_quad['blocking_factors'] = bf

        MPC_object_quad = MPC(op,
                              opt_opts_quad,
                              sample_period,
                              horizon,
                              noise_seed=seed,
                              initial_guess='trajectory')
        MPC_object_quad.update_state()
        MPC_object_quad.sample()
        res_quad = MPC_object_quad.get_results_this_sample()

        Tc = res['Tc']
        prev_value = Tc[0]
        largest_delta = 0

        for value in Tc:
            delta = value - prev_value
            if delta > largest_delta:
                largest_delta = delta
            prev_value = value

        Tc = res_quad['Tc']
        prev_value = Tc[0]
        largest_delta_quad = 0

        for value in Tc:
            delta = value - prev_value
            if delta > largest_delta_quad:
                largest_delta_quad = delta
            prev_value = value

        N.testing.assert_(largest_delta_quad < largest_delta)