BYU-PRISM / GEKKO

GEKKO Python for Machine Learning and Dynamic Optimization

Home Page:https://machinelearning.byu.edu

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Optimal Control Problem

agobL opened this issue · comments

commented

Hi,

I would like to optimize an optimal control problem with Gekko, but I don't know how to write it correctly.

On the code below, the input to optimize is the 23-elements-vector Pheat, so that the objective function Cost is minimized, and the 23-elements-vector Tint kept above a threshold value given by the setpoint list.
The computation of Tint is done by the simulateTint function. It's not an explicit mathematic formula, and I would like to know how to formulate it so that the algorithm takes it into account.

from gekko import GEKKO
import numpy as np
import pandas as pd

size = 1
optimizedParams = [9.99999946e+00, 3.56802228e+02, 2.19999993e+01, 8.38949750e+02
                              , 1.42500002e+02, 4.90000020e+01, 7.00000031e+00, 1.50000006e+00
                              , 1.82238388e+02, 6.63460266e+06, 8.66627245e+06, 8.35000109e+06
                              , 1.46599414e+08, 1.22564853e+06]
conductances = optimizedParams[0:9]
capacitances = optimizedParams[9:len(optimizedParams)]
df_1H = pd.read_csv('data1_1H.csv', index_col='date', parse_dates=['date'])
df_1H = df_1H[1:size * 24]

i = np.arange(len(df_1H))
setpoint = np.where(np.logical_or(np.logical_and(((i % 24) >= 6), ((i % 24) < 8)),
             np.logical_and(((i % 24) >= 18), ((i % 24) < 23))), 20., 0.)
TempCtr = [setpoint[i] for i in range(len(setpoint))]

def cgrid(Pgrid):
    off_peak_price = 0.1252  # €/kWh
    on_peak_price = 0.1593  # €/kWh
    N = len(Pgrid)
    i = np.arange(N)
    mask_price = np.where(
        np.logical_or((i % 24) < 7,
                      np.logical_and(((i % 24) >= 14), ((i % 24) < 17))
                      ), off_peak_price, on_peak_price)
    return Pgrid * mask_price

def Cost(Pheat):
    if len(Pheat) == 0:
        Pheat = df_1H['Pheat']
    cost = m.sum(cgrid(np.array(Pheat)))  # in €/kWh
    return cost

    
def simulateTint(Pheat):
    if len(Pheat) != 0:
        df_1H['Pheat'] = 1000 * np.array(Pheat)
    U = df_1H.values  # boundary conditions(External and adjacent zones temperatures,Solar and Internal gains)
    for i in range(len(U)):
        U[i][4]=U[i][4].value.value
    X0 = np.ones(5) * 14.9  # initialization with value from simulation
    [Uext1, Uext2, Ugar1, Ugar2, UBSoffice1, UBSoffice2, UBSroom1, UBSroom2, Uv] = [np.array(cond) for cond in
                                                                                    conductances]
    [Cext, Cgar, CBSoffice, CBSroom, Cair] = [np.array(capa) for capa in capacitances]

    # State matrix A of size 5 x 5
    C = np.array([Cext, Cgar, CBSoffice, CBSroom, Cair])
    A = np.array([[-(Uext1 + Uext2), 0, 0, 0, Uext2],
                  [0, -(Ugar1 + Ugar2), 0, 0, Ugar2],
                  [0, 0, -(UBSoffice1 + UBSoffice2), 0, UBSoffice2],
                  [0, 0, 0, -(UBSroom1 + UBSroom2), UBSroom2],
                  [Uext2, Ugar2, UBSoffice2, UBSroom2, -(Uv + Uext2 + Ugar2 + UBSoffice2 + UBSroom2)]])
    A = (A.T / C).T  # each lines of A is divided by each elements of C. ".T" means transpose
    # Matrix B of size 5 x 8
    B = np.array([[Uext1, 0, 0, 0, 0, 0, 0, 0],
                  [0, Ugar1, 0, 0, 0, 0, 0, 0],
                  [0, 0, UBSoffice1, 0, 0, 0, 0, 0],
                  [0, 0, 0, UBSroom1, 0, 0, 0, 0],
                  [Uv, 0, 0, 0, 1, 1, 1, 1]])
    B = (B.T / C).T  # each lines of B is divided by each elements of C. ".T" means transpose

    dt = 600  # 600s = 10 minutes

    # temporary matrices
    M1 = 2 * A + dt * np.dot(A, A)
    M2 = B + dt * np.dot(A, B)

    # initial states
    N = len(U)

    # Solve the numerical integration with Modified Euler's method
    Tint = np.array(X0[4])
    Xsave = X0
    for k in range(1, N):
        Xsave = Xsave + dt / 2.0 * (np.dot(M1, Xsave) + np.dot(M2, U[k - 1, :]) + np.dot(B, U[k, :]))
        Tint = np.append(Tint, Xsave[4])
    return Tint


m = GEKKO()

m.time = np.linspace(1,1, size * 24-1)
time=m.time

Pheat = m.Array(m.MV,(len(df_1H)))
j=0
for xi in Pheat:
    xi.value = 1.
    xi.lower = 0.
    xi.upper = 10.
    j += 1
m.Obj(Cost(Pheat))

Tint= m.Array(m.CV,(len(df_1H)))
j=0
for xi in Tint:
    xi.SPLO = setpoint[j]
    j += 1
    
m.Equations(Tint>TempCtr)
    
m.solve()

Thanks in advance.

Some functions such as np.dot() are allowed with Gekko arrays but others such as np.logical_or() do not return the correct form for Gekko automatic differentiation. Gekko uses gradient-based solvers so discontinuous functions are not allowed. Perhaps try scipy.optimize.minimize() instead?