Problem of using GEKKO variables in self-defined function in python - python

I tried to use GEKKO variables in self-defined function in python. But there are always annoying errors which I cannot find reason for. Could you please give me a favour?
The whole code is too long. So I only picked the important lines here to show the problem.
index = 0
na = 3
inter = np.zeros((na,na))
intera = np.zeros(na*na)
# all the other unmentioned parameters are constant.
def myfunction(x1,x2):
...
gvol_fv = A + B * x1 + C * x1 ** 2
for i in range(na):
for j in range(na):
print(index,aij[index],bij[index],cij[index])
intera[index] = aij[index] + bij[index] * x1 + cij[index] * x1**2
inter[i][j] = math.exp((aij[index] + bij[index] * x1 + cij[index] * x1**2.0 / 1000.0)/x1)
index = index+1
print(index)
...
return [ac1,ac2] # ac1 and ac2 are very complicated variables.
x1 = m.Const(300.0)
x21,x22 = [m.Var(0.01,0.0,1.0) for i in range (2)]
mf_x21_1 = myfunction(x1,x21)[0]
mf_x21_2 = myfunction(x1,x21)[1]
mf_x22_1 = myfunction(x1,x22)[0]
mf_x22_2 = myfunction(x1,x22)[1]
m.Equation(mf_x21_1==mf_x22_1)
m.Equation(mf_x21_2==mf_x22_2)
m.options.IMODE = 1
m.solve()
The errors are as following:
#### for intera[index]:
ValueError: setting an array element with a sequence.
#### for inter[i][j]:
TypeError: a float is required

Unfortunately Gekko doesn't have full support for numpy arrays right now, and the error comes from trying to insert a Gekko variable into a numpy array. To make an array of Gekko variables, you need to either use Gekko arrays, or nested lists. Here's an example of both approaches:
from gekko import GEKKO
m = GEKKO()
ni = 3 # number of rows
nj = 2 # number of columns
# best method: use m.Array function
x = m.Array(m.Var,(ni,nj))
m.Equations([x[i][j]==i*j+1 for i in range(ni) for j in range(nj)])
# another way: list comprehensions
y = [[m.Var() for j in range(nj)] for i in range(ni)]
for i in range(ni):
for j in range(nj):
m.Equation(x[i][j]**2==y[i][j])
# summation
z = m.Var()
m.Equation(z==sum([sum([x[i][j] for i in range(ni)]) for j in range(nj)]))
m.solve()
print('x:')
print(x)
print('y=x**2:')
print(y)
print('z')
print(z.value)

Related

When solving nonlinear regression problem over a long data set, the Objective value comes high? As a result estimation fails

I am trying to minimize the average root mean squared error of the following form in a class file using Gekko:
objective = np.sqrt((np.sum((ym-np.array(y))**2))/N/
(np.sum((ym-np.mean(ym))**2))/N)
Here is the code:
# Code
from math import ceil
import numpy as np
import pandas as pd
import os
from gekko import GEKKO
import sys
from demandlib.tools import add_weekdays2df
import matplotlib.pyplot as plt
class HeatBuilding_Personalized:
def __init__(self, df_index, **kwargs):
self.datapath = kwargs.get(
'datapath', os.path.join(os.path.dirname(__file__), 'bdew_data'))
self.df = pd.DataFrame(index=df_index)
self.df = add_weekdays2df(self.df, holiday_is_sunday=True,
holidays=kwargs.get('holidays'))
self.df['hour'] = self.df.index.hour + 1 # hour of the day
self.temperature = kwargs.get('temperature')
self.annual_heat_demand = kwargs.get('annual_heat_demand')
self.shlp_type = kwargs.get('shlp_type').upper()
self.wind_class = kwargs.get('wind_class')
self.building_class = kwargs.get('building_class', 0)
self.ww_incl = kwargs.get('ww_incl', True)
self.name = kwargs.get('name', self.shlp_type)
self.data_points = kwargs.get('data_points')
self.st_p= kwargs.get('st_p')
self.end= kwargs.get('end')
def get_bdew_profile(self):
""" Calculation of the normalized hourly heat demand
"""
self.df['temperature'] = self.temperature.values
self.df['temperature_geo'] = self.weighted_temperature(how='geometric_series')
sf = self.get_sf_values()
f = self.get_weekday_parameters()
# measurements
self.df['data_points']=self.data_points.values
self.df= self.df[self.st_p:self.end]
self.df=self.df.dropna()
self.annual_heat_demand= self.df['data_points'].sum()
self.temperature= pd.DataFrame(self.df['temperature'])
print(self.df)
ym = pd.DataFrame(self.df['data_points'])
print("amount of nan",str(ym.isnull().sum()))
ymeas_mean = np.mean(ym)
print(ym)
print('ymeas_mean:',ymeas_mean)
x1= np.array(self.df['temperature_geo'])
x2= np.array(self.get_weekday_parameters())
x3= np.int(self.annual_heat_demand)
x4= np.array(self.get_sf_values())
ym= np.array(ym)
# GEKKO model
m = GEKKO(remote=False)
a = m.FV( 3.7,lb=1,ub=4)
a.STATUS=1
b = m.FV(-35.1,lb=-40,ub=-30)
b.STATUS=1
c = m.FV(7.1,lb=5,ub=9)
c.STATUS=1
d = m.FV( 0.9,lb=0.1,ub=1.5)
d.STATUS=1
# variables
T_g= m.Param(value=x1)
f=m.Param(value=x2)
annual_demand=m.Param(value=x3)
sf=m.Param(value=x4)
ymeas = m.Param(value=ym)
N = len(ym)
print('index n:',N)
yest = m.CV(value=0)
yest.FSTATUS=1
# y=m.Var() # I am defining my state variabel
# y = m.Var()
# z.FSTATUS=1
# regression equation
k = m.Intermediate((a / (1 + (b / (T_g - 40)) ** c) + d))
s=m.Intermediate(np.sum(k*f))
kw=m.Intermediate( 1.0 / (s / 24))
m.Equation(yest == (k* kw * f * sf) * annual_demand)
# objectives
# m.Minimize(((yest-ymeas)/ymeas)**2)
m.Obj(m.sqrt((np.sum((ymeas-yest)**2))/N/(np.sum((ymeas-np.mean(ymeas))**2))/N))
# print('Obj init value = ' + str(object_af.value))
# regression mode
m.options.IMODE = 2
m.options.SOLVER = 1 # considering APOPT solver for 1 and IPOPT for 3
# optimize
m.options.MAX_ITER = 20
m.options.OTOL = 1.0e-10
m.options.RTOL = 1.0e-10
m.solve(disp=True)
# print parameters
# print('Obj after value = ' + str(vd.value))
print('Optimized, a = ' + str(a.value[0]))
print('Optimized, b = ' + str(b.value[0]))
print('Optimized, c = ' + str(c.value[0]))
print('Optimized, d = ' + str(d.value[0]))
# print('Optimized, h = ' + str(h.value))
# sys.exit()
print("optimization is ok")
sf = self.get_sf_values()
f = self.get_weekday_parameters()
h = (a.value[0] / (1 + (b.value[0] / (self.df['temperature_geo'] - 40)) ** c.value[0]) + d.value[0])
kw = 1.0 / (sum(h * f) / 24) #1.0 instead of annual heat demand because the #annual heat demand is already multiplied in get_bdew_profile and divide by 24 to get #daily value
y = (kw * h * f * sf) * self.annual_heat_demand
objective= np.sqrt((np.sum((ym-np.array(y))**2))/N/(np.sum((ym-np.mean(ym))**2))/N)
print('objective calculated without Gekko:',objective)
return y
It returns this output:
Outputs: Solver :
APOPT (v1.0) Solution time : 27.2771999999968 sec
Objective : 40884011.5968099
Successful solution --------------------------------------------------
Optimized, a = 3.8708321781 Optimized, b = -31.844822393
Optimized, c = 7.8648564579 Optimized, d = 1.0244814518
The objective value is high. Without Gekko the objective is calculated as 0.01904060781034217. Why is it different?
It is hard to diagnose the problem because it is missing the data to run and verify. Here are a couple things to change:
Set yest as a Variable instead of a CV. It is automatically adding squared error terms when you declare a CV with FSTATUS=1 as described in the Dynamic Optimization course and in the Estimator Tuning Lesson. Because you are defining a custom objective, there is no need to declare a CV.
#yest = m.CV(value=0)
#yest.FSTATUS=1
yest = m.Var(value=0)
For a direct comparison, try declaring Intermediate variables to inspect the parts of the objective. Also, use m.sum() instead of np.sum() for the Gekko version of summation. The den piece is a number so it can be pre-calculated before the objective function is defined with ym.
den = (np.sum((ym-np.mean(ym))**2)
m.Obj(m.sqrt((np.sum((ymeas-yest)**2))/(den*N*N)))
Please post complete minimal, verifiable code for more specific help.
so we corrected the code like said in the previous comment but we get problems when we try to take a sum of a gekko parameter and we don't understand why. s is the variable where we calculate a sum and try to use it in the next equation but it doesn't work. Even with numpy.sum() it doesn't sum it up. We get this error: TypeError: x must be a python list of GEKKO parameters, variables, or expressions
Any idea what we need to change on factor k or f so the sum can be achieved?
x1= np.array(self.df['temperature_geo'])
x2= np.array(self.get_weekday_parameters())
x3= np.int(self.annual_heat_demand)
x4= np.array(self.get_sf_values())
ym= np.array(ym)
# GEKKO model
m = GEKKO(remote=False)
# variables
T_g= m.Param(value=x1)
f=m.Param(value=x2)
annual_demand=m.Param(value=x3)
sf=m.Param(value=x4)
ymeas = m.Param(value=ym)
yest = m.Var(value=0)
# regression equation
k = m.Intermediate((a / (1 + (b / (T_g - 40)) ** c) + d))
s=m.Intermediate(m.sum(k*f))
kw=m.Intermediate( 1.0 / (s / 24))
m.Equation(yest == (k* kw * f * sf) * annual_demand)
den = (m.sum((ymeas-np.mean(ymeas))**2))
ben = m.sum((ymeas-yest)**2)
m.Obj(m.sqrt((ben)/N/(den)/N))
# print('Obj init value = ' + str(object_af.value))
# regression mode
m.options.IMODE = 2
m.options.SOLVER = 1 # considering APOPT solver for 1 and IPOPT for 3
# optimize
m.options.MAX_ITER = 20
m.options.OTOL = 1.0e-10
m.options.RTOL = 1.0e-10
m.solve(disp=True)

Problem while looping variables for Scipy Optimization (SLSQP, COBYLA)

I have a constrained optimization problem where I am trying to minimize an objective function of 100+ variables which is of the form
Min F(x) = f(x1) + f(x2) + ... + f(xn)
Subject to functional constraint
(g(x1) + g(x2) + ... + g(xn))/(f(x1) + f(x2) + ... + f(xn)) - constant >= 0
I also have individual bounds for each variable x1, x2, x3...xn
a <= x1 <= b
c <= x2 <= d
...
For this, I wrote a python script, using the scipy.optimize.minimize implementation with constraints and bounds, but I am unable to fulfill my bounds and constraints in the solutions. These are all cases where optimization could converge to a solution (message: success)
Here is a sample of my code:
df is my pandas dataset
B(x) is LogNorm transform based on x and other constants
Values U, c, lb, ub are pre-calculated constant dictionaries for each index in df
import scipy
df = pd.DataFrame(..)
k = set(df.index.values) ## list of indexes to iterate on
val = 0.25 ## Arbitrary
def obj(x):
fn = 0
for n,i in enumerate(k):
x0 = x[n]
fn1 = (U[i]) * B(x0) * (x0)
fn += fn1
return fn
def cons(x):
cn = 1
c1 = 0
c2 = 0
for n,i in enumerate(k):
x0 = x[n]
c1 += (U[i]) * (B(x0) * (x0 - c[i])
c2 += (U[i]) * (B(x0) * (x0)
cn = c1/(c2)
return cn - val
const = [{'type':'ineq', 'fun':cons}]
bnds = tuple((lb[i], ub[i]) for i in k) ## Lower, Upper for each element ((lb1, ub1), (lb2, ub2)...)
x_init = [lb[i] for i in k] ## for eg. starting from lower bound
## Solution
sol = scipy.optimize.minimize(obj, x_init, method = 'COBYLA', bounds = bnds, constraints = const)
I have more pointed questions if that helps:
Is there a way to construct the same equation concisely/ without the use of loops (given the number of variables could depend on input data and I have no control over it)?
Is there any noticeable issue in my application of bounds? I can't seem to get the final values of all variables follow individual bounds.
Similarly, is there a visible flaw in the construction on constraint equation? My results often DO NOT follow the constraints is repeated runs with different inputs.
Any help with either of the questions can help me progress further at work.
I have also looked into a Lagrangian solution of the same but so far I am unable to solve it for undefined number of (n) variables.
Thanks!

Solving Receding Horizon Control in GEKKO

I'm trying to implement a receding horizon control (RHC) scheme using GEKKO in Python, and I'd like to check my formulation. The goal is to solve the OCP over some horizon from t=tk to t=tk+H-1, apply the control solution at tk, and discard the remaining values (u_k+1 to u_k+H-1). The following code appears to give the correct solution, but I want to verify I've used the correct functions in GEKKO, namely when "resetting" the states for the next horizon. I had a few issues trying to use the .VALUE function to reset x1 and x2, e.g. TypeError: 'float' object is not subscriptable.
import numpy as np
import matplotlib.pylab as plt
from gekko import GEKKO
if __name__ == '__main__':
# Instantiate GEKKO
m = GEKKO()
# Constants
nRHC = 21
tRHC = 2
m.time = np.linspace(0, tRHC, nRHC)
# Control
u = m.MV(value=0.0,fixed_initial=False)
u.STATUS = 1
u.DCOST = 0
# Vars
t = m.SV(value=0)
x1 = m.SV(value=1)
x2 = m.SV(value=0)
# Equations
m.Equation(t.dt() == 1)
m.Equation(x1.dt() == x2)
m.Equation(x2.dt() == (1 - x2*x2)*x1 - x2 + u)
# Objective Function
m.Minimize(10*x1**2 + 10*x2**2 + u**2)
# Solve RHC
m.options.IMODE = 6
m.options.NODES = 11
m.options.MV_TYPE = 2
m.options.SOLVER = 3
nTotal = 101
tTotal = np.linspace(0, 10, nTotal)
uStore = np.zeros((1,nTotal))
xStore = np.zeros((2,nTotal))
xStore[:,0] = [1, 0]
for i in range(nTotal):
print('Solving Step: ', i+1, ' of ', nTotal-1)
if i == nTotal-1:
break
# Solve MPC over horizon
m.solve(disp=False)
# Update States
t.VALUE = t[1]
x1.MEAS = x1[1]
x2.MEAS = x2[1]
# Store
uStore[:,i] = u.NEWVAL
xStore[:,i+1] = np.array([x1[1], x2[1]])
# Plot States
f1, axs = plt.subplots(2)
axs[0].plot(tTotal, xStore[0,:])
axs[0].set_ylabel('x')
axs[0].grid()
axs[1].plot(tTotal, xStore[1,:])
axs[1].set_ylabel('x_dot')
axs[1].set_xlabel('time')
axs[1].grid()
# Show Plots
plt.show()
Thank you!
There is no need to update the states because Gekko does this automatically.
# Update States
t.VALUE = t[1]
x1.MEAS = x1[1]
x2.MEAS = x2[1]
The state values are stored in run directory files (see m.path or open with m.open_folder()). The file is ctl.t0. At the next command m.solve(), that file is imported and time shifted to make the values at the next time step the initial conditions. The time shift is adjusted with m.options.TIME_SHIFT=1 (1 is the default). If you do want to override the initial condition, use x1.MEAS=x1.value[1] or x1.value=x1.value[1].

cvxpy - How to obtain the variable value after each iteration?

I am using cvxpy to solve a second order cone program. I have used the boilerplate code as mentioned in the cvxpy website - cvxpy SOCP webpage. I do not know how to obtain the variable value after each iteration...
Code from the link:
# Import packages.
import cvxpy as cp
import numpy as np
# Generate a random feasible SOCP.
m = 3
n = 10
p = 5
n_i = 5
f = np.random.randn(n)
A = []
b = []
c = []
d = []
x0 = np.random.randn(n)
for i in range(m):
A.append(np.random.randn(n_i, n))
b.append(np.random.randn(n_i))
c.append(np.random.randn(n))
d.append(np.linalg.norm(A[i] # x0 + b, 2) - c[i].T # x0)
# Define and solve the CVXPY problem.
x = cp.Variable(n)
# We use cp.SOC(t, x) to create the SOC constraint ||x||_2 <= t.
soc_constraints = [
cp.SOC(c[i].T # x + d[i], A[i] # x + b[i]) for i in range(m)
]
prob = cp.Problem(cp.Minimize(f.T#x), soc_constraints)
prob.solve()
# Print result.
print("The optimal value is", prob.value)
print("A solution x is")
print(x.value)
x.value here only gives the variable value after all the iterations are done. I want x.value after each iteration.

ValueError: x and y must have the same first dimension

I am trying to implement a finite difference approximation to solve the Heat Equation, u_t = k * u_{xx}, in Python using NumPy.
Here is a copy of the code I am running:
## This program is to implement a Finite Difference method approximation
## to solve the Heat Equation, u_t = k * u_xx,
## in 1D w/out sources & on a finite interval 0 < x < L. The PDE
## is subject to B.C: u(0,t) = u(L,t) = 0,
## and the I.C: u(x,0) = f(x).
import numpy as np
import matplotlib.pyplot as plt
# parameters
L = 1 # legnth of the rod
T = 10 # terminal time
N = 10
M = 100
s = 0.25
# uniform mesh
x_init = 0
x_end = L
dx = float(x_end - x_init) / N
x = np.arange(x_init, x_end, dx)
x[0] = x_init
# time discretization
t_init = 0
t_end = T
dt = float(t_end - t_init) / M
t = np.arange(t_init, t_end, dt)
t[0] = t_init
# Boundary Conditions
for m in xrange(0, M):
t[m] = m * dt
# Initial Conditions
for j in xrange(0, N):
x[j] = j * dx
# definition of solution u(x,t) to u_t = k * u_xx
u = np.zeros((N, M+1)) # array to store values of the solution
# Finite Difference Scheme:
u[:,0] = x**2 #initial condition
for m in xrange(0, M):
for j in xrange(1, N-1):
if j == 1:
u[j-1,m] = 0 # Boundary condition
elif j == N-1:
u[j+1,m] = 0
else:
u[j,m+1] = u[j,m] + s * ( u[j+1,m] -
2 * u[j,m] + u[j-1,m] )
print u, #t, x
plt.plot(u, t)
#plt.show()
I think my code is working properly and it is producing an output. I want to plot the output of the solution u versus t (my time vector). If I can plot the graph then I am able to check if my numerical approximation agrees with the expected phenomena for the Heat Equation. However, I am getting the error that "x and y must have same first dimension". How can I correct this issue?
An additional question: Am I better off attempting to make an animation with matplotlib.animation instead of using matplotlib.plyplot ???
Thanks so much for any and all help! It is very greatly appreciated!
Okay so I had a "brain dump" and tried plotting u vs. t sort of forgetting that u, being the solution to the Heat Equation (u_t = k * u_{xx}), is defined as u(x,t) so it has values for time. I made the following correction to my code:
print u #t, x
plt.plot(u)
plt.show()
And now my programming is finally displaying an image. And here it is:
It is absolutely beautiful, isn't it?

Categories

Resources