Beispiel #1
0
def run_optimization(sim_res, time, price, pv, bldg, plot = True, usePV = True):
    """
    This function runs an optimization problem
    """
    
    from pyjmi.optimization.casadi_collocation import MeasurementData
    from collections import OrderedDict

    # get current directory
    curr_dir = os.path.dirname(os.path.abspath(__file__));
    
    # if pv panels are not used then remove power
    if usePV == False:
        pv = np.zeros(np.shape(pv))
    
    # compile FMU
    path = os.path.join(curr_dir,"..","Models","ElectricalNetwork.mop")
    model_name = compile_fmux('ElectricNetwork.ACnetworkBatteryMngmtOpt_Money', path, compiler_options={"enable_variable_scaling":True})
    
    # Load the model
    model_casadi = CasadiModel(model_name) 
    
    # Get the inputs that should be eliminated from the optimization variables
    eliminated = OrderedDict()
    data_price = np.vstack([t_data, price])
    eliminated['price'] = data_price
    
    #data_Q  = np.vstack([t_data, np.zeros(Npoints)])
    #eliminated['Q_batt'] = data_Q
    
    data_pv1 = np.vstack([t_data, np.squeeze(pv[:,0])])
    eliminated['P_pv1'] = data_pv1
    data_pv2 = np.vstack([t_data, np.squeeze(pv[:,1])])
    eliminated['P_pv2'] = data_pv2
    data_pv3 = np.vstack([t_data, np.squeeze(pv[:,2])])
    eliminated['P_pv3'] = data_pv3
    
    data_bldg1 = np.vstack([t_data, -np.squeeze(bldg[:,0])])
    eliminated['P_bldg1'] = data_bldg1
    data_bldg2 = np.vstack([t_data, -np.squeeze(bldg[:,1])])
    eliminated['P_bldg2'] = data_bldg2
    data_bldg3 = np.vstack([t_data, -np.squeeze(bldg[:,2])])
    eliminated['P_bldg3'] = data_bldg3
    
    measurement_data = MeasurementData(eliminated = eliminated)
    
    # define the optimization problem
    opts = model_casadi.optimize_options()
    opts['n_e'] = 60
    opts['measurement_data'] = measurement_data
    opts['init_traj'] = sim_res.result_data
    
    # get the results of the optimization
    res = model_casadi.optimize(options = opts)
    
    if plot:
        plotFunction(sim_res, res)
    
    return res
Beispiel #2
0
def run_optimization(sim_res, time, price, pv, bldg):
    """
    This function runs an optimization problem
    """

    from pyjmi.optimization.casadi_collocation import MeasurementData
    from collections import OrderedDict

    # get current directory
    curr_dir = os.path.dirname(os.path.abspath(__file__))

    # compile FMU
    path = os.path.join(curr_dir, "..", "Models", "ElectricalNetwork.mop")
    model_name = compile_fmux(
        'ElectricNetwork.NetworkBatteryMngmtOpt_Money',
        path,
        compiler_options={"enable_variable_scaling": True})

    # Load the model
    model_casadi = CasadiModel(model_name)

    # Get the inputs that should be eliminated from the optimization variables
    eliminated = OrderedDict()
    data_price = np.vstack([t_data, price])
    eliminated['price'] = data_price

    data_pv1 = np.vstack([t_data, np.squeeze(pv[:, 0])])
    eliminated['pv1'] = data_pv1
    data_pv2 = np.vstack([t_data, np.squeeze(pv[:, 1])])
    eliminated['pv2'] = data_pv2
    data_pv3 = np.vstack([t_data, np.squeeze(pv[:, 2])])
    eliminated['pv3'] = data_pv3

    data_bldg1 = np.vstack([t_data, np.squeeze(bldg[:, 0])])
    eliminated['bldg1'] = data_bldg1
    data_bldg2 = np.vstack([t_data, np.squeeze(bldg[:, 1])])
    eliminated['bldg2'] = data_bldg2
    data_bldg3 = np.vstack([t_data, np.squeeze(bldg[:, 2])])
    eliminated['bldg3'] = data_bldg3

    measurement_data = MeasurementData(eliminated=eliminated)

    # define the optimization problem
    opts = model_casadi.optimize_options()
    opts['n_e'] = 50
    opts['measurement_data'] = measurement_data
    opts['init_traj'] = sim_res.result_data

    # get the results of the optimization
    res = model_casadi.optimize(options=opts)

    plotCompare(sim_res, res)
Beispiel #3
0
def run_optimization(sim_res, time, price, pv, bldg):
    """
    This function runs an optimization problem
    """
    
    from pyjmi.optimization.casadi_collocation import MeasurementData
    from collections import OrderedDict

    # get current directory
    curr_dir = os.path.dirname(os.path.abspath(__file__));
    
    # compile FMU
    path = os.path.join(curr_dir,"..","Models","ElectricalNetwork.mop")
    model_name = compile_fmux('ElectricNetwork.NetworkBatteryMngmtOpt_Money', path, compiler_options={"enable_variable_scaling":True})
    
    # Load the model
    model_casadi = CasadiModel(model_name) 
    
    # Get the inputs that should be eliminated from the optimization variables
    eliminated = OrderedDict()
    data_price = np.vstack([t_data, price])
    eliminated['price'] = data_price
    
    data_pv1 = np.vstack([t_data, np.squeeze(pv[:,0])])
    eliminated['pv1'] = data_pv1
    data_pv2 = np.vstack([t_data, np.squeeze(pv[:,1])])
    eliminated['pv2'] = data_pv2
    data_pv3 = np.vstack([t_data, np.squeeze(pv[:,2])])
    eliminated['pv3'] = data_pv3
    
    data_bldg1 = np.vstack([t_data, np.squeeze(bldg[:,0])])
    eliminated['bldg1'] = data_bldg1
    data_bldg2 = np.vstack([t_data, np.squeeze(bldg[:,1])])
    eliminated['bldg2'] = data_bldg2
    data_bldg3 = np.vstack([t_data, np.squeeze(bldg[:,2])])
    eliminated['bldg3'] = data_bldg3
    
    measurement_data = MeasurementData(eliminated = eliminated)
    
    # define the optimization problem
    opts = model_casadi.optimize_options()
    opts['n_e'] = 50
    opts['measurement_data'] = measurement_data
    opts['init_traj'] = sim_res.result_data
    
    # get the results of the optimization
    res = model_casadi.optimize(options = opts)
    
    plotCompare(sim_res, res)
Beispiel #4
0
def run_demo(with_plots=True):
    """
    Demonstrate how to solve a dynamic optimization problem based on a Van der 
    Pol oscillator system.
    """
    curr_dir = os.path.dirname(os.path.abspath(__file__))

    jn = compile_fmux("VDP_pack.VDP_Opt2", curr_dir + "/files/VDP.mop")

    model = CasadiModel(jn)

    opts = model.optimize_options(algorithm='CasadiPseudoSpectralAlg')
    opts['n_cp'] = 50
    #opts['IPOPT_options']['hessian_approximation'] = 'limited-memory'

    res = model.optimize(algorithm='CasadiPseudoSpectralAlg', options=opts)

    # Extract variable profiles
    x1 = res['x1']
    x2 = res['x2']
    u = res['u']
    time = res['time']

    assert N.abs(res.final('x1') - 8.64330006e-07) < 1e-3
    assert N.abs(res.final('x2') + 3.68158852e-07) < 1e-3

    if with_plots:
        # Plot
        plt.figure(1)
        plt.clf()
        plt.subplot(311)
        plt.plot(time, x1, 'x-')
        plt.grid()
        plt.ylabel('x1')

        plt.subplot(312)
        plt.plot(time, x2, 'x-')
        plt.grid()
        plt.ylabel('x2')

        plt.subplot(313)
        plt.plot(time, u, 'x-')
        plt.grid()
        plt.ylabel('u')
        plt.xlabel('time')
        plt.show()
Beispiel #5
0
def run_demo(with_plots=True):
    """
    Demonstrate how to solve a dynamic optimization problem based on a Van der 
    Pol oscillator system.
    """
    curr_dir = os.path.dirname(os.path.abspath(__file__));

    jn = compile_fmux("VDP_pack.VDP_Opt2", curr_dir+"/files/VDP.mop")

    model = CasadiModel(jn)

    opts = model.optimize_options(algorithm='CasadiPseudoSpectralAlg')
    opts['n_cp'] = 50
    #opts['IPOPT_options']['hessian_approximation'] = 'limited-memory'

    res = model.optimize(algorithm='CasadiPseudoSpectralAlg',options=opts)

    # Extract variable profiles
    x1   = res['x1']
    x2   = res['x2']
    u    = res['u']
    time = res['time']
    
    assert N.abs(res.final('x1') - 8.64330006e-07) < 1e-3
    assert N.abs(res.final('x2') + 3.68158852e-07) < 1e-3

    if with_plots:
        # Plot
        plt.figure(1)
        plt.clf()
        plt.subplot(311)
        plt.plot(time,x1,'x-')
        plt.grid()
        plt.ylabel('x1')
        
        plt.subplot(312)
        plt.plot(time,x2,'x-')
        plt.grid()
        plt.ylabel('x2')
        
        plt.subplot(313)
        plt.plot(time,u,'x-')
        plt.grid()
        plt.ylabel('u')
        plt.xlabel('time')
        plt.show()
Beispiel #6
0
def run_demo(with_plots=True):
    """
    Demonstrate how to optimize a VDP oscillator using LocalDAECollocationAlgOld.
    """
    # Compile and load model
    curr_dir = os.path.dirname(os.path.abspath(__file__));
    jn = compile_fmux("VDP_pack.VDP_Opt2", curr_dir + "/files/VDP.mop")
    model = CasadiModel(jn)
    
    # Set algorithm options
    opts = model.optimize_options()
    opts['graph'] = "SX"
    
    # Optimize
    res = model.optimize(options=opts)
    
    # Extract variable profiles
    x1 = res['x1']
    x2 = res['x2']
    u = res['u']
    time = res['time']
    
    assert N.abs(res.final('x1')) < 1e-3
    assert N.abs(res.final('x2')) < 1e-3
    
    # Plot
    if with_plots:
        plt.figure(1)
        plt.clf()
        plt.subplot(3, 1, 1)
        plt.plot(time, x1)
        plt.grid()
        plt.ylabel('x1')
        
        plt.subplot(3, 1, 2)
        plt.plot(time, x2)
        plt.grid()
        plt.ylabel('x2')
        
        plt.subplot(3, 1, 3)
        plt.plot(time, u)
        plt.grid()
        plt.ylabel('u')
        plt.xlabel('time')
        plt.show()
def run_demo(with_plots=True):

    curr_dir = os.path.dirname(os.path.abspath(__file__));
        
    jmu_name  = compile_jmu("Orbital", curr_dir+"/files/Hohmann.mop")
    comp_opts = {"normalize_minimum_time_problems": False} # Disable minimum time normalization
    fmux_name = compile_fmux("HohmannTransfer", curr_dir+"/files/Hohmann.mop",
                             compiler_options=comp_opts)

    # Optimization
    model = CasadiModel(fmux_name)
    opts = model.optimize_options(algorithm="CasadiPseudoSpectralAlg")
    opts["n_cp"] = 40                                      # Number of collocation points
    opts["n_e"] = 2                                        # Number of phases
    opts["free_phases"] = True                             # The phase boundary is allowed to be changed in time
    opts["phase_options"] = ["t1"]                         # The phase boundary is connected to variable t1
    opts["link_options"] = [(1,"vy","dy1"),(1,"vx","dx1")] # Allow for discontinuities between phase 1 and 2 for vy and vx.
                                                           # The discontinuities are connected by dy1 and dx1
    # Optimize
    res_opt = model.optimize(algorithm="CasadiPseudoSpectralAlg", options=opts)

    # Get results
    dx1,dy1,dx2,dy2 = res_opt.final("dx1"), res_opt.final("dy1"), res_opt.final("dx2"), res_opt.final("dy2")
    r1,r2,my        = res_opt.final("rStart"), res_opt.final("rFinal"), res_opt.final("my")
    tf,t1           = res_opt.final("time"), res_opt.final("t1")
    
    # Verify solution using theoretical results
    # Assert dv1 
    assert N.abs( N.sqrt(dx1**2+dy1**2) - N.sqrt(my/r1)*(N.sqrt(2*r2/(r1+r2))-1) ) < 1e-1
    #Assert dv2 
    assert N.abs( N.sqrt(dx2**2+dy2**2) - N.sqrt(my/r2)*(1-N.sqrt(2*r1/(r1+r2))) ) < 1e-1
    #Assert transfer time 
    assert N.abs( tf-t1 - N.pi*((r1+r2)**3/(8*my))**0.5 ) < 1e-1

    # Verify solution by simulation
    model = JMUModel(jmu_name)
    
    # Retrieve the options
    opts = model.simulate_options()
    
    opts["ncp"] = 100
    opts["solver"] = "IDA"
    opts["initialize"] = False
    
    # Simulation of Phase 1
    res = model.simulate(final_time=t1,options=opts)

    x_phase_1,y_phase_1 = res["x"], res["y"]
    
    # Simulation of Phase 2
    model.set("vx", dx1 + res.final("vx"))
    model.set("vy", dy1 + res.final("vy"))

    res = model.simulate(start_time=t1,final_time=tf,options=opts)

    x_phase_2,y_phase_2 = res["x"], res["y"]

    # Simulation of Phase 3 (verify that we are still in orbit)
    model.set("vx", dx2 + res.final("vx"))
    model.set("vy", dy2 + res.final("vy"))

    res = model.simulate(start_time=tf, final_time=tf*2, options=opts)

    x_phase_3,y_phase_3 = res["x"], res["y"]
    
    if with_plots:
        # Plot Earth
        r = 1.0
        xE = r*N.cos(N.linspace(0,2*N.pi,200))
        yE = r*N.sin(N.linspace(0,2*N.pi,200))
        plt.plot(xE,yE,label="Earth")

        # Plot Orbits
        r = res.final("rStart")
        xS = r*N.cos(N.linspace(0,2*N.pi,200))
        yS = r*N.sin(N.linspace(0,2*N.pi,200))
        plt.plot(xS,yS,label="Low Orbit")

        r = res.final("rFinal")
        xSE = r*N.cos(N.linspace(0,2*N.pi,200))
        ySE = r*N.sin(N.linspace(0,2*N.pi,200))
        plt.plot(xSE,ySE,label="High Orbit")
        
        # Plot Satellite trajectory
        x_sim=N.hstack((N.hstack((x_phase_1,x_phase_2)),x_phase_3))
        y_sim=N.hstack((N.hstack((y_phase_1,y_phase_2)),y_phase_3))

        plt.plot(x_sim,y_sim,"-",label="Satellite")
        
        # Plot Rocket Burns
        plt.arrow(x_phase_1[-1],y_phase_1[-1],0.5*dx1,0.5*dy1, width=0.01,label="dv1")
        plt.arrow(x_phase_2[-1],y_phase_2[-1],0.5*dx2,0.5*dy2, width=0.01,label="dv2")
        
        plt.legend()
        plt.show()
Beispiel #8
0
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()
Beispiel #9
0
def run_demo(with_plots=True):

    curr_dir = os.path.dirname(os.path.abspath(__file__))

    jmu_name = compile_jmu("Orbital", curr_dir + "/files/Hohmann.mop")
    comp_opts = {
        "normalize_minimum_time_problems": False
    }  # Disable minimum time normalization
    fmux_name = compile_fmux("HohmannTransfer",
                             curr_dir + "/files/Hohmann.mop",
                             compiler_options=comp_opts)

    # Optimization
    model = CasadiModel(fmux_name)
    opts = model.optimize_options(algorithm="CasadiPseudoSpectralAlg")
    opts["n_cp"] = 40  # Number of collocation points
    opts["n_e"] = 2  # Number of phases
    opts[
        "free_phases"] = True  # The phase boundary is allowed to be changed in time
    opts["phase_options"] = [
        "t1"
    ]  # The phase boundary is connected to variable t1
    opts["link_options"] = [
        (1, "vy", "dy1"), (1, "vx", "dx1")
    ]  # Allow for discontinuities between phase 1 and 2 for vy and vx.
    # The discontinuities are connected by dy1 and dx1
    # Optimize
    res_opt = model.optimize(algorithm="CasadiPseudoSpectralAlg", options=opts)

    # Get results
    dx1, dy1, dx2, dy2 = res_opt.final("dx1"), res_opt.final(
        "dy1"), res_opt.final("dx2"), res_opt.final("dy2")
    r1, r2, my = res_opt.final("rStart"), res_opt.final(
        "rFinal"), res_opt.final("my")
    tf, t1 = res_opt.final("time"), res_opt.final("t1")

    # Verify solution using theoretical results
    # Assert dv1
    assert N.abs(
        N.sqrt(dx1**2 + dy1**2) - N.sqrt(my / r1) *
        (N.sqrt(2 * r2 / (r1 + r2)) - 1)) < 1e-1
    #Assert dv2
    assert N.abs(
        N.sqrt(dx2**2 + dy2**2) - N.sqrt(my / r2) *
        (1 - N.sqrt(2 * r1 / (r1 + r2)))) < 1e-1
    #Assert transfer time
    assert N.abs(tf - t1 - N.pi * ((r1 + r2)**3 / (8 * my))**0.5) < 1e-1

    # Verify solution by simulation
    model = JMUModel(jmu_name)

    # Retrieve the options
    opts = model.simulate_options()

    opts["ncp"] = 100
    opts["solver"] = "IDA"
    opts["initialize"] = False

    # Simulation of Phase 1
    res = model.simulate(final_time=t1, options=opts)

    x_phase_1, y_phase_1 = res["x"], res["y"]

    # Simulation of Phase 2
    model.set("vx", dx1 + res.final("vx"))
    model.set("vy", dy1 + res.final("vy"))

    res = model.simulate(start_time=t1, final_time=tf, options=opts)

    x_phase_2, y_phase_2 = res["x"], res["y"]

    # Simulation of Phase 3 (verify that we are still in orbit)
    model.set("vx", dx2 + res.final("vx"))
    model.set("vy", dy2 + res.final("vy"))

    res = model.simulate(start_time=tf, final_time=tf * 2, options=opts)

    x_phase_3, y_phase_3 = res["x"], res["y"]

    if with_plots:
        # Plot Earth
        r = 1.0
        xE = r * N.cos(N.linspace(0, 2 * N.pi, 200))
        yE = r * N.sin(N.linspace(0, 2 * N.pi, 200))
        plt.plot(xE, yE, label="Earth")

        # Plot Orbits
        r = res.final("rStart")
        xS = r * N.cos(N.linspace(0, 2 * N.pi, 200))
        yS = r * N.sin(N.linspace(0, 2 * N.pi, 200))
        plt.plot(xS, yS, label="Low Orbit")

        r = res.final("rFinal")
        xSE = r * N.cos(N.linspace(0, 2 * N.pi, 200))
        ySE = r * N.sin(N.linspace(0, 2 * N.pi, 200))
        plt.plot(xSE, ySE, label="High Orbit")

        # Plot Satellite trajectory
        x_sim = N.hstack((N.hstack((x_phase_1, x_phase_2)), x_phase_3))
        y_sim = N.hstack((N.hstack((y_phase_1, y_phase_2)), y_phase_3))

        plt.plot(x_sim, y_sim, "-", label="Satellite")

        # Plot Rocket Burns
        plt.arrow(x_phase_1[-1],
                  y_phase_1[-1],
                  0.5 * dx1,
                  0.5 * dy1,
                  width=0.01,
                  label="dv1")
        plt.arrow(x_phase_2[-1],
                  y_phase_2[-1],
                  0.5 * dx2,
                  0.5 * dy2,
                  width=0.01,
                  label="dv2")

        plt.legend()
        plt.show()
Beispiel #10
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. 
    """

    curr_dir = os.path.dirname(os.path.abspath(__file__))

    # Load measurement data from file
    data = loadmat(curr_dir + '/files/qt_par_est_data.mat', appendmat=False)

    # Extract data series
    t_meas = data['t'][6000::100, 0] - 60
    y1_meas = data['y1_f'][6000::100, 0] / 100
    y2_meas = data['y2_f'][6000::100, 0] / 100
    y3_meas = data['y3_d'][6000::100, 0] / 100
    y4_meas = data['y4_d'][6000::100, 0] / 100
    u1 = data['u1_d'][6000::100, 0]
    u2 = data['u2_d'][6000::100, 0]

    # Plot measurements and inputs
    if with_plots:
        plt.figure(1)
        plt.clf()
        plt.subplot(2, 2, 1)
        plt.plot(t_meas, y3_meas)
        plt.title('x3')
        plt.grid()
        plt.subplot(2, 2, 2)
        plt.plot(t_meas, y4_meas)
        plt.title('x4')
        plt.grid()
        plt.subplot(2, 2, 3)
        plt.plot(t_meas, y1_meas)
        plt.title('x1')
        plt.xlabel('t[s]')
        plt.grid()
        plt.subplot(2, 2, 4)
        plt.plot(t_meas, y2_meas)
        plt.title('x2')
        plt.xlabel('t[s]')
        plt.grid()

        plt.figure(2)
        plt.clf()
        plt.subplot(2, 1, 1)
        plt.plot(t_meas, u1)
        plt.hold(True)
        plt.title('u1')
        plt.grid()
        plt.subplot(2, 1, 2)
        plt.plot(t_meas, u2)
        plt.title('u2')
        plt.xlabel('t[s]')
        plt.hold(True)
        plt.grid()

    # Build input trajectory matrix for use in simulation
    u = N.transpose(N.vstack((t_meas, u1, u2)))

    # compile FMU
    fmu_name = compile_fmu('QuadTankPack.Sim_QuadTank',
                           curr_dir + '/files/QuadTankPack.mop')

    # Load model
    model = load_fmu(fmu_name)

    # Simulate model response with nominal parameters
    res = model.simulate(input=(['u1', 'u2'], u), start_time=0., final_time=60)

    # Load simulation result
    x1_sim = res['qt.x1']
    x2_sim = res['qt.x2']
    x3_sim = res['qt.x3']
    x4_sim = res['qt.x4']
    t_sim = res['time']

    u1_sim = res['u1']
    u2_sim = res['u2']

    assert N.abs(res.final('qt.x1') - 0.05642485) < 1e-3
    assert N.abs(res.final('qt.x2') - 0.05510478) < 1e-3
    assert N.abs(res.final('qt.x3') - 0.02736532) < 1e-3
    assert N.abs(res.final('qt.x4') - 0.02789808) < 1e-3
    assert N.abs(res.final('u1') - 6.0) < 1e-3
    assert N.abs(res.final('u2') - 5.0) < 1e-3

    # Plot simulation result
    if with_plots:
        plt.figure(1)
        plt.subplot(2, 2, 1)
        plt.plot(t_sim, x3_sim)
        plt.subplot(2, 2, 2)
        plt.plot(t_sim, x4_sim)
        plt.subplot(2, 2, 3)
        plt.plot(t_sim, x1_sim)
        plt.subplot(2, 2, 4)
        plt.plot(t_sim, x2_sim)

        plt.figure(2)
        plt.subplot(2, 1, 1)
        plt.plot(t_sim, u1_sim, 'r')
        plt.subplot(2, 1, 2)
        plt.plot(t_sim, u2_sim, 'r')

    # Compile the Optimica model to an XML file
    model_name = compile_fmux("QuadTankPack.QuadTank_ParEstCasADi",
                              curr_dir + "/files/QuadTankPack.mop")

    # Load the model
    model_casadi = CasadiModel(model_name)
    """
    The collocation algorithm minimizes, if the parameter_estimation_data
    option is set, a quadrature approximation of the integral

    \int_{t_0}^{t_f} (y(t)-y^{meas}(t))^T Q (y(t)-y^{meas}(t)) dt

    The measurement data is given as a matrix where the first
    column is time and the following column contains data corresponding
    to the variable names given in the measured_variables list.

    Notice that input trajectories used in identification experiments
    are handled using the errors in variables method, i.e., deviations
    from the measured inputs are penalized in the cost function, rather
    than forcing the inputs to follow the measurement profile exactly.
    The weighting matrix Q may be used to express that inputs are typically
    more reliable than than measured outputs.
    """

    # Create measurement data
    Q = N.diag([1., 1., 10., 10.])
    data_x1 = N.vstack([t_meas, y1_meas])
    data_x2 = N.vstack([t_meas, y2_meas])
    data_u1 = N.vstack([t_meas, u1])
    data_u2 = N.vstack([t_meas, u2])
    unconstrained = OrderedDict()
    unconstrained['qt.x1'] = data_x1
    unconstrained['qt.x2'] = data_x2
    unconstrained['u1'] = data_u1
    unconstrained['u2'] = data_u2
    measurement_data = MeasurementData(Q=Q, unconstrained=unconstrained)

    opts = model_casadi.optimize_options()

    opts['n_e'] = 60

    opts['measurement_data'] = measurement_data

    res = model_casadi.optimize(algorithm="LocalDAECollocationAlg",
                                options=opts)

    # Load state profiles
    x1_opt = res["qt.x1"]
    x2_opt = res["qt.x2"]
    x3_opt = res["qt.x3"]
    x4_opt = res["qt.x4"]
    u1_opt = res["qt.u1"]
    u2_opt = res["qt.u2"]
    t_opt = res["time"]

    # Extract optimal values of parameters
    a1_opt = res.final("qt.a1")
    a2_opt = res.final("qt.a2")

    # Print and assert optimal parameter values
    print('a1: ' + str(a1_opt * 1e4) + 'cm^2')
    print('a2: ' + str(a2_opt * 1e4) + 'cm^2')
    a_ref = [0.02656702, 0.02713898]
    N.testing.assert_allclose(1e4 * N.array([a1_opt, a2_opt]),
                              [0.02656702, 0.02713898],
                              rtol=1e-4)

    # Plot
    if with_plots:
        plt.figure(1)
        plt.subplot(2, 2, 1)
        plt.plot(t_opt, x3_opt, 'k')
        plt.subplot(2, 2, 2)
        plt.plot(t_opt, x4_opt, 'k')
        plt.subplot(2, 2, 3)
        plt.plot(t_opt, x1_opt, 'k')
        plt.subplot(2, 2, 4)
        plt.plot(t_opt, x2_opt, 'k')

        plt.figure(2)
        plt.subplot(2, 1, 1)
        plt.plot(t_opt, u1_opt, 'k')
        plt.subplot(2, 1, 2)
        plt.plot(t_opt, u2_opt, 'k')
        plt.show()
Beispiel #11
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 was published in
    @InProceedings{CFA2011,
      author = "Casella, Francesco and Donida, Filippo and {\AA}kesson, Johan",
      title = "Object-Oriented Modeling and Optimal Control: A Case Study in
               Power Plant Start-Up",
      booktitle = "18th IFAC World Congress",
      address = "Milano, Italy",
      year = 2011,
      month = aug
    }
    """
    ### 1. Compute initial guess trajectories by means of simulation
    # Locate the Modelica and Optimica code
    file_paths = (os.path.join(get_files_path(), "CombinedCycle.mo"),
                  os.path.join(get_files_path(), "CombinedCycleStartup.mop"))
    
    # Compile the optimization initialization model
    init_sim_fmu = compile_fmu("CombinedCycleStartup.Startup6Reference",
                               file_paths)
    
    # Load the model
    init_sim_model = load_fmu(init_sim_fmu)
    
    # Simulate
    init_res = init_sim_model.simulate(start_time=0., final_time=10000.)
    
    # Extract variable profiles
    init_sim_plant_p = init_res['plant.p']
    init_sim_plant_sigma = init_res['plant.sigma']
    init_sim_plant_load = init_res['plant.load']
    init_sim_time = init_res['time']
    
    # Plot the initial guess trajectories
    if with_plots:
        plt.close(1)
        plt.figure(1)
        plt.subplot(3, 1, 1)
        plt.plot(init_sim_time, init_sim_plant_p * 1e-6)
        plt.ylabel('evaporator pressure [MPa]')
        plt.grid(True)
        plt.title('Initial guess obtained by simulation')
        
        plt.subplot(3, 1, 2)
        plt.plot(init_sim_time, init_sim_plant_sigma * 1e-6)
        plt.grid(True)
        plt.ylabel('turbine thermal stress [MPa]')
        
        plt.subplot(3, 1, 3)
        plt.plot(init_sim_time, init_sim_plant_load)
        plt.grid(True)
        plt.ylabel('input load [1]')
        plt.xlabel('time [s]')
    
    ### 2. Solve the optimal control problem
    # Compile model
    fmux = compile_fmux("CombinedCycleStartup.Startup6", file_paths)
    
    # Load model
    opt_model = CasadiModel(fmux)
    
    # Set options
    opt_opts = opt_model.optimize_options()
    opt_opts['n_e'] = 50 # Number of elements
    opt_opts['init_traj'] = init_res.result_data # Simulation result
    opt_opts['nominal_traj'] = init_res.result_data
    
    # Solve the optimal control problem
    opt_res = opt_model.optimize(options=opt_opts)
    
    # Extract variable profiles
    opt_plant_p = opt_res['plant.p']
    opt_plant_sigma = opt_res['plant.sigma']
    opt_plant_load = opt_res['plant.load']
    opt_time = opt_res['time']
    opt_input = N.vstack([opt_time, opt_plant_load]).T
    
    # Plot the optimized trajectories
    if with_plots:
        plt.close(2)
        plt.figure(2)
        plt.subplot(3, 1, 1)
        plt.plot(opt_time, opt_plant_p * 1e-6)
        plt.ylabel('evaporator pressure [MPa]')
        plt.grid(True)
        plt.title('Optimized trajectories')
        
        plt.subplot(3, 1, 2)
        plt.plot(opt_time, opt_plant_sigma * 1e-6)
        plt.grid(True)
        plt.ylabel('turbine thermal stress [MPa]')
        
        plt.subplot(3, 1, 3)
        plt.plot(opt_time, opt_plant_load)
        plt.grid(True)
        plt.ylabel('input load [1]')
        plt.xlabel('time [s]')
    
    # Verify solution for testing purposes
    try:
        import casadi
    except:
        pass
    else:
        cost = float(opt_res.solver.solver.output(casadi.NLP_SOLVER_F))
        N.testing.assert_allclose(cost, 17492.465548193624, rtol=1e-5)

    ### 3. Simulate to verify the optimal solution
    # Compile model
    sim_fmu = compile_fmu("CombinedCycle.Optimization.Plants.CC0D_WarmStartUp",
                          file_paths)

    # Load model
    sim_model = load_fmu(sim_fmu)
    
    # Simulate using optimized input
    sim_res = sim_model.simulate(start_time=0., final_time=4000.,
                                 input=('load', opt_input))
    
    # Extract variable profiles
    sim_plant_p = sim_res['p']
    sim_plant_sigma = sim_res['sigma']
    sim_plant_load = sim_res['load']
    sim_time = sim_res['time']
    
    # Plot the simulated trajectories
    if with_plots:
        plt.close(3)
        plt.figure(3)
        plt.subplot(3, 1, 1)
        plt.plot(opt_time, opt_plant_p * 1e-6, '--', lw=5)
        plt.hold(True)
        plt.plot(sim_time, sim_plant_p * 1e-6, lw=2)
        plt.ylabel('evaporator pressure [MPa]')
        plt.grid(True)
        plt.legend(('optimized', 'simulated'), loc='lower right')
        plt.title('Verification')
        
        plt.subplot(3, 1, 2)
        plt.plot(opt_time, opt_plant_sigma * 1e-6, '--', lw=5)
        plt.hold(True)
        plt.plot(sim_time, sim_plant_sigma * 1e-6, lw=2)
        plt.ylabel('turbine thermal stress [MPa]')
        plt.grid(True)
        
        plt.subplot(3, 1, 3)
        plt.plot(opt_time, opt_plant_load, '--', lw=5)
        plt.hold(True)
        plt.plot(sim_time, sim_plant_load, lw=2)
        plt.ylabel('input load [1]')
        plt.xlabel('time [s]')
        plt.grid(True)
        plt.show()
    
    # Verify solution for testing purposes
    N.testing.assert_allclose(opt_res.final('plant.p'),
                              sim_res.final('p'), rtol=5e-3)
def run_demo(with_plots=True):
    """
    Demonstrate how to solve a simple parameter estimation problem.
    """
    
    # Locate model file
    curr_dir = os.path.dirname(os.path.abspath(__file__));
    model_path = curr_dir + "/files/ParameterEstimation_1.mop"
    
    # Compile the model into an FMU and FMUX
    fmu = compile_fmu("ParEst.SecondOrder", model_path)
    fmux = compile_fmux("ParEst.ParEstCasADi", model_path)
    
    # Load the model
    sim_model = load_fmu(fmu)
    opt_model = CasadiModel(fmux)
    
    # Simulate model with nominal parameters
    sim_res = sim_model.simulate(final_time=10)
        
    # Extract nominal trajectories
    t_sim = sim_res['time']
    x1_sim = sim_res['x1']
    x2_sim = sim_res['x2']

    # Get measurement data with 1 Hz and add measurement noise
    sim_model = load_fmu(fmu)
    meas_res = sim_model.simulate(final_time=10, options={'ncp': 10})
    x1_meas = meas_res['x1']
    noise = [0.01463904, 0.0139424, 0.09834249, 0.0768069, 0.01971631, 
             -0.03827911, 0.05266659, -0.02608245, 0.05270525, 0.04717024,
             0.0779514]
    t_meas = N.linspace(0, 10, 11)
    y_meas = x1_meas + noise

    if with_plots:
        # Plot simulation
        plt.close(1)
        plt.figure(1)
        plt.subplot(2, 1, 1)
        plt.plot(t_sim, x1_sim)
        plt.grid()
        plt.plot(t_meas, y_meas, 'x')
        plt.ylabel('x1')
        
        plt.subplot(2, 1, 2)
        plt.plot(t_sim, x2_sim)
        plt.grid()
        plt.ylabel('x2')
        plt.show()
    
    # Create MeasurementData object
    Q = N.array([[1.]])
    unconstrained = OrderedDict()
    unconstrained['sys.y'] = N.vstack([t_meas, y_meas])
    measurement_data = MeasurementData(Q=Q, unconstrained=unconstrained)
    
    # Set optimization options
    opts = opt_model.optimize_options()
    opts['measurement_data'] = measurement_data
    opts['n_e'] = 16
    
    # Optimize
    opt_res = opt_model.optimize(options=opts)

    # Extract variable profiles
    x1_opt = opt_res['sys.x1']
    x2_opt = opt_res['sys.x2']
    w_opt = opt_res.final('sys.w')
    z_opt = opt_res.final('sys.z')
    t_opt = opt_res['time']
    
    # Assert results
    assert N.abs(opt_res.final('sys.x1') - 1.) < 1e-2
    assert N.abs(w_opt - 1.05)  < 1e-2
    assert N.abs(z_opt - 0.47)   < 1e-2
    
    # Plot optimization result
    if with_plots:
        plt.close(2)
        plt.figure(2)
        plt.subplot(2, 1, 1)
        plt.plot(t_opt, x1_opt, 'g')
        plt.plot(t_sim, x1_sim)
        plt.plot(t_meas, y_meas, 'x')
        plt.grid()
        plt.subplot(2, 1, 2)
        plt.plot(t_opt, x2_opt, 'g')
        plt.grid()
        plt.plot(t_sim, x2_sim)
        plt.show()
        
        print("** Optimal parameter values: **")
        print("w = %f" % w_opt)
        print("z = %f" % z_opt)
Beispiel #13
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 was published in
    @InProceedings{CFA2011,
      author = "Casella, Francesco and Donida, Filippo and {\AA}kesson, Johan",
      title = "Object-Oriented Modeling and Optimal Control: A Case Study in
               Power Plant Start-Up",
      booktitle = "18th IFAC World Congress",
      address = "Milano, Italy",
      year = 2011,
      month = aug
    }
    """
    ### 1. Compute initial guess trajectories by means of simulation
    # Locate the Modelica and Optimica code
    file_paths = (os.path.join(get_files_path(), "CombinedCycle.mo"),
                  os.path.join(get_files_path(), "CombinedCycleStartup.mop"))

    # Compile the optimization initialization model
    init_sim_fmu = compile_fmu("CombinedCycleStartup.Startup6Reference",
                               file_paths)

    # Load the model
    init_sim_model = load_fmu(init_sim_fmu)

    # Simulate
    init_res = init_sim_model.simulate(start_time=0., final_time=10000.)

    # Extract variable profiles
    init_sim_plant_p = init_res['plant.p']
    init_sim_plant_sigma = init_res['plant.sigma']
    init_sim_plant_load = init_res['plant.load']
    init_sim_time = init_res['time']

    # Plot the initial guess trajectories
    if with_plots:
        plt.close(1)
        plt.figure(1)
        plt.subplot(3, 1, 1)
        plt.plot(init_sim_time, init_sim_plant_p * 1e-6)
        plt.ylabel('evaporator pressure [MPa]')
        plt.grid(True)
        plt.title('Initial guess obtained by simulation')

        plt.subplot(3, 1, 2)
        plt.plot(init_sim_time, init_sim_plant_sigma * 1e-6)
        plt.grid(True)
        plt.ylabel('turbine thermal stress [MPa]')

        plt.subplot(3, 1, 3)
        plt.plot(init_sim_time, init_sim_plant_load)
        plt.grid(True)
        plt.ylabel('input load [1]')
        plt.xlabel('time [s]')

    ### 2. Solve the optimal control problem
    # Compile model
    fmux = compile_fmux("CombinedCycleStartup.Startup6", file_paths)

    # Load model
    opt_model = CasadiModel(fmux)

    # Set options
    opt_opts = opt_model.optimize_options()
    opt_opts['n_e'] = 50  # Number of elements
    opt_opts['init_traj'] = init_res.result_data  # Simulation result
    opt_opts['nominal_traj'] = init_res.result_data

    # Solve the optimal control problem
    opt_res = opt_model.optimize(options=opt_opts)

    # Extract variable profiles
    opt_plant_p = opt_res['plant.p']
    opt_plant_sigma = opt_res['plant.sigma']
    opt_plant_load = opt_res['plant.load']
    opt_time = opt_res['time']
    opt_input = N.vstack([opt_time, opt_plant_load]).T

    # Plot the optimized trajectories
    if with_plots:
        plt.close(2)
        plt.figure(2)
        plt.subplot(3, 1, 1)
        plt.plot(opt_time, opt_plant_p * 1e-6)
        plt.ylabel('evaporator pressure [MPa]')
        plt.grid(True)
        plt.title('Optimized trajectories')

        plt.subplot(3, 1, 2)
        plt.plot(opt_time, opt_plant_sigma * 1e-6)
        plt.grid(True)
        plt.ylabel('turbine thermal stress [MPa]')

        plt.subplot(3, 1, 3)
        plt.plot(opt_time, opt_plant_load)
        plt.grid(True)
        plt.ylabel('input load [1]')
        plt.xlabel('time [s]')

    # Verify solution for testing purposes
    try:
        import casadi
    except:
        pass
    else:
        cost = float(opt_res.solver.solver.output(casadi.NLP_SOLVER_F))
        N.testing.assert_allclose(cost, 17492.465548193624, rtol=1e-5)

    ### 3. Simulate to verify the optimal solution
    # Compile model
    sim_fmu = compile_fmu("CombinedCycle.Optimization.Plants.CC0D_WarmStartUp",
                          file_paths)

    # Load model
    sim_model = load_fmu(sim_fmu)

    # Simulate using optimized input
    sim_res = sim_model.simulate(start_time=0.,
                                 final_time=4000.,
                                 input=('load', opt_input))

    # Extract variable profiles
    sim_plant_p = sim_res['p']
    sim_plant_sigma = sim_res['sigma']
    sim_plant_load = sim_res['load']
    sim_time = sim_res['time']

    # Plot the simulated trajectories
    if with_plots:
        plt.close(3)
        plt.figure(3)
        plt.subplot(3, 1, 1)
        plt.plot(opt_time, opt_plant_p * 1e-6, '--', lw=5)
        plt.hold(True)
        plt.plot(sim_time, sim_plant_p * 1e-6, lw=2)
        plt.ylabel('evaporator pressure [MPa]')
        plt.grid(True)
        plt.legend(('optimized', 'simulated'), loc='lower right')
        plt.title('Verification')

        plt.subplot(3, 1, 2)
        plt.plot(opt_time, opt_plant_sigma * 1e-6, '--', lw=5)
        plt.hold(True)
        plt.plot(sim_time, sim_plant_sigma * 1e-6, lw=2)
        plt.ylabel('turbine thermal stress [MPa]')
        plt.grid(True)

        plt.subplot(3, 1, 3)
        plt.plot(opt_time, opt_plant_load, '--', lw=5)
        plt.hold(True)
        plt.plot(sim_time, sim_plant_load, lw=2)
        plt.ylabel('input load [1]')
        plt.xlabel('time [s]')
        plt.grid(True)
        plt.show()

    # Verify solution for testing purposes
    N.testing.assert_allclose(opt_res.final('plant.p'),
                              sim_res.final('p'),
                              rtol=5e-3)
def run_demo(with_plots=True):
    """
    This example demonstrates how to solve parameter estimation problmes.

    The data used in the example was recorded by Kristian Soltesz at the 
    Department of Automatic Control. 
    """
    
    curr_dir = os.path.dirname(os.path.abspath(__file__));

    # Load measurement data from file
    data = loadmat(curr_dir+'/files/qt_par_est_data.mat',appendmat=False)

    # Extract data series
    t_meas = data['t'][6000::100,0]-60
    y1_meas = data['y1_f'][6000::100,0]/100
    y2_meas = data['y2_f'][6000::100,0]/100
    y3_meas = data['y3_d'][6000::100,0]/100
    y4_meas = data['y4_d'][6000::100,0]/100
    u1 = data['u1_d'][6000::100,0]
    u2 = data['u2_d'][6000::100,0]
        
    # Plot measurements and inputs
    if with_plots:
        plt.figure(1)
        plt.clf()
        plt.subplot(2,2,1)
        plt.plot(t_meas,y3_meas)
        plt.title('x3')
        plt.grid()
        plt.subplot(2,2,2)
        plt.plot(t_meas,y4_meas)
        plt.title('x4')
        plt.grid()
        plt.subplot(2,2,3)
        plt.plot(t_meas,y1_meas)
        plt.title('x1')
        plt.xlabel('t[s]')
        plt.grid()
        plt.subplot(2,2,4)
        plt.plot(t_meas,y2_meas)
        plt.title('x2')
        plt.xlabel('t[s]')
        plt.grid()

        plt.figure(2)
        plt.clf()
        plt.subplot(2,1,1)
        plt.plot(t_meas,u1)
        plt.hold(True)
        plt.title('u1')
        plt.grid()
        plt.subplot(2,1,2)
        plt.plot(t_meas,u2)
        plt.title('u2')
        plt.xlabel('t[s]')
        plt.hold(True)
        plt.grid()

    # Build input trajectory matrix for use in simulation
    u = N.transpose(N.vstack((t_meas,u1,u2)))

    # compile FMU
    fmu_name = compile_fmu('QuadTankPack.Sim_QuadTank', 
        curr_dir+'/files/QuadTankPack.mop')

    # Load model
    model = load_fmu(fmu_name)
    
    # Simulate model response with nominal parameters
    res = model.simulate(input=(['u1','u2'],u),start_time=0.,final_time=60)

    # Load simulation result
    x1_sim = res['qt.x1']
    x2_sim = res['qt.x2']
    x3_sim = res['qt.x3']
    x4_sim = res['qt.x4']
    t_sim  = res['time']
    
    u1_sim = res['u1']
    u2_sim = res['u2']
    
    assert N.abs(res.final('qt.x1') - 0.05642485) < 1e-3
    assert N.abs(res.final('qt.x2') - 0.05510478) < 1e-3
    assert N.abs(res.final('qt.x3') - 0.02736532) < 1e-3
    assert N.abs(res.final('qt.x4') - 0.02789808) < 1e-3
    assert N.abs(res.final('u1') - 6.0)           < 1e-3
    assert N.abs(res.final('u2') - 5.0)           < 1e-3

    # Plot simulation result
    if with_plots:
        plt.figure(1)
        plt.subplot(2,2,1)
        plt.plot(t_sim,x3_sim)
        plt.subplot(2,2,2)
        plt.plot(t_sim,x4_sim)
        plt.subplot(2,2,3)
        plt.plot(t_sim,x1_sim)
        plt.subplot(2,2,4)
        plt.plot(t_sim,x2_sim)

        plt.figure(2)
        plt.subplot(2,1,1)
        plt.plot(t_sim,u1_sim,'r')
        plt.subplot(2,1,2)
        plt.plot(t_sim,u2_sim,'r')

    # Compile the Optimica model to an XML file
    model_name = compile_fmux("QuadTankPack.QuadTank_ParEstCasADi",
        curr_dir+"/files/QuadTankPack.mop")
    
    # Load the model
    model_casadi=CasadiModel(model_name)

    """
    The collocation algorithm minimizes, if the parameter_estimation_data
    option is set, a quadrature approximation of the integral

    \int_{t_0}^{t_f} (y(t)-y^{meas}(t))^T Q (y(t)-y^{meas}(t)) dt

    The measurement data is given as a matrix where the first
    column is time and the following column contains data corresponding
    to the variable names given in the measured_variables list.

    Notice that input trajectories used in identification experiments
    are handled using the errors in variables method, i.e., deviations
    from the measured inputs are penalized in the cost function, rather
    than forcing the inputs to follow the measurement profile exactly.
    The weighting matrix Q may be used to express that inputs are typically
    more reliable than than measured outputs.
    """
    
    # Create measurement data
    Q = N.diag([1., 1., 10., 10.])
    data_x1 = N.vstack([t_meas, y1_meas])
    data_x2 = N.vstack([t_meas, y2_meas])
    data_u1 = N.vstack([t_meas, u1])
    data_u2 = N.vstack([t_meas, u2])
    unconstrained = OrderedDict()
    unconstrained['qt.x1'] = data_x1
    unconstrained['qt.x2'] = data_x2
    unconstrained['u1'] = data_u1
    unconstrained['u2'] = data_u2
    measurement_data = MeasurementData(Q=Q, unconstrained=unconstrained)
    
    opts = model_casadi.optimize_options()
    
    opts['n_e'] = 60
    
    opts['measurement_data'] = measurement_data
    
    res = model_casadi.optimize(options=opts)
    
    # Load state profiles
    x1_opt = res["qt.x1"]
    x2_opt = res["qt.x2"]
    x3_opt = res["qt.x3"]
    x4_opt = res["qt.x4"]
    u1_opt = res["qt.u1"]
    u2_opt = res["qt.u2"]
    t_opt  = res["time"]

    # Extract optimal values of parameters
    a1_opt = res.final("qt.a1")
    a2_opt = res.final("qt.a2")

    # Print and assert optimal parameter values
    print('a1: ' + str(a1_opt*1e4) + 'cm^2')
    print('a2: ' + str(a2_opt*1e4) + 'cm^2')
    a_ref = [0.02656702, 0.02713898]
    N.testing.assert_allclose(1e4 * N.array([a1_opt, a2_opt]),
                              [0.02656702, 0.02713898], rtol=1e-4)
    
    # Plot
    if with_plots:
        plt.figure(1)
        plt.subplot(2,2,1)
        plt.plot(t_opt,x3_opt,'k')
        plt.subplot(2,2,2)
        plt.plot(t_opt,x4_opt,'k')
        plt.subplot(2,2,3)
        plt.plot(t_opt,x1_opt,'k')
        plt.subplot(2,2,4)
        plt.plot(t_opt,x2_opt,'k')

        plt.figure(2)
        plt.subplot(2,1,1)
        plt.plot(t_opt,u1_opt,'k')
        plt.subplot(2,1,2)
        plt.plot(t_opt,u2_opt,'k')
        plt.show()
Beispiel #15
0
def run_demo(with_plots=True):
    """
    This example is based on the Hicks-Ray Continuously Stirred Tank Reactors 
    (CSTR) system. The system has two states, the concentration and the 
    temperature. The control input to the system is the temperature of the 
    cooling flow in the reactor jacket. The chemical reaction in the reactor is 
    exothermic, and also temperature dependent; high temperature results in high 
    reaction rate.
    
    The problem is solved using the CasADi-based collocation algorithm. The
    steps performed correspond to those demonstrated in
    example pyjmi.examples.cstr, where the same problem is solved using the
    default JMI algorithm. FMI is used for initialization and simulation
    purposes.
    
    The following steps are demonstrated in this example:
    
    1.  How to solve the initialization problem. The initialization model has
        equations specifying that all derivatives should be identically zero,
        which implies that a stationary solution is obtained. Two stationary
        points, corresponding to different inputs, are computed. We call the
        stationary points A and B respectively. Point A corresponds to
        operating conditions where the reactor is cold and the reaction rate is
        low, whereas point B corresponds to a higher temperature where the
        reaction rate is high.
    
    2.  How to generate an initial guess for a direct collocation method by
        means of simulation with a constant input. The trajectories resulting
        from the simulation are used to initialize the variables in the
        transcribed NLP.
       
    3.  An optimal control problem is solved where the objective is to transfer 
        the state of the system from stationary point A to point B. The
        challenge is to ignite the reactor while avoiding uncontrolled
        temperature increase.

    4.  Finally the system is simulated using the optimal control profile. This
        step is important in order to verify that the approximation in the
        transcription step is sufficiently accurate.
    """
    ### 1. Solve the initialization problem
    # Locate the Modelica and Optimica code
    file_path = os.path.join(get_files_path(), "CSTR.mop")
    
    # Compile the stationary initialization model into a FMU
    init_fmu = compile_fmu("CSTR.CSTR_Init", file_path)
    
    # Load the FMU
    init_model = load_fmu(init_fmu)
    
    # Set input for Stationary point A
    Tc_0_A = 250
    init_model.set('Tc', Tc_0_A)

    # Solve the initialization problem using FMI
    init_model.initialize()

    # Store stationary point A
    [c_0_A, T_0_A] = init_model.get(['c', 'T'])

    # Print some data for stationary point A
    print(' *** Stationary point A ***')
    print('Tc = %f' % Tc_0_A)
    print('c = %f' % c_0_A)
    print('T = %f' % T_0_A)
    
    # Set inputs for Stationary point B
    init_model = load_fmu(init_fmu)
    Tc_0_B = 280
    init_model.set('Tc', Tc_0_B)

    # Solve the initialization problem using FMI
    init_model.initialize()

    # Store stationary point B
    [c_0_B, T_0_B] = init_model.get(['c', 'T'])

    # Print some data for stationary point B
    print(' *** Stationary point B ***')
    print('Tc = %f' % Tc_0_B)
    print('c = %f' % c_0_B)
    print('T = %f' % T_0_B)
    
    ### 2. Compute initial guess trajectories by means of simulation
    # Compile the optimization initialization model
    init_sim_fmu = compile_fmu("CSTR.CSTR_Init_Optimization", file_path)

    # Load the model
    init_sim_model = load_fmu(init_sim_fmu)
    
    # Set initial and reference values
    init_sim_model.set('cstr.c_init', c_0_A)
    init_sim_model.set('cstr.T_init', T_0_A)
    init_sim_model.set('c_ref', c_0_B)
    init_sim_model.set('T_ref', T_0_B)
    init_sim_model.set('Tc_ref', Tc_0_B)
    
    # Simulate with constant input Tc
    init_res = init_sim_model.simulate(start_time=0., final_time=150.)

    # Extract variable profiles
    c_init_sim = init_res['cstr.c']
    T_init_sim = init_res['cstr.T']
    Tc_init_sim = init_res['cstr.Tc']
    t_init_sim = init_res['time']
    
    # Plot the initial guess trajectories
    if with_plots:
        plt.close(1)
        plt.figure(1)
        plt.hold(True)
        plt.subplot(3, 1, 1)
        plt.plot(t_init_sim, c_init_sim)
        plt.grid()
        plt.ylabel('Concentration')
        plt.title('Initial guess obtained by simulation')

        plt.subplot(3, 1, 2)
        plt.plot(t_init_sim, T_init_sim)
        plt.grid()
        plt.ylabel('Temperature')

        plt.subplot(3, 1, 3)
        plt.plot(t_init_sim, Tc_init_sim)
        plt.grid()
        plt.ylabel('Cooling temperature')
        plt.xlabel('time')
        plt.show()
    
    ### 3. Solve the optimal control problem
    # Compile model
    fmux = compile_fmux("CSTR.CSTR_Opt2", file_path)
    
    # Load model
    cstr = CasadiModel(fmux)
    
    # Set reference values
    cstr.set('Tc_ref', Tc_0_B)
    cstr.set('c_ref', c_0_B)
    cstr.set('T_ref', T_0_B)
    
    # Set initial values
    cstr.set('cstr.c_init', c_0_A)
    cstr.set('cstr.T_init', T_0_A)
    
    # Set options
    opt_opts = cstr.optimize_options()
    opt_opts['n_e'] = 100 # Number of elements
    opt_opts['init_traj'] = init_res.result_data
    opt_opts['nominal_traj'] = init_res.result_data
    opt_opts['IPOPT_options']['tol'] = 1e-10
    
    # Solve the optimal control problem
    res = cstr.optimize(options=opt_opts)
    
    # Extract variable profiles
    c_res = res['cstr.c']
    T_res = res['cstr.T']
    Tc_res = res['cstr.Tc']
    time_res = res['time']

    c_ref = res['c_ref']
    T_ref = res['T_ref']
    Tc_ref = res['Tc_ref']
    
    # Verify solution for testing purposes
    try:
        import casadi
    except:
        pass
    else:
        cost = float(res.solver.solver.output(casadi.NLP_SOLVER_F))
        assert(N.abs(cost/1.e3 - 1.8585429) < 1e-3)
    
    # Plot the results
    if with_plots:
        plt.close(2)
        plt.figure(2)
        plt.hold(True)
        plt.subplot(3, 1, 1)
        plt.plot(time_res, c_res)
        plt.plot([time_res[0], time_res[-1]], [c_ref, c_ref], '--')
        plt.grid()
        plt.ylabel('Concentration')
        plt.title('Optimized trajectories')

        plt.subplot(312)
        plt.plot(time_res,T_res)
        plt.plot([time_res[0],time_res[-1]],[T_ref,T_ref],'--')
        plt.grid()
        plt.ylabel('Temperature')

        plt.subplot(313)
        plt.plot(time_res,Tc_res)
        plt.plot([time_res[0],time_res[-1]],[Tc_ref,Tc_ref],'--')
        plt.grid()
        plt.ylabel('Cooling temperature')
        plt.xlabel('time')
        plt.show()

    ### 4. Simulate to verify the optimal solution
    # Compile model
    sim_fmu = compile_fmu("CSTR.CSTR", file_path)

    # Load model
    sim_model = load_fmu(sim_fmu)
    
    # Get optimized input
    (_, opt_input) = res.solver.get_opt_input()
    
    # Set initial values
    sim_model.set('c_init',c_0_A)
    sim_model.set('T_init',T_0_A)

    # Simulate using optimized input
    sim_opts = sim_model.simulate_options()
    sim_opts['CVode_options']['rtol'] = 1e-6
    sim_opts['CVode_options']['atol'] = 1e-8
    res = sim_model.simulate(start_time=0., final_time=150.,
                             input=('Tc', opt_input), options=sim_opts)
    
    # Extract variable profiles
    c_sim=res['c']
    T_sim=res['T']
    Tc_sim=res['Tc']
    time_sim = res['time']

    # Verify results
    N.testing.assert_array_less(abs(c_res[-1] - c_sim[-1])/c_res[-1], 5e-2)
    
    # Plot the results
    if with_plots:
        plt.close(3)
        plt.figure(3)
        plt.hold(True)
        plt.subplot(3, 1, 1)
        plt.plot(time_res, c_res, '--', lw=5)
        plt.plot(time_sim, c_sim, lw=2)
        plt.legend(('optimized', 'simulated'))
        plt.grid(True)
        plt.ylabel('Concentration')
        plt.title('Verification')
        
        plt.subplot(3, 1, 2)
        plt.plot(time_res, T_res, '--', lw=5)
        plt.plot(time_sim, T_sim, lw=2)
        plt.grid(True)
        plt.ylabel('Temperature')
        
        plt.subplot(3, 1, 3)
        plt.plot(time_res, Tc_res, '--', lw=5)
        plt.plot(time_sim, Tc_sim, lw=2)
        plt.grid(True)
        plt.ylabel('Cooling temperature')
        plt.xlabel('time')
        plt.show()