ODE boundary value problem with singularities - python

Here is a relatively simple boundary value problem solved with shooting method and Python
import numpy as np
from scipy.optimize import fsolve
from scipy.integrate import odeint
import matplotlib.pyplot as plt
%matplotlib inline
R = 0.5
ka = 6.4
De = 0.1
Cas = 0.2
def odefun(U, r):
Ca, Na = U
dCa = -Na/De
if np.abs(r) <= 1e-10:
dNa = ka/3*Ca
else:
dNa = -2/r*Na-ka*Ca
return [dCa, dNa]
r = np.linspace(0, R)
Na_0 = 0
Ca_R = 0.2
def objective(x):
U = odeint(odefun, [x, Na_0], r)
u = U[-1,0]-Ca_R
return u
x0 = 0.1 #initial guess
x, = fsolve(objective, x0)
print ("Ca_0=",x)
U = odeint(odefun, [x, Na_0], r)
print ("r=0 =>",U[0])
print ("r=R =>",U[-1])
plt.plot(t.value,Ca.value)
plt.plot(t.value,Na.value)
The system is singular at r=0 (divison by zero) and we took care about this by defining limiting dNa at the boundary r=0
dNa = ka/3*Ca
Other methods are possible to solve this numerically (using r as a small number at the boundary, dividing by r+small number)
Solving the same problem in Gekko ignoring the singular boundary problem might be this way
#Boundary value problem
import numpy as np
from gekko import GEKKO
import matplotlib.pyplot as plt
R = 0.5
ka = 6.4
De = 0.1
Cas = 0.2
Na_0 = 0
Ca_R = 0.2
m = GEKKO()
nt = 101
m.time = np.linspace(0,R,nt) # time points
Na = m.Var(Na_0) # known at r=0
Ca = m.Var(fixed_initial=False) # unknown at r=0
pi = np.zeros(nt)
pi[-1]=1
p = m.Param(value=pi)
# create GEEKO equations
t = m.Var(m.time)
m.Equation(t.dt() == 1)
m.Equation(Na.dt() == -2/t*Na-ka*Ca)
m.Equation(Ca.dt() == -Na/De)
m.Minimize(p*(Ca - Ca_R)**2) # minimizing at r=R
# solve ODE
m.options.IMODE = 6
m.options.NODES = 7
m.solve(disp=False)
# plot results
print ("r=0 =>",Ca[0],Na[0])
print ("r=R =>",Ca[-1],Na[-1])
plt.plot(r,U[:,1])
plt.plot(r,U[:,0])
Gekko will not complain about singularity at the boundary and will solve this.
Both Pythone and Gekko will solve this satisfying boundary conditions
Python
r=0 => [0.02931475 0. ]
r=R => [ 0.2 -0.12010739]
Gekko
r=0 => 0.029314856906 0.0
r=R => 0.2 -0.12010738377
I do not know how to include the singularity at he boundary in Gekko. On the other hand, Gekko gave the result, did not complain about the singularity and boundary conditions are satisfied Na(0)=0, Ca(R)=0.2.
I suppose that collocation method can successfully avoid the problem with singularities at the boundaries, but I would like the confirmation whether this is correct or not in Gekko - just to ignore it.
What could be done about this?
Best Regards,
Radovan

One way to overcome most divide-by-zero issues is to reform the equation by multiplying both sides by the denominator such as:
#m.Equation(Na.dt() == -2/t*Na-ka*Ca)
m.Equation(t*Na.dt() == -2*Na-t*ka*Ca)
When t=0, the equation is 0==-2*Na. With the initial condition Na.value=0 with Na = m.Var(Na_0), this equation is satisfied even though Gekko doesn't include the equations at the initial time point.
This isn't a problem but the valid range of nodes is 2 to 6 so when m.options.NODES = 7 the actual nodes used is 6.
Your problem looks correct. Try the m.fix_final(Ca,Ca_R) to ensure that the final condition is satisfied.

Related

GEKKO returned non-optimal solution

I want to use GEKKO to solve the following optimization problem:
Minimize x'Qx + 1e-10 * sum_{i=1}^n x_i^0.1
subject to 1' x = 1 and x >= 0
However, the following code returns sol = [0., 0., 0. ,0. ,1.] and Objective: 1.99419 as a solution. Which is far from optimal, I'll explain why below.
import numpy as np
from gekko import GEKKO
n = 5
m = GEKKO(remote=False)
m.options.SOLVER = 1
m.options.IMODE = 3
x = [m.Var(lb=0, ub=1) for _ in range(n)]
m.Equation(m.sum(x) == 1)
np.random.seed(0)
Q = np.random.uniform(-1, 1, size=(n, n))
Q = np.dot(Q.T, Q)
## Add h_i^p
c, p = 1e-10, 0.1
for i in range(n):
m.Obj(c * x[i] ** p)
for j in range(n):
m.Obj(x[i] * Q[i, j] * x[j])
m.solve(disp=True)
sol = np.array(x).flatten()
This is clearly wrong since if we only optimize the quadratic part (x'Qx) using below code, and put the solution to the initial objective, we get a much smaller objective value (Objective: 0.02489503). The 1e-10 * sum_{i=1}^n x_i^p is esentially ignored since it is very small.
m1 = GEKKO(remote=False)
m1.options.SOLVER = 1
m1.options.OTOL = 1e-10
x1 = [m1.Var(lb=0, ub=1) for _ in range(n)]
m1.Equation(m1.sum(x1) == 1)
m1.qobj(b=np.zeros(n), A=2 * Q, x=x1, otype='min')
m1.solve(disp=True)
sol = np.array(x1).flatten()
Is there any way to resolve this? Thank you!
Gekko solves nonlinear programming optimization problems with gradient-based methods: interior point and active set SQP. It looks like there is a problem with the objective function. Use matrix operations in Numpy to simplify the objective definition.
## Create Objective
c, p = 1e-10, 0.1
obj = np.dot(np.dot(x,Q),x) + c*m.sum([xi**p for xi in x])
m.Minimize(obj)
Here is the modified script that solves with Gekko. Increase MAX_ITER if the default limit of 250 is reached.
import numpy as np
from gekko import GEKKO
n = 5
m = GEKKO(remote=False)
m.options.SOLVER = 3
m.options.IMODE = 3
x = m.Array(m.Var,n,value=0.1, lb=1e-6, ub=1)
m.Equation(m.sum(x) == 1)
np.random.seed(0)
Q = np.random.uniform(-1, 1, size=(n, n))
Q = np.dot(Q.T, Q)
print(Q)
## Create Objective
c, p = 1e-10, 0.1
obj = np.dot(np.dot(x,Q),x) + c*m.sum([xi**p for xi in x])
m.Minimize(obj)
# adjust solver tolerance
m.options.RTOL=1e-10
m.options.OTOL=1e-10
m.options.MAX_ITER = 1000
m.solve(disp=True)
sol = np.array(x).flatten()
print('x: ', sol)
print('obj: ', m.options.OBJFCNVAL)
This gives an optimal solution that is also global because it is a Quadratic Programming (QP) problem (convex optimization). Using a nonlinear programming (SQP) solver for QP problems gives a solution with the IPOPT solver:
x: [[0.36315827507] [0.081993130341] [1e-06] [0.086231281612] [0.46861632269]]
obj: 0.024895918696
As far as I could see, gekko looks like it's built for machine learning, which focuses on local optimization opposed to global optimization, and typically most libraries will not be able to guarantee you optimal solutions.
If you really want optimal solutions, than for this case I would suggest looking into interval arithmetic. There are packages such as mpmath which can offer this, though I have yet to see optimizers using it in my brief time searching.
The TL;DR on how interval arithmetic works is you feed in a range of inputs and get back a range of outputs. For example, you can test if 1 is in the range of possible outputs for x1 + x2 + x3 + x4, and you can see the minimum/maximum potential values for your objective function. In this way, you can progressively split your intervals in half, keeping only intervals for which your constraints are potentially satisfied and for which your objective function's maximum potential is at least the largest minimum potential. This allows you to achieve guaranteed convergence to global optimums at the cost of a lot more computation.

Simulating an elementary stochastic process in Python

I'm trying to simulate a simple stochastic process in Python, but with no success. The process is the following:
x(t + δt) = r(t) * x(t)
where r(t) is a Bernoulli random variable that can assume the values 1.5 or 0.6.
I've tried the following:
n = 10
r = np.zeros( (1,n))
for i in range(0, n, 1):
if r[1,i] == r[1,0]:
r[1,i] = 1
else:
B = bernoulli.rvs(0.5, size=1)
if B == 0:
r[1,i] = r[1,i-1] * 0.6
else:
r[1,i] = r[1,i-1] * 1.5
Can you explain why this is wrong and a possible solution?
So , first thing is that the SDE should be perceived over time, so you also need to consider the discretization rather than just giving the number of steps through n .
Essentially, what you are asking is just a simple random walk with a Bernoulli random variable taking on the values 0.5 and 1.6 instead of a Gaussian (standard normal) random variable.
So I have created an answer here, using NumPy to create the Bernoulli random variable for efficiency (numpy is faster than scipy) and then running the simulation with a stepsize of 0.01 then plotting the solution using matplotlib.
One thing to note that this SDE is one dimensional so we can just store the state and time in separate vectors and plot them at the end.
# Function generating bernoulli trial (your r(t))
def get_bernoulli(p=0.5):
'''
Function using numpy (faster than scipy.stats)
to generate bernoulli random variable with values 0.5 or 1.6
'''
B = np.random.binomial(1, p, 1)
if B == 0:
return 0.6
else:
return 1.5
This is then used in the simulation as
import numpy as np
import matplotlib.pyplot as plt
dt = 0.01 #step size
x0 = 1# initialize
tfinal = 1
sqrtdt = np.sqrt(dt)
n = int(tfinal/dt)
# State and time vectors
xtraj = np.zeros(n+1, float)
trange = np.linspace(start=0,stop=tfinal ,num=n+1)
# initialized
xtraj[0] = x0
for i in range(n):
xtraj[i+1] = xtraj[i] * get_bernoulli(p=0.5)
plt.plot(trange,xtraj,label=r'$x(t)$')
plt.xlabel("time")
plt.ylabel(r"$X$")
plt.legend()
plt.show()
Where we assumed the Bernoulli trial is fair, but can be customized to add some more variation.

Gekko: Problem with the obtained solution

I am trying to solve the following Optimal Control Problem in GEKKO:
I know a priori that the path for c is:
where the parameter values are: r = 0.33, i = 0.5, K(0) = 10 and T = 10.
I wrote the following code in Python:
import numpy as np
import matplotlib.pyplot as plt
from gekko import GEKKO
m = GEKKO(remote=True)
nt = 101; m.time = np.linspace(0,10,nt)
r = 0.33
i = 0.5
# Variables
c = m.Var()
k = m.Var(value=10)
objective = m.Var()
rate = [-r*t/10 for t in range(0, 101)]
factor = m.exp(rate)
p = np.zeros(nt)
p[-1] = 1.0
final = m.Param(value=p)
disc = m.Param(value=factor)
# Equations
m.Equation(k.dt() == i*k - c)
m.Equation(objective.dt() == disc*m.log(c))
# Objective Function
m.Maximize(final*objective)
m.options.IMODE = 6
m.solve()
plt.figure(1)
plt.plot(m.time,c.value,'k:',LineWidth=2,label=r'$C$')
plt.plot(m.time,k.value,'b-',LineWidth=2,label=r'$K$')
plt.legend(loc='best')
plt.xlabel('Time')
plt.ylabel('Value')
plt.show()
The solved path for c and k is as shown below:
This clearly is not right because c should be increasing with time from just eye-balling the solution given before hand.
I'm not sure where I am wrong.
The optimal control problem as it is currently written is unbounded. The value of c will go to infinity to maximize the function. I set an upper bound of 100 on c and the solver went to that bound. I reformulated the model to reflect the current problem statement. Here are a few suggestions:
Use the m.integral() function to make the model more readable.
Initialize c at a value other than 0 (default). You may also want to set a lower bound with c>0.01 so that m.log(c) is not undefined if the solver tries a value <0.
Only use Gekko functions inside Gekko equations such as with factor = m.exp(rate). Use factor = np.exp(rate) instead unless it is in a Gekko equation where it can be evaluated.
Include a plot of the exact solution so that you can compare the exact and numerical solution.
Use m.options.NODES=3 with c=m.MV() and c.STATUS=1 to increase the solution accuracy. The default is m.options.NODES=2 that isn't as accurate.
You can free the initial condition with m.free_initial(c) to calculate the initial value of c.
import numpy as np
import matplotlib.pyplot as plt
from gekko import GEKKO
m = GEKKO(remote=True)
nt = 101; m.time = np.linspace(0,10,nt)
r = 0.33
i = 0.5
# Variables
c = m.MV(4,lb=0.01,ub=100); c.STATUS=1
#m.free_initial(c)
k = m.Var(value=10)
objective = m.Var(0)
t = m.Param(m.time)
m.Equation(objective==m.exp(-r*t)*m.log(c))
# just to include on the plot
iobj = m.Intermediate(m.integral(objective))
p = np.zeros(nt)
p[-1] = 1.0
final = m.Param(value=p)
# Equations
m.Equation(k.dt() == i*k - c)
# Objective Function
m.Maximize(final*m.integral(objective))
m.options.IMODE = 6
m.solve()
plt.figure(1)
plt.subplot(3,1,1)
plt.plot(m.time,c.value,'k:',linewidth=2,label=r'$C_{gekko}$')
C_sol = r*10*np.exp((i-r)*m.time)/(1-np.exp(-r*10))
plt.plot(m.time,C_sol,'r--',linewidth=2,label=r'$C_{exact}$')
plt.ylabel('Value'); plt.legend(loc='best')
plt.subplot(3,1,2)
plt.plot(m.time,k.value,'b-',linewidth=2,label=r'$K$')
plt.legend(loc='best')
plt.subplot(3,1,3)
plt.plot(m.time,objective.value,'g:',linewidth=2,label=r'$obj$')
plt.plot(m.time,iobj.value,'k',linewidth=2,label=r'$\int obj$')
plt.legend(loc='best')
plt.xlabel('Time')
plt.show()
Is there additional information that this problem is missing?
Edit: Added additional constraint k>0.
Added additional constraint as suggested in the comment. There is a small difference at the end from the exact solution because the last c value does not appear to influence the solution.
import numpy as np
import matplotlib.pyplot as plt
from gekko import GEKKO
m = GEKKO(remote=True)
nt = 101; m.time = np.linspace(0,10,nt)
r = 0.33
i = 0.5
# Variables
c = m.MV(4,lb=0.001,ub=100); c.STATUS=1; c.DCOST=1e-6
m.free_initial(c)
k = m.Var(value=10,lb=0)
objective = m.Var(0)
t = m.Param(m.time)
m.Equation(objective==m.exp(-r*t)*m.log(c))
# just to include on the plot
iobj = m.Intermediate(m.integral(objective))
p = np.zeros(nt)
p[-1] = 1.0
final = m.Param(value=p)
# Equations
m.Equation(k.dt() == i*k - c)
# Objective Function
m.Maximize(final*m.integral(objective))
m.options.IMODE = 6
m.options.NODES = 3
m.solve()
plt.figure(1)
plt.subplot(3,1,1)
plt.plot(m.time,c.value,'k:',linewidth=2,label=r'$C_{gekko}$')
C_sol = r*10*np.exp((i-r)*m.time)/(1-np.exp(-r*10))
plt.plot(m.time,C_sol,'r--',linewidth=2,label=r'$C_{exact}$')
plt.ylabel('Value'); plt.legend(loc='best')
plt.subplot(3,1,2)
plt.plot(m.time,k.value,'b-',linewidth=2,label=r'$K$')
plt.legend(loc='best')
plt.subplot(3,1,3)
plt.plot(m.time,objective.value,'g:',linewidth=2,label=r'$obj$')
plt.plot(m.time,iobj.value,'k',linewidth=2,label=r'$\int obj$')
plt.legend(loc='best')
plt.xlabel('Time')
plt.show()

I am newbie in python and doing coding for my physics project which requires to generate a matrix with a variable E

I am newbie in python and doing coding for my physics project which requires to generate a matrix with a variable E for which first element of the matrix has to be solved. Please help me. Thanks in advance.
Here is the part of code
import numpy as np
import pylab as pl
import math
import cmath
import sympy as sy
from scipy.optimize import fsolve
#Constants(Values at temp 10K)
hbar = 1.055E-34
m0=9.1095E-31 #free mass of electron
q= 1.602E-19
v = [0.510,0,0.510] # conduction band offset in eV
m1= 0.043 #effective mass in In_0.53Ga_0.47As
m2 = 0.072 #effective mass in Al_0.48In_0.52As
d = [-math.inf,100,math.inf] # dimension of structure in nanometers
'''scaling factor to with units of E in eV, mass in terms of free mass of electron, length in terms
of nanometers '''
s = (2*q*m0*1E-18)/(hbar)**2
#print('scaling factor is ',s)
E = sy.symbols('E') #Suppose energy of incoming particle is 0.3eV
m = [0.043,0.072,0.043] #effective mass of electrons in layers
for i in range(3):
print ('Effective mass of e in layer', i ,'is', m[i])
k=[ ] #Defining an array for wavevectors in different layers
for i in range(3):
k.append(sy.sqrt(s*m[i]*(E-v[i])))
print('Wave vector in layer',i,'is',k[i])
x = []
for i in range(2):
x.append((k[i+1]*m[i])/(k[i]*m[i+1]))
# print(x[i])
#Define Boundary condition matrix for two interfaces.
D0 = (1/2)*sy.Matrix([[1+x[0],1-x[0]], [1-x[0], 1+x[0]]], dtype = complex)
#print(D0)
#A = sy.matrix2numpy(D0,dtype=complex)
D1 = (1/2)*sy.Matrix([[1+x[1],1-x[1]], [1-x[1], 1+x[1]]], dtype = complex)
#print(D1)
#a=eye(3,3)
#print(a)
#Define Propagation matrix for 2nd layer or quantum well
#print(d[1])
#print(k[1])
P1 = 1*sy.Matrix([[sy.exp(-1j*k[1]*d[1]), 0],[0, sy.exp(1j*k[1]*d[1])]], dtype = complex)
#print(P1)
print("abs")
T= D0*P1*D1
#print('Transfer Matrix is given by:',T)
#print('Dimension of tranfer matrix T is' ,T.shape)
#print(T[0,0]
# I want to solve T{0,0} = 0 equation for E
def f(x):
return T[0,0]
x0= 0.5 #intial guess
x = fsolve(f, x0)
print("E is",x)
'''
y=sy.Eq(T[0,0],0)
z=sy.solve(y,E)
print('z',z)
'''
**The main part i guess is the part of the code where i am trying to solve the equation.***Steps I am following:
Defining a symbol E by using sympy
Generating three matrices which involves sum formulae and with variable E
Generating a matrix T my multiplying those 3 matrices,note that elements are complex and involves square roots of negative number.
I need to solve first element of this matrix T[0,0]=0,for variable E and find out value of E. I used fsolve for soving T[0,0]=0.*
Just a note for future questions, please leave out unused imports such as numpy and leave out zombie code like # a = eye(3,3). This helps keep the code as clean and short as possible. Also, the sample code would not run because of indentation problems, so when you copy and paste code, make sure it works before you do so. Always try to make your questions as short and modular as possible.
The expression of T[0,0] is too complex to solve analytically by SymPy so numerical approximation is needed. This leaves 2 options:
using SciPy's solvers which are advanced but require type casting to float values since SciPy does not deal with SymPy objects in any way.
using SymPy's root solvers which are less advanced but are probably simpler to use.
Both of these will only ever produce a single number as output since you can't expect numeric solvers to find every root. If you wanted to find more than one, then I advise that you use a list of points that you want to use as initial values, input each of them into the solvers and keep track of the distinct outputs. This will however never guarantee that you have obtained every root.
Only mix SciPy and SymPy if you are comfortable using both with no problems. SciPy doesn't play at all with SymPy and you should only have list, float, and complex instances when working with SciPy.
import math
import sympy as sy
from scipy.optimize import newton
# Constants(Values at temp 10K)
hbar = 1.055E-34
m0 = 9.1095E-31 # free mass of electron
q = 1.602E-19
v = [0.510, 0, 0.510] # conduction band offset in eV
m1 = 0.043 # effective mass in In_0.53Ga_0.47As
m2 = 0.072 # effective mass in Al_0.48In_0.52As
d = [-math.inf, 100, math.inf] # dimension of structure in nanometers
'''scaling factor to with units of E in eV, mass in terms of free mass of electron, length in terms
of nanometers '''
s = (2 * q * m0 * 1E-18) / hbar ** 2
E = sy.symbols('E') # Suppose energy of incoming particle is 0.3eV
m = [0.043, 0.072, 0.043] # effective mass of electrons in layers
for i in range(3):
print('Effective mass of e in layer', i, 'is', m[i])
k = [] # Defining an array for wavevectors in different layers
for i in range(3):
k.append(sy.sqrt(s * m[i] * (E - v[i])))
print('Wave vector in layer', i, 'is', k[i])
x = []
for i in range(2):
x.append((k[i + 1] * m[i]) / (k[i] * m[i + 1]))
# Define Boundary condition matrix for two interfaces.
D0 = (1 / 2) * sy.Matrix([[1 + x[0], 1 - x[0]], [1 - x[0], 1 + x[0]]], dtype=complex)
D1 = (1 / 2) * sy.Matrix([[1 + x[1], 1 - x[1]], [1 - x[1], 1 + x[1]]], dtype=complex)
# Define Propagation matrix for 2nd layer or quantum well
P1 = 1 * sy.Matrix([[sy.exp(-1j * k[1] * d[1]), 0], [0, sy.exp(1j * k[1] * d[1])]], dtype=complex)
print("abs")
T = D0 * P1 * D1
# did not converge for 0.5
x0 = 0.75
# method 1:
def f(e):
# evaluate T[0,0] at e and remove all sympy related things.
result = complex(T[0, 0].replace(E, e))
return result
solution1 = newton(f, x0)
print(solution1)
# method 2:
solution2 = sy.nsolve(T[0,0], E, x0)
print(solution2)
This prints:
(0.7533104353644469-0.023775286117722193j)
1.00808496181754 - 0.0444042144405285*I
Note that the first line is a native Python complex instance while the second is an instance of SymPy's complex number. One can convert the second simply with print(complex(solution2)).
Now, you'll notice that they produce different numbers but both are correct. This function seems to have a lot of zeros as can be shown from the Geogebra plot:
The red axis is Re(E), green is Im(E) and blue is |T[0,0]|. Each of those "spikes" are probably zeros.

Optimal trajectory to minimize force, issues with final conditions

I am trying to find a trajectory that minimizes the squared integral of the force to move a block from one point to another. Here are the system dynamics:
dx/dt = v (derivative of position is velocity)
dv/dt = u (derivative of velocity is acceleration, which is what I am trying to minimize)
min integral of u**2
The initial conditions and final conditions are:
x(0) = 0, v(0) = 0
x(1) = 1, v(1) = 1
I have implemented this in python using the Gekko library, but I cannot get the final conditions working properly. Using m.fix() to fix the end position makes the problem unsolvable.
Reading online, I used m.Minimize() to make a soft constraint, but the solution was very far off from the end conditions. I added an extra equation to make the velocity less than zero at the end, and that made the solution look like the correct solution, albeit the end position was wrong (if the solution was scaled by a factor, it would be correct).
I should I properly solve this problem?
from gekko import GEKKO
import numpy as np
import matplotlib.pyplot as plt
##model
m = GEKKO() # initialize gekko
nt = 101
m.time = np.linspace(0,1,nt)
# Variables
x = m.Var(value=0)
v = m.Var(value=0)
u = m.Var( fixed_initial=False)
p = np.zeros(nt) # mark final time point
p[-1] = 1.0
final = m.Param(value=p)
# Equations
m.Equation(x.dt()==v)
m.Equation(v.dt()==u)
#m.Equation(x*final >= 1) ##error: Solution Not Found
m.Equation(v*final <= 0)
m.Minimize(final*(x-1)**2)
m.Minimize(final*(v-0)**2)
m.Obj(m.integral(u**2)*final) # Objective function
m.options.IMODE = 6 # optimal control mode
##solve
m.solve() # solve
##plot
plt.figure(1) # plot results
plt.plot(m.time,x.value,'k-',label=r'$x$')
plt.plot(m.time,v.value,'b-',label=r'$v$')
plt.plot(m.time,u.value,'r--',label=r'$u$')
plt.legend(loc='best')
plt.xlabel('Time')
plt.ylabel('Value')
##show plot
plt.show()
Plot of my results
You can fix the problem by putting a higher weight on the final conditions:
m.Minimize(final*1e5*(x-1)**2)
m.Minimize(final*1e5*(v-0)**2)
There is still some tradeoff with the u minimization but it is minimal.
The constraint m.Equation(x*final >= 1) is infeasible when final=0 because this results in the inequality 0 >= 1. If you'd like to use the final position constraint, you'll need to use m.Equation((x-1)*final >= 0) so that the constraint is enforced only at the end but is feasible (0 >= 0) elsewhere. You don't necessarily need the hard constraints with the soft (objective function) constraints for the final condition. Here is a related problem with an inverted pendulum.
from gekko import GEKKO
import numpy as np
import matplotlib.pyplot as plt
m = GEKKO() # initialize gekko
nt = 101; m.time = np.linspace(0,1,nt)
# Variables
x = m.Var(value=0)
v = m.Var(value=0)
u = m.Var(fixed_initial=False)
p = np.zeros(nt) # mark final time point
p[-1] = 1.0
final = m.Param(value=p)
# Equations
m.Equation(x.dt()==v)
m.Equation(v.dt()==u)
m.Equation((x-1)*final >= 0)
m.Equation(v*final <= 0)
m.Minimize(final*1e5*(x-1)**2)
m.Minimize(final*1e5*(v-0)**2)
m.Obj(m.integral(u**2)*final) # Objective function
m.options.IMODE = 6 # optimal control mode
m.solve() # solve
plt.figure(1) # plot results
plt.grid()
plt.plot(m.time,x.value,'k-',label=r'$x$')
plt.plot(m.time,v.value,'b-',label=r'$v$')
plt.plot(m.time,u.value,'r--',label=r'$u$')
plt.legend(loc='best')
plt.xlabel('Time')
plt.ylabel('Value')
plt.show()

Categories

Resources