"Solution Not Found" error using Gekko optimization suite when changing parameters, objective function, and initial condition

Viewed 212

I am trying to solve multiple optimization problems with various initial conditions using the Gekko suite. Initial conditions are assigned, run optimization using Gekko, and collect each solution. When I try to change parameters, objective function, or initial condition, Gekko often gives me 'Solution Not Found error: line 2130, in solve raise Exception(apm_error).' I am presenting some cases below hoping to get advice to resolve this problem I have. I had a similar question posted earlier, but I hope this question is more concise and clear. Thank you.

Case 1. runs well without error.

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

dat = {'A0': [23221, 2198, 4296, 104906, 691], 'h': [0.04, 0.25, 0.07, 0, 12.58],'emax': [23221, 2198, 4296, 104906, 691] }
dftemp = pd.DataFrame(data=dat)
na=len(dftemp)

# time points
n=51
year=50

# constants
Pa0 = 3.061 
Pe0 = 10.603 
C0 = 100 
r = 0.05 
k=50 
shift=10000000 # to make positive inside log function
ll=0.15

  
for i in range(0,na):
    # create GEKKO model
    m = GEKKO(remote=False)

    m.time = np.linspace(0,year,n)
    t=m.time
    
    A0=dftemp.loc[i][0]
    h=dftemp.loc[i][1]
    emax=dftemp.loc[i][2]    
    
    A = m.SV(value=A0, lb=0, ub=A0)
    E = m.SV(value=0, lb=0, ub=A0)

    u = m.MV(value=0, lb=-emax, ub=emax) 
    u.STATUS = 1

    t = m.Param(value=m.time)
    C = m.Var(value=C0)
    d = m.Var(value=1)
    l = m.Param(value=ll)
    
    # Equation
    m.Equation(A.dt()==-u)
    m.Equation(E.dt()==u)
    m.Equation(C.dt()==-C/k)
    m.Equation(d==m.exp(-t*r))
    # Objective (Utility)
    J = m.Var(value=0)
    
    # Final objective
    Jf = m.FV()
    Jf.STATUS = 1
    m.Connection(Jf,J,pos2='end')
    m.Equation(J.dt() == m.log((A+E*(1-l))*h*Pa0-C*u+E*Pe0+shift)*d)
    
    # maximize U
    m.Maximize(Jf)
    
    # options
    m.options.IMODE = 6  # optimal control
    m.options.NODES = 3  # collocation nodes
    m.options.SOLVER = 3 # solver (IPOPT)
    
    # solve optimization problem
    m.solve()
    
    # print profit
    print('Optimal Profit: ' + str(Jf.value[0]))
    

Case 2. change number of "time points" from n=51 to n=501 Error occurs

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

dat = {'A0': [23221, 2198, 4296, 104906, 691], 'h': [0.04, 0.25, 0.07, 0, 12.58],'emax': [23221, 2198, 4296, 104906, 691] }
dftemp = pd.DataFrame(data=dat)
na=len(dftemp)

# time points
n=501 
year=50

# constants
Pa0 = 3.061 
Pe0 = 10.603 
C0 = 100 
r = 0.05 
k=50 
shift=10000000 # to make positive inside log function
ll=0.15

   
for i in range(0,na):
    # create GEKKO model
    m = GEKKO(remote=False)

    m.time = np.linspace(0,year,n)
    t=m.time
    
    A0=dftemp.loc[i][0]
    h=dftemp.loc[i][1]
    emax=dftemp.loc[i][2]    
    
    A = m.SV(value=A0, lb=0, ub=A0)
    E = m.SV(value=0, lb=0, ub=A0)

    u = m.MV(value=0, lb=-emax, ub=emax) 
    u.STATUS = 1

    t = m.Param(value=m.time)
    C = m.Var(value=C0)
    d = m.Var(value=1)
    l = m.Param(value=ll)
    
    # Equation
    m.Equation(A.dt()==-u)
    m.Equation(E.dt()==u)
    m.Equation(C.dt()==-C/k)
    m.Equation(d==m.exp(-t*r))
    # Objective (Utility)
    J = m.Var(value=0)
    
    # Final objective
    Jf = m.FV()
    Jf.STATUS = 1
    m.Connection(Jf,J,pos2='end')
    m.Equation(J.dt() == m.log((A+E*(1-l))*h*Pa0-C*u+E*Pe0+shift)*d)
    
    # maximize U
    m.Maximize(Jf)
    
    # options
    m.options.IMODE = 6  # optimal control
    m.options.NODES = 3  # collocation nodes
    m.options.SOLVER = 3 # solver (IPOPT)
    
    # solve optimization problem
    m.solve()
    
    # print profit
    print('Optimal Profit: ' + str(Jf.value[0]))
    

Case 3. change objective function from m.log to simple linear sum. Works well.

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

dat = {'A0': [23221, 2198, 4296, 104906, 691], 'h': [0.04, 0.25, 0.07, 0, 12.58],'emax': [23221, 2198, 4296, 104906, 691] }
dftemp = pd.DataFrame(data=dat)
na=len(dftemp)

# time points
n=51
year=50

# constants
Pa0 = 3.061 
Pe0 = 10.603 
C0 = 100 
r = 0.05 
k=50 
shift=10000000 # to make positive inside log function
ll=0.15
    
for i in range(0,na):
    # create GEKKO model
    m = GEKKO(remote=False)

    m.time = np.linspace(0,year,n)
    t=m.time
    
    A0=dftemp.loc[i][0]
    h=dftemp.loc[i][1]
    emax=dftemp.loc[i][2]    
    
    A = m.SV(value=A0, lb=0, ub=A0)
    E = m.SV(value=0, lb=0, ub=A0)

    u = m.MV(value=0, lb=-emax, ub=emax) 
    u.STATUS = 1

    t = m.Param(value=m.time)
    C = m.Var(value=C0)
    d = m.Var(value=1)
    l = m.Param(value=ll)
    
    # Equation
    m.Equation(A.dt()==-u)
    m.Equation(E.dt()==u)
    m.Equation(C.dt()==-C/k)
    m.Equation(d==m.exp(-t*r))
    # Objective (Utility)
    J = m.Var(value=0)
    
    # Final objective
    Jf = m.FV()
    Jf.STATUS = 1
    m.Connection(Jf,J,pos2='end')
    m.Equation(J.dt() == ((A+E*(1-l))*h*Pa0-C*u+E*Pe0+shift)*d)
    
    # maximize U
    m.Maximize(Jf)
    
    # options
    m.options.IMODE = 6  # optimal control
    m.options.NODES = 3  # collocation nodes
    m.options.SOLVER = 3 # solver (IPOPT)
    
    # solve optimization problem
    m.solve()
    
    # print profit
    print('Optimal Profit: ' + str(Jf.value[0]))
    

Case 4. change objective function from m.log to simple sum, and remove "variable" d from the objective function. Error occurs

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

dat = {'A0': [23221, 2198, 4296, 104906, 691], 'h': [0.04, 0.25, 0.07, 0, 12.58],'emax': [23221, 2198, 4296, 104906, 691] }
dftemp = pd.DataFrame(data=dat)
na=len(dftemp)

# time points
n=51
year=50

# constants
Pa0 = 3.061 
Pe0 = 10.603 
C0 = 100 
r = 0.05 
k=50 
shift=10000000 # to make positive inside log function
ll=0.15

    
for i in range(0,na):
    # create GEKKO model
    m = GEKKO(remote=False)

    m.time = np.linspace(0,year,n)
    t=m.time
    
    A0=dftemp.loc[i][0]
    h=dftemp.loc[i][1]
    emax=dftemp.loc[i][2]    
    
    A = m.SV(value=A0, lb=0, ub=A0)
    E = m.SV(value=0, lb=0, ub=A0)

    u = m.MV(value=0, lb=-emax, ub=emax) 
    u.STATUS = 1

    t = m.Param(value=m.time)
    C = m.Var(value=C0)
    d = m.Var(value=1)
    l = m.Param(value=ll)
    
    # Equation
    m.Equation(A.dt()==-u)
    m.Equation(E.dt()==u)
    m.Equation(C.dt()==-C/k)
    m.Equation(d==m.exp(-t*r))
    # Objective (Utility)
    J = m.Var(value=0)
    
    # Final objective
    Jf = m.FV()
    Jf.STATUS = 1
    m.Connection(Jf,J,pos2='end')
    m.Equation(J.dt() == ((A+E*(1-l))*h*Pa0-C*u+E*Pe0+shift))
    
    # maximize U
    m.Maximize(Jf)
    
    # options
    m.options.IMODE = 6  # optimal control
    m.options.NODES = 3  # collocation nodes
    m.options.SOLVER = 3 # solver (IPOPT)
    
    # solve optimization problem
    m.solve()
    
    # print profit
    print('Optimal Profit: ' + str(Jf.value[0]))
    

Case 5. change objective function from m.log to simple linear sum, and change shift to 0. Error occurs

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

dat = {'A0': [23221, 2198, 4296, 104906, 691], 'h': [0.04, 0.25, 0.07, 0, 12.58],'emax': [23221, 2198, 4296, 104906, 691] }
dftemp = pd.DataFrame(data=dat)
na=len(dftemp)

# time points
n=51
year=50

# constants
Pa0 = 3.061 
Pe0 = 10.603 
C0 = 100 
r = 0.05 
k=50 
shift=0 
ll=0.15
    
for i in range(0,na):
    # create GEKKO model
    m = GEKKO(remote=False)

    m.time = np.linspace(0,year,n)
    t=m.time
    
    A0=dftemp.loc[i][0]
    h=dftemp.loc[i][1]
    emax=dftemp.loc[i][2]    
    
    A = m.SV(value=A0, lb=0, ub=A0)
    E = m.SV(value=0, lb=0, ub=A0)

    u = m.MV(value=0, lb=-emax, ub=emax) 
    u.STATUS = 1

    t = m.Param(value=m.time)
    C = m.Var(value=C0)
    d = m.Var(value=1)
    l = m.Param(value=ll)
    
    # Equation
    m.Equation(A.dt()==-u)
    m.Equation(E.dt()==u)
    m.Equation(C.dt()==-C/k)
    m.Equation(d==m.exp(-t*r))
    # Objective (Utility)
    J = m.Var(value=0)
    
    # Final objective
    Jf = m.FV()
    Jf.STATUS = 1
    m.Connection(Jf,J,pos2='end')
    m.Equation(J.dt() == ((A+E*(1-l))*h*Pa0-C*u+E*Pe0+shift)*d)
    
    # maximize U
    m.Maximize(Jf)
    
    # options
    m.options.IMODE = 6  # optimal control
    m.options.NODES = 3  # collocation nodes
    m.options.SOLVER = 3 # solver (IPOPT)
    
    # solve optimization problem
    m.solve()
    
    # print profit
    print('Optimal Profit: ' + str(Jf.value[0]))
    
1 Answers

For many of these cases, it can help to make a couple changes such as:

  • Reformulate to avoid m.log() with a negative. The Intermediate variable can also help.
# Objective (Utility)
J = m.Var(value=0)
rhs = m.Intermediate((A+E*(1-l))*h*Pa0-C*u+E*Pe0+shift)
m.Equation(m.exp(J.dt()/d)==rhs)
  • Initialize before optimizing. The APOPT solver does better on the initialization and IPOPT does better with the initialized solution from APOPT. Initialization strategies are discussed in the article: Safdarnejad, S.M., Hedengren, J.D., Lewis, N.R., Haseltine, E., Initialization Strategies for Optimization of Dynamic Systems, Computers and Chemical Engineering, 2015, Vol. 78, pp. 39-50, DOI: 10.1016/j.compchemeng.2015.04.016.
# solve optimization problem
m.options.NODES = 3  # collocation nodes
m.options.SOLVER = 1 # solver (APOPT)
m.options.IMODE=4
m.solve()

# solve optimization problem
m.options.TIME_SHIFT=0
m.options.SOLVER=3 # solver (IPOPT)
m.options.IMODE=6
m.solve()

Case 2: Successful Solutions with n=501

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

dat = {'A0': [23221, 2198, 4296, 104906, 691], \
       'h': [0.04, 0.25, 0.07, 0, 12.58],\
       'emax': [23221, 2198, 4296, 104906, 691] }
dftemp = pd.DataFrame(data=dat)
na=len(dftemp)

# time points
n=501 
year=50

# constants
Pa0 = 3.061 
Pe0 = 10.603 
C0 = 100 
r = 0.05 
k=50 
shift=10000000 # to make positive inside log function
ll=0.15

for i in range(0,na):
    # create GEKKO model
    m = GEKKO(remote=True)

    m.time = np.linspace(0,year,n)
    t=m.time
    
    A0=dftemp.loc[i][0]
    h=dftemp.loc[i][1]
    emax=dftemp.loc[i][2]    
    
    A = m.SV(value=A0, lb=0, ub=A0)
    E = m.SV(value=0, lb=0, ub=A0)

    u = m.MV(value=0, lb=-emax, ub=emax) 
    u.STATUS = 1

    t = m.Param(value=m.time)
    C = m.Var(value=C0)
    d = m.Var(value=1)
    l = m.Param(value=ll)
    
    # Equation
    m.Equation(A.dt()==-u)
    m.Equation(E.dt()==u)
    m.Equation(C.dt()==-C/k)
    m.Equation(d==m.exp(-t*r))
    # Objective (Utility)
    J = m.Var(value=0)
    rhs = m.Intermediate((A+E*(1-l))*h*Pa0-C*u+E*Pe0+shift)
    m.Equation(m.exp(J.dt()/d)==rhs)
        
    # Final objective
    final = np.zeros_like(m.time)
    final[-1] = 1
    final = m.Param(final)
    
    # maximize U
    m.Maximize(final*J)
        
    # solve optimization problem
    m.options.NODES = 3  # collocation nodes
    m.options.SOLVER = 1 # solver (APOPT)
    m.options.IMODE=4
    print('\n\nInitializing with APOPT')
    m.solve(disp=False)

    # solve optimization problem
    m.options.TIME_SHIFT=0
    m.options.SOLVER=3 # solver (IPOPT)
    m.options.IMODE=6
    m.solve()
        
    # print profit
    print('Optimal Profit: ' + str(J.value[-1]))

Please try this approach with the other cases as well. It is generally better to use m.sum() versus sum because of the way Gekko constructs the summation as a built-in object versus a long string.

Edit: Updated Solution Here is an updated solution with the correct initial conditions. The initial conditions from IMODE=4 aren't transferring over to IMODE=6. An alternative is to use IMODE=6 with COLDSTART=1 that is equivalent.

Results

from gekko import GEKKO
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

dat = {'A0': [23221, 2198, 4296, 104906, 691], \
       'h': [0.04, 0.25, 0.07, 0, 12.58],\
       'emax': [23221, 2198, 4296, 104906, 691] }
dftemp = pd.DataFrame(data=dat)
na=len(dftemp)

# time points
n=101 
year=50

# constants
Pa0 = 3.061 
Pe0 = 10.603 
C0 = 100 
r = 0.05 
k=50 
shift=10000000 # to make positive inside log function
ll=0.15

plt.figure(figsize=(10,5))
for i in range(0,na):
    # create GEKKO model
    m = GEKKO(remote=True)

    m.time = np.linspace(0,year,n)
    t=m.time
    
    A0=dftemp.loc[i][0]
    h=dftemp.loc[i][1]
    emax=dftemp.loc[i][2]    

    print('A (initial): ' + str(A0))
    A = m.Var(value=A0, lb=0, ub=A0)
    E = m.Var(value=0, lb=0, ub=A0)

    u = m.MV(value=0, lb=-emax, ub=emax) 
    u.STATUS = 1

    t = m.Param(value=m.time)
    C = m.Var(value=C0)
    d = m.Var(value=1)
    l = m.Param(value=ll)
    
    # Equation
    m.Equation(A.dt()==-u)
    m.Equation(E.dt()==u)
    m.Equation(C.dt()==-C/k)
    m.Equation(d==m.exp(-t*r))
    # Objective (Utility)
    J = m.Var(value=0)
    rhs = m.Intermediate((A+E*(1-l))*h*Pa0-C*u+E*Pe0+shift)
    m.Equation(m.exp(J.dt()/d)==rhs)
        
    # Final objective
    final = np.zeros_like(m.time)
    final[-1] = 1
    final = m.Param(final)
    
    # maximize U
    m.Maximize(final*J)
        
    # solve optimization problem
    m.options.NODES = 3  # collocation nodes
    m.options.SOLVER = 1 # solver (APOPT)
    m.options.IMODE=6
    m.options.COLDSTART=1
    print('\n\nInitializing with APOPT')
    m.solve(disp=False)

    # solve optimization problem
    m.options.COLDSTART=0
    m.options.TIME_SHIFT=0
    m.options.SOLVER=3 # solver (IPOPT)
    m.options.IMODE=6
    m.solve()
        
    # print profit
    print('Optimal Profit: ' + str(J.value[-1]))

    plt.plot(m.time,A.value,label='A case '+str(i))
    plt.plot(m.time,E.value,label='E case '+str(i))
    plt.plot(m.time,u.value,label='u case '+str(i))
    

plt.legend()
plt.show()
Related