Search code examples
pythonoptimizationgekko

Hydrogen Vehicle Refueling Model Optimization


I am currently in the process of trying to determine the optimal inflow conditions for the refueling process of a hydrogen (H2) vehicle using GEKKO. Below are the coupled, ordinary differential equations which govern how the temperature of H2 and the fuel tank wall change over the fueling time.

T.dt() = (1+alpha)*(T_star - T)/(t_star + t)
T_w.dt() = (T - T_w)/t_w_star

where

alpha = (a_in*A_in)/(c_v*m_dot_in), t_star = m_0/m_dot_in, t_w_star = (m_w*c_w)/(a_in*A_in)
T_star = gamma_p*T_inf + alpha_p*T_w, gamma_p = gamma/(1 + alpha), alpha_p = alpha/(1 + alpha)

Here, m_0 is the initial mass of H2 in the tank, m_dot_in is the mass flow rate of H2 into the tank, gamma is the ratio of the specific heats for H2, T_inf is the inflow temperature of H2, and the other variables are intermediate variables/tank parameters. Through the refueling process, m_dot_in is taken to be constant (but unknown), so the mass of H2 in the tank over time is defined as:

m = m_0 + m_dot_in*t

Additionally, the pressure of H2 within the tank may be calculated with a real gas equation of state (I use the Peng-Robinson equation of state for this model).

What I am trying to do with this model is determine the optimal m_dot_in, T_inf, and m_0 to minimize the total fueling time, t_f. Some constraints on the variables are that T<=358.15 K throughout the whole refueling process (for safety reasons), and that the final pressure of H2 within the tank must be 35 MPa. For this model, I consider t_f, m_dot_in, m_0, and T_inf to be fixed variables that have the following bounds:

60 sec <= t_f <= 300 sec
0.0005 kg/sec <= m_dot_in <= 0.03 kg/sec
5% of m_f <= m_0 <= 90% of m_f, where m_f = 1.79 kg
288.15 K <= T_inf <= 303.15 K

Below I have copied my code for this optimization problem using GEKKO:

# HYDROGEN TANK REFUELING MODEL
# OPTIMIZE MODEL WITH GEKKO OPTIMIZATION SUITE
from gekko import GEKKO

m = GEKKO()

# CONSTANTS
## TANK PARAMETERS (ASSUME TYPE III, ALUMINUM, 74 l, RATED FOR 35 MPa)
V = 0.074 # m^3
a_in = 167/19e-3 # W/m^2/K
c_w = 2730 # J/kg/K
rho_w = 900 # kg/m^3
m_w = rho_w*(np.pi*(((0.358+19e-3)/2)**2)*(0.893+19e-3) - np.pi*((0.358/2)**2)*0.893)
A_in = 2*np.pi*(0.358/2)*((0.358/2) + 0.893) # m^2
T_w0 = 293.15 # K
m_f = 1.79 # final mass of hydrogen in tank, kg
## HYDROGEN PARAMETERS
c_p = 14.615e3 # specific heat at constant pressure, J/kg/K
c_v = 10.316e3 # specific heat at constant volume, J/kg/K
gamma = c_p/c_v
R = 8.314/M_H2 # gas constant for H2, J/kgK
T_c = -240 + 273.15 # critical temperature for H2, K
p_c = 1.3e6 # critical pressure for H2, Pa
w_H2 = -0.219 # acentric factor for H2
a = 0.45724*(R**2 * T_c**2)/(p_c**2)
b = 0.0778*(R*T_c)/p_c
kappa = 0.37464 + 1.54226*w_H2 - 0.26992*(w_H2**2)

# SET TIME ANALYSIS POINTS
nt = 101
tm = np.linspace(0, 1, nt)
m.time = tm

# options
m.options.NODES = 6
m.options.SOLVER = 3
m.options.IMODE = 6
m.options.MAX_ITER = 500
m.options.MV_TYPE = 0
m.options.DIAGLEVEL = 0

# FIXED VARIABLES
t_f = m.FV(value=60.0,lb=60.0,ub=300.0) # final fuel time, s
t_f.STATUS = 1
m_dot_in = m.FV(value=0.001,lb=0.0005,ub=0.03) # mass flow rate into tank, kg/s
m_dot_in.STATUS = 1
m_0 = m.FV(value=0.1*m_f,lb=0.05*m_f,ub=0.9*m_f) # initial mass of H2 in tank (as % of m_f), kg
m_0.STATUS = 1
T_inf = m.FV(value=20 + 273.15,lb=15 + 273.15,ub=30 + 273.15) # inflow temperature, K
T_inf.STATUS = 1

# PARAMETERS
f = np.zeros(nt)
f[-1] = 1.0
final = m.Param(value=f)

# VARIABLES
T = m.Var(value=15+273.15,lb=15+273.15,ub=85+273.15)
T_w = m.Var(value=T_w0,lb=T_w0,ub=85+273.15)
mass = m.Var(value=m_0,lb=m_0,ub=m_f)
p = m.Var(value=1.0e6,lb=0.0,ub=35.0e6)

# INTERMEDIATES
alpha = m.Intermediate((a_in*A_in)/c_v/m_dot_in)
gamma_p = m.Intermediate(gamma/(1 + alpha))
alpha_p = m.Intermediate(alpha/(1 + alpha))
t_star = m.Intermediate(m_0/m_dot_in)
t_w_star = m.Intermediate((m_w*c_w)/(a_in*A_in))
T_star = m.Intermediate(gamma_p*T_inf + alpha_p*T_w)
alpha_T = m.Intermediate(1 + kappa*(1 - (T/T_c)**0.5))
v = m.Intermediate(V/mass) # specific volume, m^3/kg

# EQUATIONS
m.Equation(mass==t_f*(m_0 + m_dot_in*m.time))
m.Equation(T.dt()==t_f*(1 + alpha)*((T_star-T)/(t_star+tm)))
m.Equation(T_w.dt()==t_f*((T-T_w)/t_w_star))
m.Equation(p*1.0e6==t_f*((R*T/(v-b)) - ((a*alpha_T**2)/(v*(v+b) + b*(v-b))))) 
m.Equation(T*final<=85+273.15)
m.Equation(T_w*final<=85+273.15)

# SPECIFIY ENDPOINT CONDITIONS
m.fix(mass, pos=len(m.time)-1, val=m_f)
m.fix(p, pos=len(m.time)-1, val=35.0e6)

# MINIMIZE FINAL FUEL TIME
m.Obj(t_f)

# SOLVE
m.solve()

# RESULTS
print('Final Time: ' + str(t_f.value[0]))

This code currently gives me the following error:

apm 45.3.69.90_gk_model46 <br><pre> ----------------------------------------------------------------
 APMonitor, Version 1.0.1
 APMonitor Optimization Suite
 ----------------------------------------------------------------
 
 @error: Equation Definition
 Equation without an equality (=) or inequality (>,<)
 0.140.150.160.170.180.190.20.210.220.230.240.250.260.27
 STOPPING...
---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
<ipython-input-102-4d40bf2f7c9c> in <module>
     87 
     88 # SOLVE
---> 89 m.solve()
     90 
     91 # RESULTS

~\anaconda3\lib\site-packages\gekko\gekko.py in solve(self, disp, debug, GUI, **kwargs)
   2172             #print APM error message and die
   2173             if (debug >= 1) and ('@error' in response):
-> 2174                 raise Exception(response)
   2175 
   2176             #load results

Exception:  @error: Equation Definition
 Equation without an equality (=) or inequality (>,<)
 0.140.150.160.170.180.190.20.210.220.230.240.250.260.27
 STOPPING...

I am very new to optimization in general, and I tried including several different equality and inequality constraints, but nothing seems to work. I thought I was doing it correctly based off example problems and information from the APMonitor website, but obviously something is off with my implementation. I was wondering if someone knew what I should change/add or if I am doing something completely wrong? Any help would be much appreciated!

Thank you for your time,

Evan

EDIT: Based on Dr. Hedengren's answer, I tried to simplifying the model such that the variables of mass and p were not included, as they only depend on the final values for t_f, m_dot_in, and T and may be calculated after the solution has been obtained. Below is my edited code:

# HYDROGEN TANK REFUELING MODEL
# OPTIMIZE MODEL WITH GEKKO OPTIMIZATION SUITE
from gekko import GEKKO
import numpy as np

m = GEKKO(remote=False)

# CONSTANTS
## TANK PARAMETERS (ASSUME TYPE III, ALUMINUM, 74 l, RATED FOR 35 MPa)
V = 0.074 # m^3
a_in = 167/19e-3 # W/m^2/K
c_w = 2730 # J/kg/K
rho_w = 900 # kg/m^3
m_w = rho_w*(np.pi*(((0.358+19e-3)/2)**2)*(0.893+19e-3) - np.pi*((0.358/2)**2)*0.893)
A_in = 2*np.pi*(0.358/2)*((0.358/2) + 0.893) # m^2
T_w0 = 293.15 # K
m_f = 1.79 # final mass of hydrogen in tank, kg
## HYDROGEN PARAMETERS
c_p = 14.615e3 # specific heat at constant pressure, J/kg/K
c_v = 10.316e3 # specific heat at constant volume, J/kg/K
gamma = c_p/c_v
M_H2 = 2.02
R = 8.314/M_H2 # gas constant for H2, J/kgK
T_c = -240 + 273.15 # critical temperature for H2, K
p_c = 1.3e6 # critical pressure for H2, Pa
w_H2 = -0.219 # acentric factor for H2
a = 0.45724*(R**2 * T_c**2)/(p_c**2)
b = 0.0778*(R*T_c)/p_c
kappa = 0.37464 + 1.54226*w_H2 - 0.26992*(w_H2**2)
## SET INFLOW TEMPERATURE AND INITIAL MASS IN TANK
m_0 = 0.1*m_f
T_inf = 20 + 273.15

# SET TIME ANALYSIS POINTS
nt = 101
tm = np.linspace(0, 1, nt)
m.time = tm
t = m.Param(tm, name='time')

# options
m.options.NODES = 6
m.options.SOLVER = 3
m.options.IMODE = 6
m.options.MAX_ITER = 500
m.options.MV_TYPE = 0
m.options.DIAGLEVEL = 0

# FIXED VARIABLES
t_f = m.FV(value=60.0,lb=60.0,ub=300.0) # final fuel time, s
t_f.STATUS = 0
m_dot_in = m.FV(value=0.001,lb=0.0005,ub=0.03) # mass flow rate into tank, kg/s
m_dot_in.STATUS = 0
# m_0 = m.FV(value=0.1*m_f,lb=0.05*m_f,ub=0.9*m_f) # initial mass of H2 in tank (as % of m_f), kg
# m_0.STATUS = 0
# T_inf = m.FV(value=20 + 273.15,lb=15 + 273.15,ub=30 + 273.15) # inflow temperature, K
# T_inf.STATUS = 0

# PARAMETERS
f = np.zeros(nt)
f[-1] = 1.0
final = m.Param(value=f, name='final')

# VARIABLES
T = m.Var(value=15+273.15,lb=15+273.15,ub=85+273.15, name='H2 Temp')
T_w = m.Var(value=T_w0,lb=T_w0,ub=85+273.15, name='Wall Temp')
# mass = m.Var(value=m_0,lb=m_0,ub=m_f, name='H2 Mass')
# p = m.Var(value=1.0e6,lb=0.0,ub=35.0e6, name='H2 Press')

# INTERMEDIATES
alpha = m.Intermediate((a_in*A_in)/c_v/m_dot_in, name='alpha')
gamma_p = m.Intermediate(gamma/(1 + alpha), name='gamma_p')
alpha_p = m.Intermediate(alpha/(1 + alpha), name='alpha_p')
t_star = m.Intermediate(m_0/m_dot_in, name='t_star')
t_w_star = m.Intermediate((m_w*c_w)/(a_in*A_in), name='t_w_star')
T_star = m.Intermediate(gamma_p*T_inf + alpha_p*T_w, name='Temp_star')
# alpha_T = m.Intermediate(1 + kappa*(1 - (T/T_c)**0.5))
# v = m.Intermediate(V/mass) # specific volume, m^3/kg

# EQUATIONS
# m.Equation(mass==t_f*(m_0 + m_dot_in*t*t_f))
m.Equation(T.dt()==t_f*(1 + alpha)*((T_star-T)/(t_star+t*t_f)))
m.Equation(T_w.dt()==t_f*((T-T_w)/t_w_star))
# m.Equation(p==t_f*((R*T/(v-b)) - ((a*alpha_T**2)/(v*(v+b) + b*(v-b))))) 

# m.Equation((T-(85+273.15))*final<=0)
# m.Equation((T_w-(85+273.15))*final<=0)

# SPECIFIY ENDPOINT CONDITIONS
# m.Minimize(final*(mass-m_f)**2)
# m.Minimize(final*(p-35.0e6)**2)
m.Minimize(final*(T-351)**2)

#m.fix(mass, pos=len(m.time)-1, val=m_f)
#m.fix(p, pos=len(m.time)-1, val=35.0e6)

# MINIMIZE FINAL FUEL TIME
m.Minimize(t_f)

# SOLVE
m.options.SOLVER = 3
m.open_folder()
m.solve()

# RESULTS
print('Final Time: ' + str(t_f.value[0]))

I am still getting infeasibilities (not as many as before), but I am having trouble understanding what said infeasibilities mean and how to go about fixing them. Below are the infeasibilities I am getting:

************************************************
***** POSSIBLE INFEASBILE EQUATIONS ************
************************************************
____________________________________________________________________________
EQ Number   Lower        Residual     Upper        Infeas.     Name
         1   0.0000E+00  -7.5600E-04   0.0000E+00   7.5600E-04  p(1).n(2).Eqn(1): 0 = $h2_temp-(((((p2)*((1+alpha))))*((((temp_star-h2_temp))/((t_star+((time)*(p2))))))))
 Variable   Lower        Value        Upper        $Value      Name
         0  -1.2346E+20   1.0000E+00   1.2346E+20   0.0000E+00  p(1).n(2).time
         0   6.0000E+01   6.0000E+01   3.0000E+02   0.0000E+00  p(1).n(1).p2
         0   5.0000E-04   1.0000E-03   3.0000E-02   0.0000E+00  p(1).n(1).p3
         1   2.8815E+02   2.8949E+02   3.5815E+02   9.7624E+02  p(1).n(2).h2_temp
         2   2.9315E+02   2.9315E+02   3.5815E+02  -7.9554E+01  p(1).n(2).wall_temp
         1   2.8815E+02   2.8949E+02   3.5815E+02   9.7624E+02  p(1).n(2).h2_temp
____________________________________________________________________________
EQ Number   Lower        Residual     Upper        Infeas.     Name
         5   0.0000E+00  -7.5600E-04   0.0000E+00   7.5600E-04  p(1).n(3).Eqn(1): 0 = $h2_temp-(((((p2)*((1+alpha))))*((((temp_star-h2_temp))/((t_star+((time)*(p2))))))))
 Variable   Lower        Value        Upper        $Value      Name
         0  -1.2346E+20   1.0000E+00   1.2346E+20   0.0000E+00  p(1).n(3).time
         0   6.0000E+01   6.0000E+01   3.0000E+02   0.0000E+00  p(1).n(1).p2
         0   5.0000E-04   1.0000E-03   3.0000E-02   0.0000E+00  p(1).n(1).p3
         3   2.8815E+02   2.9123E+02   3.5815E+02   5.2535E+02  p(1).n(3).h2_temp
         4   2.9315E+02   2.9315E+02   3.5815E+02  -4.1620E+01  p(1).n(3).wall_temp
         3   2.8815E+02   2.9123E+02   3.5815E+02   5.2535E+02  p(1).n(3).h2_temp
____________________________________________________________________________
EQ Number   Lower        Residual     Upper        Infeas.     Name
         9   0.0000E+00  -7.5600E-04   0.0000E+00   7.5600E-04  p(1).n(4).Eqn(1): 0 = $h2_temp-(((((p2)*((1+alpha))))*((((temp_star-h2_temp))/((t_star+((time)*(p2))))))))
 Variable   Lower        Value        Upper        $Value      Name
         0  -1.2346E+20   1.0000E+00   1.2346E+20   0.0000E+00  p(1).n(4).time
         0   6.0000E+01   6.0000E+01   3.0000E+02   0.0000E+00  p(1).n(1).p2
         0   5.0000E-04   1.0000E-03   3.0000E-02   0.0000E+00  p(1).n(1).p3
         5   2.8815E+02   2.9229E+02   3.5815E+02   2.5164E+02  p(1).n(4).h2_temp
         6   2.9315E+02   2.9315E+02   3.5815E+02  -1.8591E+01  p(1).n(4).wall_temp
         5   2.8815E+02   2.9229E+02   3.5815E+02   2.5164E+02  p(1).n(4).h2_temp
____________________________________________________________________________
EQ Number   Lower        Residual     Upper        Infeas.     Name
        13   0.0000E+00  -7.5600E-04   0.0000E+00   7.5600E-04  p(1).n(5).Eqn(1): 0 = $h2_temp-(((((p2)*((1+alpha))))*((((temp_star-h2_temp))/((t_star+((time)*(p2))))))))
 Variable   Lower        Value        Upper        $Value      Name
         0  -1.2346E+20   1.0000E+00   1.2346E+20   0.0000E+00  p(1).n(5).time
         0   6.0000E+01   6.0000E+01   3.0000E+02   0.0000E+00  p(1).n(1).p2
         0   5.0000E-04   1.0000E-03   3.0000E-02   0.0000E+00  p(1).n(1).p3
         7   2.8815E+02   2.9274E+02   3.5815E+02   1.3550E+02  p(1).n(5).h2_temp
         8   2.9315E+02   2.9315E+02   3.5815E+02  -8.8200E+00  p(1).n(5).wall_temp
         7   2.8815E+02   2.9274E+02   3.5815E+02   1.3550E+02  p(1).n(5).h2_temp
____________________________________________________________________________
EQ Number   Lower        Residual     Upper        Infeas.     Name
        25   0.0000E+00  -7.5600E-04   0.0000E+00   7.5600E-04  p(2).n(3).Eqn(1): 0 = $h2_temp-(((((p2)*((1+alpha))))*((((temp_star-h2_temp))/((t_star+((time)*(p2))))))))
 Variable   Lower        Value        Upper        $Value      Name
         0  -1.2346E+20   1.0000E+00   1.2346E+20   0.0000E+00  p(2).n(3).time
         0   6.0000E+01   6.0000E+01   3.0000E+02   0.0000E+00  p(1).n(1).p2
         0   5.0000E-04   1.0000E-03   3.0000E-02   0.0000E+00  p(1).n(1).p3
        13   2.8815E+02   2.9312E+02   3.5815E+02   3.9285E+01  p(2).n(3).h2_temp
        14   2.9315E+02   2.9315E+02   3.5815E+02  -7.2493E-01  p(2).n(3).wall_temp
        13   2.8815E+02   2.9312E+02   3.5815E+02   3.9285E+01  p(2).n(3).h2_temp
____________________________________________________________________________
EQ Number   Lower        Residual     Upper        Infeas.     Name
        29   0.0000E+00  -7.5598E-04   0.0000E+00   7.5598E-04  p(2).n(4).Eqn(1): 0 = $h2_temp-(((((p2)*((1+alpha))))*((((temp_star-h2_temp))/((t_star+((time)*(p2))))))))
 Variable   Lower        Value        Upper        $Value      Name
         0  -1.2346E+20   1.0000E+00   1.2346E+20   0.0000E+00  p(2).n(4).time
         0   6.0000E+01   6.0000E+01   3.0000E+02   0.0000E+00  p(1).n(1).p2
         0   5.0000E-04   1.0000E-03   3.0000E-02   0.0000E+00  p(1).n(1).p3
        15   2.8815E+02   2.9320E+02   3.5815E+02   1.8882E+01  p(2).n(4).h2_temp
        16   2.9315E+02   2.9315E+02   3.5815E+02   9.9172E-01  p(2).n(4).wall_temp
        15   2.8815E+02   2.9320E+02   3.5815E+02   1.8882E+01  p(2).n(4).h2_temp
____________________________________________________________________________
EQ Number   Lower        Residual     Upper        Infeas.     Name
      2006   0.0000E+00  -1.0946E-01   0.0000E+00   1.0946E-01  p(1).c(2).t(2): not available
 Variable   Lower        Value        Upper        $Value      Name
         2   2.9315E+02   2.9315E+02   3.5815E+02  -7.9554E+01  p(1).n(2).wall_temp
         4   2.9315E+02   2.9315E+02   3.5815E+02  -4.1620E+01  p(1).n(3).wall_temp
         6   2.9315E+02   2.9315E+02   3.5815E+02  -1.8591E+01  p(1).n(4).wall_temp
         8   2.9315E+02   2.9315E+02   3.5815E+02  -8.8200E+00  p(1).n(5).wall_temp
        10   2.9315E+02   2.9316E+02   3.5815E+02  -6.0293E+00  p(1).n(6).wall_temp
         2   2.9315E+02   2.9315E+02   3.5815E+02  -7.9554E+01  p(1).n(2).wall_temp
         0   2.9315E+02   2.9315E+02   3.5815E+02   0.0000E+00  p(1).n(1).wall_temp
____________________________________________________________________________
EQ Number   Lower        Residual     Upper        Infeas.     Name
      2007   0.0000E+00  -2.5022E-01   0.0000E+00   2.5022E-01  p(1).c(2).t(3): not available
 Variable   Lower        Value        Upper        $Value      Name
         2   2.9315E+02   2.9315E+02   3.5815E+02  -7.9554E+01  p(1).n(2).wall_temp
         4   2.9315E+02   2.9315E+02   3.5815E+02  -4.1620E+01  p(1).n(3).wall_temp
         6   2.9315E+02   2.9315E+02   3.5815E+02  -1.8591E+01  p(1).n(4).wall_temp
         8   2.9315E+02   2.9315E+02   3.5815E+02  -8.8200E+00  p(1).n(5).wall_temp
        10   2.9315E+02   2.9316E+02   3.5815E+02  -6.0293E+00  p(1).n(6).wall_temp
         4   2.9315E+02   2.9315E+02   3.5815E+02  -4.1620E+01  p(1).n(3).wall_temp
         0   2.9315E+02   2.9315E+02   3.5815E+02   0.0000E+00  p(1).n(1).wall_temp
____________________________________________________________________________
EQ Number   Lower        Residual     Upper        Infeas.     Name
      2008   0.0000E+00  -3.3207E-01   0.0000E+00   3.3207E-01  p(1).c(2).t(4): not available
 Variable   Lower        Value        Upper        $Value      Name
         2   2.9315E+02   2.9315E+02   3.5815E+02  -7.9554E+01  p(1).n(2).wall_temp
         4   2.9315E+02   2.9315E+02   3.5815E+02  -4.1620E+01  p(1).n(3).wall_temp
         6   2.9315E+02   2.9315E+02   3.5815E+02  -1.8591E+01  p(1).n(4).wall_temp
         8   2.9315E+02   2.9315E+02   3.5815E+02  -8.8200E+00  p(1).n(5).wall_temp
        10   2.9315E+02   2.9316E+02   3.5815E+02  -6.0293E+00  p(1).n(6).wall_temp
         6   2.9315E+02   2.9315E+02   3.5815E+02  -1.8591E+01  p(1).n(4).wall_temp
         0   2.9315E+02   2.9315E+02   3.5815E+02   0.0000E+00  p(1).n(1).wall_temp
____________________________________________________________________________
EQ Number   Lower        Residual     Upper        Infeas.     Name
      2009   0.0000E+00  -3.6373E-01   0.0000E+00   3.6373E-01  p(1).c(2).t(5): not available
 Variable   Lower        Value        Upper        $Value      Name
         2   2.9315E+02   2.9315E+02   3.5815E+02  -7.9554E+01  p(1).n(2).wall_temp
         4   2.9315E+02   2.9315E+02   3.5815E+02  -4.1620E+01  p(1).n(3).wall_temp
         6   2.9315E+02   2.9315E+02   3.5815E+02  -1.8591E+01  p(1).n(4).wall_temp
         8   2.9315E+02   2.9315E+02   3.5815E+02  -8.8200E+00  p(1).n(5).wall_temp
        10   2.9315E+02   2.9316E+02   3.5815E+02  -6.0293E+00  p(1).n(6).wall_temp
         8   2.9315E+02   2.9315E+02   3.5815E+02  -8.8200E+00  p(1).n(5).wall_temp
         0   2.9315E+02   2.9315E+02   3.5815E+02   0.0000E+00  p(1).n(1).wall_temp
____________________________________________________________________________
EQ Number   Lower        Residual     Upper        Infeas.     Name
      2010   0.0000E+00  -3.8212E-01   0.0000E+00   3.8212E-01  p(1).c(2).t(6): not available
 Variable   Lower        Value        Upper        $Value      Name
         2   2.9315E+02   2.9315E+02   3.5815E+02  -7.9554E+01  p(1).n(2).wall_temp
         4   2.9315E+02   2.9315E+02   3.5815E+02  -4.1620E+01  p(1).n(3).wall_temp
         6   2.9315E+02   2.9315E+02   3.5815E+02  -1.8591E+01  p(1).n(4).wall_temp
         8   2.9315E+02   2.9315E+02   3.5815E+02  -8.8200E+00  p(1).n(5).wall_temp
        10   2.9315E+02   2.9316E+02   3.5815E+02  -6.0293E+00  p(1).n(6).wall_temp
        10   2.9315E+02   2.9316E+02   3.5815E+02  -6.0293E+00  p(1).n(6).wall_temp
         0   2.9315E+02   2.9315E+02   3.5815E+02   0.0000E+00  p(1).n(1).wall_temp
____________________________________________________________________________
EQ Number   Lower        Residual     Upper        Infeas.     Name
      2017   0.0000E+00  -7.1275E-04   0.0000E+00   7.1275E-04  p(2).c(2).t(3): not available
 Variable   Lower        Value        Upper        $Value      Name
        12   2.9315E+02   2.9315E+02   3.5815E+02  -3.6833E+00  p(2).n(2).wall_temp
        14   2.9315E+02   2.9315E+02   3.5815E+02  -7.2493E-01  p(2).n(3).wall_temp
        16   2.9315E+02   2.9315E+02   3.5815E+02   9.9172E-01  p(2).n(4).wall_temp
        18   2.9315E+02   2.9315E+02   3.5815E+02   1.6707E+00  p(2).n(5).wall_temp
        20   2.9315E+02   2.9316E+02   3.5815E+02   1.8694E+00  p(2).n(6).wall_temp
        14   2.9315E+02   2.9315E+02   3.5815E+02  -7.2493E-01  p(2).n(3).wall_temp
        10   2.9315E+02   2.9316E+02   3.5815E+02  -6.0293E+00  p(1).n(6).wall_temp
************************************************

Also, this took around 2 minutes to run, so if there is any advice on how to decrease the computation time, that would be much appreciated!


Solution

  • You can see the model that Gekko writes with m.open_folder() and then open the model gk_model0.apm with a text editor:

    Model
    Parameters
        p1 = 60.0, <= 300.0, >= 60.0
        p2 = 0.001, <= 0.03, >= 0.0005
        p3 = 0.17900000000000002, <= 1.611, >= 0.08950000000000001
        p4 = 293.15, <= 303.15, >= 288.15
        p5
    End Parameters
    Variables
        v1 = 288.15, <= 358.15, >= 288.15
        v2 = 293.15, <= 358.15, >= 293.15
        v3 = 0.17900000000000002, <= 1.79, >= p3
        v4 = 1000000.0, <= 35000000.0, >= 0.0
    End Variables
    Intermediates
        i0=(1.0272572651140832/p2)
        i1=(1.416731291198139/(1+i0))
        i2=((i0)/((1+i0)))
        i3=((p3)/(p2))
        i4=2.762640041099948
        i5=(((i1)*(p4))+((i2)*(v2)))
        i6=(1+((0.02393942687999997)*((1-((((v1)/(33.14999999999998)))^(0.5))))))
        i7=(0.074/v3)
    End Intermediates
    Equations
        v3=((p1)*((p3+((p2)*([0.   0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.1  0.11 0.12 0.13
     0.14 0.15 0.16 0.17 0.18 0.19 0.2  0.21 0.22 0.23 0.24 0.25 0.26 0.27
     0.28 0.29 0.3  0.31 0.32 0.33 0.34 0.35 0.36 0.37 0.38 0.39 0.4  0.41
     0.42 0.43 0.44 0.45 0.46 0.47 0.48 0.49 0.5  0.51 0.52 0.53 0.54 0.55
     0.56 0.57 0.58 0.59 0.6  0.61 0.62 0.63 0.64 0.65 0.66 0.67 0.68 0.69
     0.7  0.71 0.72 0.73 0.74 0.75 0.76 0.77 0.78 0.79 0.8  0.81 0.82 0.83
     0.84 0.85 0.86 0.87 0.88 0.89 0.9  0.91 0.92 0.93 0.94 0.95 0.96 0.97
     0.98 0.99 1.  ])))))
        $v1=((((p1)*((1+i0))))*((((i5-v1))/((i3+[0.   0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.1  0.11 0.12 0.13
     0.14 0.15 0.16 0.17 0.18 0.19 0.2  0.21 0.22 0.23 0.24 0.25 0.26 0.27
     0.28 0.29 0.3  0.31 0.32 0.33 0.34 0.35 0.36 0.37 0.38 0.39 0.4  0.41
     0.42 0.43 0.44 0.45 0.46 0.47 0.48 0.49 0.5  0.51 0.52 0.53 0.54 0.55
     0.56 0.57 0.58 0.59 0.6  0.61 0.62 0.63 0.64 0.65 0.66 0.67 0.68 0.69
     0.7  0.71 0.72 0.73 0.74 0.75 0.76 0.77 0.78 0.79 0.8  0.81 0.82 0.83
     0.84 0.85 0.86 0.87 0.88 0.89 0.9  0.91 0.92 0.93 0.94 0.95 0.96 0.97
     0.98 0.99 1.  ])))))
        $v2=((p1)*((((v1-v2))/(i4))))
        ((v4)*(1000000.0))=((p1)*((((((4.1158415841584155)*(v1)))/((i7-8.165418118811874e-06)))-((((5.036651227998414e-09)*(((i6)^(2)))))/((((i7)*((i7+8.165418118811874e-06)))+((8.165418118811874e-06)*((i7-8.165418118811874e-06)))))))))
        ((v1)*(p5))<=358.15
        ((v2)*(p5))<=358.15
        minimize p1
    End Equations
    Connections
        p(100).n(end).v3=1.79
        p(100).n(end).v3=fixed
        p(100).n(end).v4=35000000.0
        p(100).n(end).v4=fixed
    End Connections
    
    End Model
    

    The problem is with the first two equation that have m.time and tm as Numpy arrays instead of using a Gekko variable or parameter. If a Numpy array or Python list is is needed in the optimization problem then create a new m.Param() such as:

    t = m.Param(tm)
    m.Equation(mass==t_f*(m_0 + m_dot_in*t))
    m.Equation(T.dt()==t_f*(1 + alpha)*((T_star-T)/(t_star+t)))
    

    Because the final time is minimized, the time in those equations may need to be t*t_f.

    Equations such as m.Equation(T_w*final<=85+273.15) should be reformulated as m.Equation((T_w-(85+273.15))*final<=0) so that when final=0 then it is 0<=0. In this case, your original equations are okay but it is good practice to put all terms on one side of the equation.

    Even with these modifications there is still Exception: @error: Solution Not Found. The problem may be with the terminal constraint. One way to get a feasible solution is to "soften" the constraint by including it as an objective.

    m.Minimize(final*(mass-m_f)**2)
    m.Minimize(final*(p-35.0e6)**2)
    

    There is still a message that the problem is not feasible. You may want to continue to simplify your problem by turning off degrees of freedom (STATUS=0) and remove inequality constraints just to see if there is a problem with one of the equations such as divide-by-zero.

    # HYDROGEN TANK REFUELING MODEL
    # OPTIMIZE MODEL WITH GEKKO OPTIMIZATION SUITE
    from gekko import GEKKO
    import numpy as np
    
    m = GEKKO(remote=False)
    
    M_H2 = 2.02
    
    # CONSTANTS
    ## TANK PARAMETERS (ASSUME TYPE III, ALUMINUM, 74 l, RATED FOR 35 MPa)
    V = 0.074 # m^3
    a_in = 167/19e-3 # W/m^2/K
    c_w = 2730 # J/kg/K
    rho_w = 900 # kg/m^3
    m_w = rho_w*(np.pi*(((0.358+19e-3)/2)**2)*(0.893+19e-3) - np.pi*((0.358/2)**2)*0.893)
    A_in = 2*np.pi*(0.358/2)*((0.358/2) + 0.893) # m^2
    T_w0 = 293.15 # K
    m_f = 1.79 # final mass of hydrogen in tank, kg
    ## HYDROGEN PARAMETERS
    c_p = 14.615e3 # specific heat at constant pressure, J/kg/K
    c_v = 10.316e3 # specific heat at constant volume, J/kg/K
    gamma = c_p/c_v
    R = 8.314/M_H2 # gas constant for H2, J/kgK
    T_c = -240 + 273.15 # critical temperature for H2, K
    p_c = 1.3e6 # critical pressure for H2, Pa
    w_H2 = -0.219 # acentric factor for H2
    a = 0.45724*(R**2 * T_c**2)/(p_c**2)
    b = 0.0778*(R*T_c)/p_c
    kappa = 0.37464 + 1.54226*w_H2 - 0.26992*(w_H2**2)
    
    # SET TIME ANALYSIS POINTS
    nt = 101
    tm = np.linspace(0, 1, nt)
    m.time = tm
    t = m.Param(tm)
    
    # options
    m.options.NODES = 6
    m.options.SOLVER = 3
    m.options.IMODE = 6
    m.options.MAX_ITER = 500
    m.options.MV_TYPE = 0
    m.options.DIAGLEVEL = 0
    
    # FIXED VARIABLES
    t_f = m.FV(value=60.0,lb=60.0,ub=300.0) # final fuel time, s
    t_f.STATUS = 0
    m_dot_in = m.FV(value=0.001,lb=0.0005,ub=0.03) # mass flow rate into tank, kg/s
    m_dot_in.STATUS = 1
    m_0 = m.FV(value=0.1*m_f,lb=0.05*m_f,ub=0.9*m_f) # initial mass of H2 in tank (as % of m_f), kg
    m_0.STATUS = 1
    T_inf = m.FV(value=20 + 273.15,lb=15 + 273.15,ub=30 + 273.15) # inflow temperature, K
    T_inf.STATUS = 1
    
    # PARAMETERS
    f = np.zeros(nt)
    f[-1] = 1.0
    final = m.Param(value=f)
    
    # VARIABLES
    T = m.Var(value=15+273.15,lb=15+273.15,ub=85+273.15)
    T_w = m.Var(value=T_w0,lb=T_w0,ub=85+273.15)
    mass = m.Var(value=m_0,lb=m_0,ub=m_f)
    p = m.Var(value=1.0e6,lb=0.0,ub=35.0e6)
    
    # INTERMEDIATES
    alpha = m.Intermediate((a_in*A_in)/c_v/m_dot_in)
    gamma_p = m.Intermediate(gamma/(1 + alpha))
    alpha_p = m.Intermediate(alpha/(1 + alpha))
    t_star = m.Intermediate(m_0/m_dot_in)
    t_w_star = m.Intermediate((m_w*c_w)/(a_in*A_in))
    T_star = m.Intermediate(gamma_p*T_inf + alpha_p*T_w)
    alpha_T = m.Intermediate(1 + kappa*(1 - (T/T_c)**0.5))
    v = m.Intermediate(V/mass) # specific volume, m^3/kg
    
    # EQUATIONS
    m.Equation(mass==t_f*(m_0 + m_dot_in*t))
    m.Equation(T.dt()==t_f*(1 + alpha)*((T_star-T)/(t_star+t)))
    m.Equation(T_w.dt()==t_f*((T-T_w)/t_w_star))
    m.Equation(p*1.0e6==t_f*((R*T/(v-b)) - ((a*alpha_T**2)/(v*(v+b) + b*(v-b))))) 
    
    m.Equation((T-(85+273.15))*final<=0)
    m.Equation((T_w-(85+273.15))*final<=0)
    
    # SPECIFIY ENDPOINT CONDITIONS
    m.Minimize(final*(mass-m_f)**2)
    m.Minimize(final*(p-35.0e6)**2)
    
    #m.fix(mass, pos=len(m.time)-1, val=m_f)
    #m.fix(p, pos=len(m.time)-1, val=35.0e6)
    
    # MINIMIZE FINAL FUEL TIME
    m.Minimize(t_f)
    
    # SOLVE
    m.options.SOLVER = 3
    m.solve()
    
    # RESULTS
    print('Final Time: ' + str(t_f.value[0]))
    

    Response to edit

    The infeasibility reveals that wall_temp is a culprit from the first block. The solver is trying to push that value lower but it is at a bound. There are other parameters (variable 0) in the equation but wall_temp is the only one that is a variable that is at the lower bound. I made a modification to create a deadband to penalize any deviation outside of the upper (SPHI) and lower (SPLO) bounds. This way, the solution can still remain feasible if the constraints cannot be satisfied. The weights (WSPHI / WSPLO) can be increased if needed. Here is additional information on tuning.

    # HYDROGEN TANK REFUELING MODEL
    # OPTIMIZE MODEL WITH GEKKO OPTIMIZATION SUITE
    from gekko import GEKKO
    import numpy as np
    
    m = GEKKO(remote=False)
    
    # CONSTANTS
    ## TANK PARAMETERS (ASSUME TYPE III, ALUMINUM, 74 l, RATED FOR 35 MPa)
    V = 0.074 # m^3
    a_in = 167/19e-3 # W/m^2/K
    c_w = 2730 # J/kg/K
    rho_w = 900 # kg/m^3
    m_w = rho_w*(np.pi*(((0.358+19e-3)/2)**2)*(0.893+19e-3) - np.pi*((0.358/2)**2)*0.893)
    A_in = 2*np.pi*(0.358/2)*((0.358/2) + 0.893) # m^2
    T_w0 = 293.15 # K
    m_f = 1.79 # final mass of hydrogen in tank, kg
    ## HYDROGEN PARAMETERS
    c_p = 14.615e3 # specific heat at constant pressure, J/kg/K
    c_v = 10.316e3 # specific heat at constant volume, J/kg/K
    gamma = c_p/c_v
    M_H2 = 2.02
    R = 8.314/M_H2 # gas constant for H2, J/kgK
    T_c = -240 + 273.15 # critical temperature for H2, K
    p_c = 1.3e6 # critical pressure for H2, Pa
    w_H2 = -0.219 # acentric factor for H2
    a = 0.45724*(R**2 * T_c**2)/(p_c**2)
    b = 0.0778*(R*T_c)/p_c
    kappa = 0.37464 + 1.54226*w_H2 - 0.26992*(w_H2**2)
    ## SET INFLOW TEMPERATURE AND INITIAL MASS IN TANK
    m_0 = 0.1*m_f
    T_inf = 20 + 273.15
    
    # SET TIME ANALYSIS POINTS
    nt = 101
    tm = np.linspace(0, 1, nt)
    m.time = tm
    t = m.Param(tm, name='time')
    
    # options
    m.options.NODES = 6
    m.options.SOLVER = 3
    m.options.IMODE = 6
    m.options.MAX_ITER = 500
    m.options.MV_TYPE = 0
    m.options.DIAGLEVEL = 0
    
    # FIXED VARIABLES
    t_f = m.FV(value=60.0,lb=60.0,ub=300.0) # final fuel time, s
    t_f.STATUS = 1
    m_dot_in = m.FV(value=0.001,lb=0.0005,ub=0.03) # mass flow rate into tank, kg/s
    m_dot_in.STATUS = 1
    # m_0 = m.FV(value=0.1*m_f,lb=0.05*m_f,ub=0.9*m_f) # initial mass of H2 in tank (as % of m_f), kg
    # m_0.STATUS = 0
    # T_inf = m.FV(value=20 + 273.15,lb=15 + 273.15,ub=30 + 273.15) # inflow temperature, K
    # T_inf.STATUS = 0
    
    # PARAMETERS
    f = np.zeros(nt)
    f[-1] = 1.0
    final = m.Param(value=f, name='final')
    
    # VARIABLES
    T = m.CV(value=15+273.15,name='H2 Temp')
    T.SPLO=15+273.15
    T.SPHI=85+273.15
    T.WSPLO = 100
    T.WSPHI = 100
    T.TR_INIT = 0
    T.STATUS = 1
    
    T_w = m.CV(value=T_w0,name='Wall Temp')
    T_w.SPLO=T_w0
    T_w.SPHI=85+273.15
    T_w.WSPLO = 100
    T_w.WSPHI = 100
    T_w.TR_INIT = 0
    T_w.STATUS = 1
    
    # INTERMEDIATES
    alpha = m.Intermediate((a_in*A_in)/c_v/m_dot_in, name='alpha')
    gamma_p = m.Intermediate(gamma/(1 + alpha), name='gamma_p')
    alpha_p = m.Intermediate(alpha/(1 + alpha), name='alpha_p')
    t_star = m.Intermediate(m_0/m_dot_in, name='t_star')
    t_w_star = m.Intermediate((m_w*c_w)/(a_in*A_in), name='t_w_star')
    T_star = m.Intermediate(gamma_p*T_inf + alpha_p*T_w, name='Temp_star')
    # alpha_T = m.Intermediate(1 + kappa*(1 - (T/T_c)**0.5))
    # v = m.Intermediate(V/mass) # specific volume, m^3/kg
    
    # EQUATIONS
    # m.Equation(mass==t_f*(m_0 + m_dot_in*t*t_f))
    m.Equation(T.dt()==t_f*(1 + alpha)*((T_star-T)/(t_star+t*t_f)))
    m.Equation(T_w.dt()==t_f*((T-T_w)/t_w_star))
    # m.Equation(p==t_f*((R*T/(v-b)) - ((a*alpha_T**2)/(v*(v+b) + b*(v-b))))) 
    
    # m.Equation((T-(85+273.15))*final<=0)
    # m.Equation((T_w-(85+273.15))*final<=0)
    
    # SPECIFIY ENDPOINT CONDITIONS
    # m.Minimize(final*(mass-m_f)**2)
    # m.Minimize(final*(p-35.0e6)**2)
    m.Minimize(final*(T-351)**2)
    
    #m.fix(mass, pos=len(m.time)-1, val=m_f)
    #m.fix(p, pos=len(m.time)-1, val=35.0e6)
    
    # MINIMIZE FINAL FUEL TIME
    m.Minimize(t_f)
    
    # SOLVE
    m.options.SOLVER = 3
    m.solve()
    
    # RESULTS
    print('Final Time: ' + str(t_f.value[0]))
    

    Nice work simplifying the problem. Those deleted equations can likely be added back in, if desired, for convenience in plotting the solution. The next step is likely to plot the solution and see if it make intuitive sense with the weights and any constraint violations.