i'm currently working on a model of a distillation flask for a university project, the phisical problem is described by a DAE system, and i'm trying to solve it using GEKKO.
I'm facing a problem with list handling:
In this case i built a function that outputs the compressibility factor of a mixture, and it requires as inputs 3 gekko variables T1,x,y (x,y arrays)
zv1 = m.Param(value=ZCALC(n,comps,R0,p,T1.value,x,y))
m = GEKKO()
y = m.Array(m.Var,n,value=0.)
x = m.Array(m.Var,n,value=0.)
for i in range(n):
y[i].value = y0[i]
x[i].value = x0[i]
T1 = m.Var(value=3.31513478e+02, lb=300, ub=900)
If i leave the 3 values as they are i recieve some errors like:
File "F:\Codice_GEKKO\D86_GEKKO.py", line 113, in <module>
zv1 = m.Param(value=ZCALC(n,comps,R0,p,T1.value,x,y))
File "F:\Codice_GEKKO\compressibilityfactor.py", line 48, in ZCALC
zv=np.max(np.roots([1,-1,(Av-Bv-Bv**2),-Av*Bv]))
File "<__array_function__ internals>", line 6, in roots
File "C:\Users\verci\AppData\Local\Programs\Python\Python36\lib\site-packages\numpy\lib\polynomial.py", line 222, in roots
non_zero = NX.nonzero(NX.ravel(p))[0]
File "<__array_function__ internals>", line 6, in nonzero
File "C:\Users\verci\AppData\Local\Programs\Python\Python36\lib\site-packages\numpy\core\fromnumeric.py", line 1908, in nonzero
return _wrapfunc(a, 'nonzero')
File "C:\Users\verci\AppData\Local\Programs\Python\Python36\lib\site-packages\numpy\core\fromnumeric.py", line 67, in _wrapfunc
return _wrapit(obj, method, *args, **kwds)
File "C:\Users\verci\AppData\Local\Programs\Python\Python36\lib\site-packages\numpy\core\fromnumeric.py", line 44, in _wrapit
result = getattr(asarray(obj), method)(*args, **kwds)
File "C:\Users\verci\AppData\Local\Programs\Python\Python36\lib\site-packages\gekko\gk_operators.py", line 25, in __len__
return len(self.value)
File "C:\Users\verci\AppData\Local\Programs\Python\Python36\lib\site-packages\gekko\gk_operators.py", line 144, in __len__
return len(self.value)
TypeError: object of type 'int' has no len()```
Traceback (most recent call last):
File "F:\Codice_GEKKO\D86_GEKKO.py", line 113, in <module>
zv1 = m.Param(value=ZCALC(n,comps,R0,p,T1,x,y))
File "F:\Codice_GEKKO\compressibilityfactor.py", line 27, in ZCALC
(1-np.sqrt(t/tc[ii])))**2
TypeError: loop of ufunc does not support argument 0 of type GK_Operators which has no callable sqrt method
The first error is biven by the fact that x and y are not list, but they are GEKKO arrays and the second error is due to T1 not being a float (t=T1)
I found out that by using T1.value i can avoid the second error but still i have the first error
I have read the gekko documentation but i haven't been able to find a method to obtain a "standard" python list from a GEKKO array
Thank you in advance for your help
There are two different methods for obtained the value of zv.
Option 1: Initialization Calculation
The first method is to use floating point numbers to obtain a single calculation that can be used for initialization of a parameter. This first method allows any type of functions such as np.roots() or np.sqrt(). The function ZCALC() returns a floating point number. Even though Gekko variables are used as an input, the floating point number is accessed from a scalar variable with T1.value or from an array variable with x[i].value.
def ZCALC(n,comps,R0,p,T1,x,y):
# using the initialized values
t = T1.value
i = 0 # select values from x,y arrays
x1 = x[i].value
y1 = y[i].value
print('t,x[0],y[0] initialized values')
print(t,x1,y1)
# include equations for compressibility factor
w = (1-np.sqrt(t/300))**2
z = np.max(np.roots([1,-1,x1**2,x1*y1]))
# original equations from question
#(1-np.sqrt(t/tc[ii])))**2
#zv=np.max(np.roots([1,-1,(Av-Bv-Bv**2),-Av*Bv]))
return z
zv1 = m.Param(value=ZCALC(n,comps,R0,p,T1,x,y))
Option 2: Implicit Calculation
If the compressibility factor needs to change as T1 and x,y change then use Gekko variables so that the model is compiled with that dependency. The functions are only called during problem initialization. Gekko needs the equations with specific Gekko functions to enable automatic differentiation to provide gradients to the solvers.
def ZCALC2(n,comps,R0,p,T1,x,y):
# using gekko variables
t = T1
i = 0
x1 = x[i] # use index to x array
y1 = y[i] # use index to y array
# use Gekko equations, not Numpy
w = (x1/y1)*(1-m.sqrt(t/300))**2
# set lower bound to get the maximum root
zv = m.Var(value=ZCALC(n,comps,R0,p,T1,x,y),lb=10)
# solve for roots of eq with gekko, not with np.roots
eq = 1-zv+x1**2*zv+x1*y1*zv**3
m.Equation(eq==0)
return zv
zv2 = ZCALC2(n,comps,R0,p,T1,x,y)
Here is a script that shows the two methods:
import numpy as np
m=GEKKO(remote=False)
def ZCALC(n,comps,R0,p,T1,x,y):
# using the initialized values
t = T1.value
i = 0 # select values from x,y arrays
x1 = x[i].value
y1 = y[i].value
print('t,x[0],y[0] initialized values')
print(t,x1,y1)
# include equations for compressibility factor
w = (1-np.sqrt(t/300))**2
z = np.max(np.roots([1,-1,x1**2,x1*y1]))
# original equations from question
#(1-np.sqrt(t/tc[ii])))**2
#zv=np.max(np.roots([1,-1,(Av-Bv-Bv**2),-Av*Bv]))
return z
def ZCALC2(n,comps,R0,p,T1,x,y):
# using gekko variables
t = T1
i = 0
x1 = x[i] # use index to x array
y1 = y[i] # use index to y array
# use Gekko equations, not Numpy
w = (x1/y1)*(1-m.sqrt(t/300))**2
# set lower bound to get the maximum root
zv = m.Var(value=ZCALC(n,comps,R0,p,T1,x,y),lb=10)
# solve for roots of eq with gekko, not with np.roots
eq = 1-zv+x1**2*zv+x1*y1*zv**3
m.Equation(eq==0)
return zv
n = 3
y = m.Array(m.Var,n)
x = m.Array(m.Var,n)
x0 = [0.1,0.2,0.3]
y0 = [0.15,0.25,0.35]
for i in range(n):
y[i].value = y0[i]
x[i].value = x0[i]
T1 = m.Var(value=331, lb=300, ub=900)
comps = ['C2=','C3=','C2H8']; R0 = 8.314; p=10
# define Zv from initialized values (fixed parameter)
zv1 = m.Param(value=ZCALC(n,comps,R0,p,T1,x,y))
# define Zv from Gekko variables (updates with T1,x,y changes)
zv2 = ZCALC2(n,comps,R0,p,T1,x,y)
# initialized value of zv1 does not update with changes in T1,x,y
# initialized value of zv2 does update with changes in T1,x,y
print('initialized value of zv1, zv2')
print(zv1.value,zv2.value)
If the compressibility factor correlations can't be expressed as Gekko equations then try the cspline for 1D or bspline for 2D functions to create an approximation. You may be able to use the bspline function if compressibility can depend on just 2 variables T and x (replace y with an explicit calculation of x).
Related
After using curve_fitting from scipy,the scatter data is fitted by Gaussian approximation,the code is as follows:
x = np.linspace(1,len(y),len(y))
n = len(x)
mean = sum(x*y)/n
sigma = np.sqrt(sum(y*(x-mean)**2)/n)
def gaus(x,a,x0,sigma):
return a*np.exp(-(x-x0)**2/(2*sigma**2))/(sigma*np.sqrt(2*np.pi))
popt,pcov = curve_fit(gaus,x,y,maxfev = 200000)
When I call it, the generated p1 is just an array corresponding to x:
p1 = gaus(x,*popt)
,The returned array is:
[0.09933219 0.10139629 0.10350315 0.10565368 0.10784877 0.11008935
0.11237635 0.11471073 0.11709347 0.11952557 0.12200806 0.12454196
0.12712835 0.1297683 0.13246293 0.13521337 0.13802076 0.14088628
0.14381113 0.14679655 0.14984377 0.15295407 0.15612876 0.15936917
0.16267665 0.16605259 0.1694984 0.17301552 0.17660543 0.18026962
0.18400963 0.18782703 0.19172341 0.19570039 0.19975966 0.20390289
0.20813183 0.21244823 0.21685392 0.22135072 0.22594052 0.23062523
0.23540682 0.24028728 0.24526864 0.250353 0.25554246 0.26083921
0.26624545 0.27176344 0.27739549 0.28314393 0.28901118 0.29499968
0.30111193 0.30735049 0.31371794 0.32021696 0.32685025 0.33362057
0.34053076 0.34758369 0.3547823 0.36212959 0.36962863 0.37728255
0.38509452 0.39306781 0.40120574 0.4095117 0.41798914 0.42664161
0.4354727 0.4444861 0.45368554 0.46307487 0.472658 0.4824389
0.49242166 0.50261042 0.51300944 0.52362302 0.53445559 0.54551166
0.55679582]
In this case, how can I find it's first derivative expression, the second derivative and so on for the generated function?
This can be achieved using scipy.interpolate.InterpolatedUnivariateSpline.
First, you need to create a spline of your data as:
from scipy.interpolate import InterpolatedUnivariateSpline
spl = InterpolatedUnivariateSpline(x, p1)
Afterward, you can use the spl object to pass x and n (the number of derivative), to get a new spline as np.ndarray at x with its nth derivative as:
der1 = spl(x, 1)
der2 = spl(x, 2)
I'm new to pytorch. I'm trying to implement a custom loss function by computing the absolute and relative distance and concatenating them.
def distance(p1, p2,labels):
"""
Returns the distance between the point sets p1 and p2
p1 = m by d matrix containing a set of points
p2 = m by d matrix containing a different set of points
returns: an m-length vector containing the distance from each point in
p1 to the corresponding point in p2
"""
if not np.all(p1.shape == p2.shape):
raise ValueError("p1 and p2 must be the same shape.")
d = p1.shape[1]
features = np.zeros(dtype=np.float32, shape=(p1.shape[0], d * 2))
features[:, :d] = np.abs(p1 - p2)
features[:, d:] = (p1 + p2) / 2
return features
The problem appears when I try to run it and I get the following error:
File "... line 34, in distance
features[:, :d] = np.abs(p1 - p2)
File "...\Anaconda2\envs\tensorflow_gpuenv\lib\site-packages\tensorflow\python\util\dispatch.py", line 180, in wrapper
return target(*args, **kwargs)
File "...\lib\site-packages\tensorflow\python\ops\math_ops.py", line 266, in abs
x = ops.convert_to_tensor(x, name="x")
File "...\lib\site-packages\tensorflow\python\framework\ops.py", line 1087, in convert_to_tensor
return convert_to_tensor_v2(value, dtype, preferred_dtype, name)
RuntimeError: Can't call numpy() on Variable that requires grad. Use var.detach().numpy() instead.
The error tells you exactly what is going wrong. You need to convert first the pytorch tensor into a numpy array. You can do that using .detach().numpy()
So inside your function you can put:
def distance(p1, p2, labels):
p1 = p1.detach().numpy()
p2 = p2.detach().numpy()
labels = labels.detach().numpy()
Even though be aware that tensor are meant to speed up calculations, converting them into array means to increase computation time. So looking at pytorch functions as suggested in the comments is definitely the best approach to follow.
I am completely new to python and in fact any fundamental programming language, I use Mathematica for my all my symbolic and numeric calculations. I am learning to work with python and finding it really awesome! Here is a problem I am trying to solve but stuck without a clue!
I have a data file for example
0. 1.
0.01 0.9998000066665778
0.02 0.9992001066609779
... ..
Which just the {t, Cos[2t]}.
I want to define a function out of this data and use it in solving an equation in python. My Mathematica intuition tells me that I should define the function like:
iFunc[x_] = Interpolation[iData, x]
and rest of the job is easy. for instance
NDSolve[{y''[x] + iFunc[x] y[x] == 0, y[0] == 1, y[1] == 0}, y, {x, 0, 1}]
Solves the equation easily. (I have not tried with more complicated cases though).
Now how to do the job in python and also accuracy is an important issue for me. So, now I would like to ask two questions.
1. Is this the most accurate method in Mathematica?
2. And what is the equivalent of more accurate way to do the problem in python?
Here is my humble attempt to solve the problem (with a lot of input from StackOverflow) where the definition with cos(2t) works:
from scipy.integrate import odeint
import numpy as np
import matplotlib.pyplot as plt
from math import cos
from scipy import interpolate
data = np.genfromtxt('cos2t.dat')
T = data[:,0] #first column
phi = data[:,1] #second column
f = interpolate.interp1d(T, phi)
tmin = 0.0# There should be a better way to define from the data
dt = 0.01
tmax = 2*np.pi
t = np.arange(tmin, tmax, dt)
phinew = f(t) # use interpolation function returned by `interp1d`
"""
def fun(z, t):
x, y = z
return np.array([y, -(cos(2*t))*x ])
"""
def fun(z, t):
x, y = z
return np.array([y, -(phinew(t))*x ])
sol1 = odeint(fun, [1, 0], t)[..., 0]
# for checking the plots
plt.plot(t, sol1, label='sol')
plt.show()
*When I run the code with interpolated function from cos(2t) data, is not working...the error message tell
Traceback (most recent call last): File "testde.py", line 30,
in <module> sol1 = odeint(fun, [1, 0], t)[..., 0]
File "/home/archimedes/anaconda3/lib/python3.6/site-packages/scipy/integrate/odepack.py",
line 215, in odeint ixpr, mxstep, mxhnil, mxordn, mxords)
File "testde.py",
line 28, in fun return np.array([y, -(phinew(t))*x ])
TypeError: 'numpy.ndarray' object is not callable.
I really can't decipher them. Please help...
In Mathematica, the usual way is simply
iFunc = Interpolation[iData]
Interpolation[iData] already returns a function.
To sub-question 2
With
t = np.arange(tmin, tmax, dt)
phinew = f(t) # use interpolation function returned by `interp1d`
equivalent to
phinew = np.array([ f(s) for s in t])
you construct phinew not as callable function but as array of values, closing the circle array to interpolation function to array. Use f which is a scalar function directly in the derivatives function,
def fun(z, t):
x, y = z
return np.array([y, -f(t)*x ])
I am practicing with SciPy and I encountered an error when trying to use fmin_slsqp. I set up a problem in which I want to maximize an objective function, U, given a set of constraints.
I have two control variables, x[0,t] and x[1,t] and, as you can see, they are indexed by t (time periods). The objective function is:
def obj_fct(x, alpha,beta,Al):
U = 0
x[1,0] = x0
for t in trange:
U = U - beta**t * ( (Al[t]*L)**(1-alpha) * x[1,t]**alpha - x[0,t])
return U
The constraints are defined over these two variables and one of them links the variables from one period (t) to another (t-1).
def constr(x,alpha,beta,Al):
return np.array([
x[0,t],
x[1,0] - x0,
x[1,t] - x[0,t] - (1-delta)*x[1,t-1]
])
Finally, here is the use of fmin_slsqp:
sol = fmin_slsqp(obj_fct, x_init, f_eqcons=constr, args=(alpha,beta,Al))
Leaving aside the fact that there are better ways to solve such dynamic problems, my question is about the syntax. When running this simple code, I get the following error:
Traceback (most recent call last):
File "xxx", line 34, in <module>
sol = fmin_slsqp(obj_fct, x_init, f_eqcons=constr, args=(alpha,beta,Al))
File "D:\Anaconda3\lib\site-packages\scipy\optimize\slsqp.py", line 207, in fmin_slsqp
constraints=cons, **opts)
File "D:\Anaconda3\lib\site-packages\scipy\optimize\slsqp.py", line 311, in _minimize_slsqp
meq = sum(map(len, [atleast_1d(c['fun'](x, *c['args'])) for c in cons['eq']]))
File "D:\Anaconda3\lib\site-packages\scipy\optimize\slsqp.py", line 311, in <listcomp>
meq = sum(map(len, [atleast_1d(c['fun'](x, *c['args'])) for c in cons['eq']]))
File "xxx", line 30, in constr
x[0,t],
IndexError: too many indices for array
[Finished in 0.3s with exit code 1]
What am I doing wrong?
The initial part of the code, assigning values to the parameters, is:
from scipy.optimize import fmin_slsqp
import numpy as np
T = 30
beta = 0.96
L = 1
x0 = 1
gl = 0.02
alpha = 0.3
delta = 0.05
x_init = np.array([1,0.1])
A_l0 = 1000
Al = np.zeros((T+1,1))
Al[1] = A_l0
trange = np.arange(1,T+1,1, dtype='Int8') # does not include period zero
for t in trange: Al[t] = A_l0*(1 + gl)**(t-1)
The array x passed to your objective and constraint functions will be a one-dimensional array (just like your x_init is). You can't index a one-dimensional array with two indices, so expressions such as x[1,0] and x[0,t] will generate an error.
I have a set of data that I am trying to fit to an ODE model using scipy's leastsq function. My ODE has parameters beta and gamma, so that it looks for example like this:
# dS/dt = -betaSI
# dI/dt = betaSI - gammaI
# dR/dt = gammaI
# with y0 = y(t=0) = (S(0),I(0),R(0))
The idea is to find beta and gamma so that the numerical integration of my system of ODE's best approximates the data. I am able to do this just fine using leastsq if I know all the points in my initial condition y0.
Now, I am trying to do the same thing but to pass now one of the entries of y0 as an extra parameter. Here is where the Python and me stop communicating...
I did a function so that now the first entry of the parameters that I pass to leastsq is the initial condition of my variable R.
I get the following message:
*Traceback (most recent call last):
File "/Users/Laura/Dropbox/SHIV/shivmodels/test.py", line 73, in <module>
p1,success = optimize.leastsq(errfunc, initguess, args=(simpleSIR,[y0[0]],[Tx],[mydata]))
File "/Library/Frameworks/Python.framework/Versions/7.2/lib/python2.7/site-packages/scipy/optimize/minpack.py", line 283, in leastsq
gtol, maxfev, epsfcn, factor, diag)
TypeError: array cannot be safely cast to required type*
Here is my code. It is a little more involved that what it needs to be for this example because in reality I want to fit another ode with 7 parameters and want to fit to several data sets at once. But I wanted to post here something simpler... Any help will be very very much appreciated! Thank you very much!
import numpy as np
from matplotlib import pyplot as plt
from scipy import optimize
from scipy.integrate import odeint
#define the time span for the ODE integration:
Tx = np.arange(0,50,1)
num_points = len(Tx)
#define a simple ODE to fit:
def simpleSIR(y,t,params):
dydt0 = -params[0]*y[0]*y[1]
dydt1 = params[0]*y[0]*y[1] - params[1]*y[1]
dydt2 = params[1]*y[1]
dydt = [dydt0,dydt1,dydt2]
return dydt
#generate noisy data:
y0 = [1000.,1.,0.]
beta = 12*0.06/1000.0
gamma = 0.25
myparam = [beta,gamma]
sir = odeint(simpleSIR, y0, Tx, (myparam,))
mydata0 = sir[:,0] + 0.05*(-1)**(np.random.randint(num_points,size=num_points))*sir[:,0]
mydata1 = sir[:,1] + 0.05*(-1)**(np.random.randint(num_points,size=num_points))*sir[:,1]
mydata2 = sir[:,2] + 0.05*(-1)**(np.random.randint(num_points,size=num_points))*sir[:,2]
mydata = np.array([mydata0,mydata1,mydata2]).transpose()
#define a function that will run the ode and fit it, the reason I am doing this
#is because I will use several ODE's to see which one fits the data the best.
def fitfunc(myfun,y0,Tx,params):
myfit = odeint(myfun, y0, Tx, args=(params,))
return myfit
#define a function that will measure the error between the fit and the real data:
def errfunc(params,myfun,y0,Tx,y):
"""
INPUTS:
params are the parameters for the ODE
myfun is the function to be integrated by odeint
y0 vector of initial conditions, so that y(t0) = y0
Tx is the vector over which integration occurs, since I have several data sets and each
one has its own vector of time points, Tx is a list of arrays.
y is the data, it is a list of arrays since I want to fit to multiple data sets at once
"""
res = []
for i in range(len(y)):
V0 = params[0][i]
myparams = params[1:]
initCond = np.zeros([3,])
initCond[:2] = y0[i]
initCond[2] = V0
myfit = fitfunc(myfun,initCond,Tx[i],myparams)
res.append(myfit[:,0] - y[i][:,0])
res.append(myfit[:,1] - y[i][:,1])
res.append(myfit[1:,2] - y[i][1:,2])
#end for
all_residuals = np.hstack(res).ravel()
return all_residuals
#end errfunc
#example of the problem:
V0 = [0]
params = [V0,beta,gamma]
y0 = [1000,1]
#this is just to test that my errfunc does work well.
errfunc(params,simpleSIR,[y0],[Tx],[mydata])
initguess = [V0,0.5,0.5]
p1,success = optimize.leastsq(errfunc, initguess, args=(simpleSIR,[y0[0]],[Tx],[mydata]))
The problem is with the variable initguess. The function optimize.leastsq has the following call signature:
http://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.leastsq.html
It's second argument, x0, has to be an array. Your list
initguess = [v0,0.5,0.5]
won't be converted to an array because v0 is a list instead of an int or float. So you get an error when you try to convert initguess from a list to an array in the leastsq function.
I would adjust the variable params from
def errfunc(params,myfun,y0,Tx,y):
so that it is a 1-D array. Make the first few entries the values of v0 then append beta and gamma to that.