Cannot solve simple non-linear differential equation with the control library - python

I wanted to implement a simple non-linear system to test the control library but I do get an error which I do not understand.
Example:
import control
import numpy as np
def simple_update(t, x, u, params={}):
dx = 3 * x[0]**2
return dx
io_simple = control.NonlinearIOSystem(simple_update,
None,
states=('x'),
name='simple')
X0 = 2 # Initial
time_sequence = np.linspace(0, 1, 10)
# Simulate the system
t, y = control.input_output_response(io_simple, time_sequence, 0, X0)
But it yields this error:
lib\site-packages\control\iosys.py", line 1624, in input_output_response
y[:, i] = sys._out(T[i], soln.y[:, i], u)
IndexError: index 2 is out of bounds for axis 1 with size 2
Does anyone understand the problem or can give me a hint how to debug this problem? Does it have something to do with the ode solver?

Related

Explicit Euler method is unable to complete the solution to a system of differential equations

I am trying to solve the following nonlinear system of differential equation with the explicit Euler method:
x' = f1(x,y),
y' = f2(x,y)
And I know the fact that the curve corresponding to the solution must connect (x_{initial},y_{initial}) to (0,1) in the x-y plane, but the obtained curve stops prematurely at around (0.17,0.98). I tried to vary the parameters but again I can't push that value any further towards (0,1). First, I thought my equations becomes stiff towards the end point; now it doesn't seem to be the case when I read about the stiff ODEs. What might be the problem?
The code I wrote in python is:
import math
import numpy as np
import matplotlib.pyplot as plt
q=1
#my f1 and f2 functions:
def l(lna,x,y,m,n,xi,yi):
return n *m**(-1)*(np.divide((yi**2)*(np.float64(1)-np.power(x,2)-np.power(y,2))*np.exp(3*(lna-lnai)),(y**2)*(1-xi**2-yi**2)))**(-1/n)
def f1 (x,y,l):
return -3*x + l*np.sqrt(3/2)* y**2+ 3/2 *x*(2*(x**2)+q*(1-x**2-y**2))
def f2 (x,y,l):
return -l*np.sqrt(3/2) *y*x + 3/2 *y*(2*x**2+q*(1-x**2-y**2))
#my code for the explicit Euler:
def e_E(xa,xb,dlna,m,n,xi,yi):
N = int(round((lnaf-lnai)/dlna))
lna = np.linspace(0, N*dlna, N+1)
x = np.empty(N+1)
y = np.empty(N+1)
x[0],y[0] = xi,yi
for i in range(N):
sd = l(lna[i],x[i],y[i],m,n,xi,yi)
x[i+1] = x[i] + dlna * f1(x[i],y[i],sd)
y[i+1] = y[i] + dlna * f2(x[i],y[i],sd)
return x,y,lna
#range for the independent variable (in my case it is lna)
lnai = np.float64(0)
lnaf = np.float64(15)
#step size
dlna = np.float64(1e-3)
#initial conditions
yi = np.float64(1e-5)
xi = 0
x1,y1,lna1 = e_E(lnai, lnaf, dlna, np.float64(0.1), np.float64(2), xi, yi)
plt.plot(x1,y1,'b',label = ('x1'))
plt.legend()
plt.grid()
plt.ylabel('y')
plt.xlabel('x')
plt.show()
My solution in the x-y plane:
Full/correct solution:

How to evaluate this line integral (Python-Sympy)

The idea is to compute the line integral of the following vector field and curve:
This is the code I have tried:
import numpy as np
from sympy import *
from sympy import Curve, line_integrate
from sympy.abc import x, y, t
C = Curve([cos(t) + 1, sin(t) + 1, 1 - cos(t) - sin(t)], (t, 0, 2*np.pi))
line_integrate(y * exp(x) + x**2 + exp(x) + z**2 * exp(z), C, [x, y, z])
But the ValueError: Function argument should be (x(t), y(t)) but got [cos(t) + 1, sin(t) + 1, -sin(t) - cos(t) + 1] comes up.
How can I compute this line integral then?
I think that maybe this line integral contains integrals that don't have exact solution. It is also fine if you provide a numerical approximation method.
Thanks
In this case you can compute the integral using line_integrate because we can reduce the 3d integral to a 2d one. I'm sorry to say I don't know python well enough to write the code, but here's the drill:
If we write
C(t) = x(t),y(t),z(t)
then the thing to notice is that
z(t) = 3 - x(t) - y(t)
and so
dz = -dx - dy
So, we can write
F.dr = Fx*dx + Fy*dy + Fz*dz
= (Fx-Fz)*dx + (Fy-Fz)*dy
So we have reduced the problem to a 2d problem: we integrate
G = (Fx-Fz)*i + (Fx-Fz)*j
round
t -> x(t), y(t)
Note that in G we need to get rid of z by substituting
z = 3 - x - y
The value error you receive does not come from your call to the line_integrate function; it comes because according to the source code for the Curve class, only functions in 2D Euclidean space are supported. This integral can still be computed without using sympy according to this research blog that I found by simply searching for a workable method on Google.
The code you need looks like this:
import autograd.numpy as np
from autograd import jacobian
from scipy.integrate import quad
def F(X):
x, y, z = X
return [y * np.exp(x), x**2 + np.exp(x), z**2 * np.exp(z)]
def C(t):
return np.array([np.cos(t) + 1, np.sin(t) + 1, 1 - np.cos(t) - np.sin(t)])
dCdt = jacobian(C, 0)
def integrand(t):
return F(C(t)) # dCdt(t)
I, e = quad(integrand, 0, 2 * np.pi)
The variable I then stores the numerical solution to your question.
You can define a function:
import sympy as sp
from sympy import *
def linea3(f,C):
P = f[0].subs([(x,C[0]),(y,C[1]),(z,C[2])])
Q = f[1].subs([(x,C[0]),(y,C[1]),(z,C[2])])
R = f[2].subs([(x,C[0]),(y,C[1]),(z,C[2])])
dx = diff(C[0],t)
dy = diff(C[1],t)
dz = diff(C[2],t)
m = integrate(P*dx+Q*dy+R*dz,(t,C[3],C[4]))
return m
Then use the example:
f = [x**2*z**2,y**2*z**2,x*y*z]
C = [2*cos(t),2*sin(t),4,0,2*sp.pi]

Solve equation in python over a given time interval with initial condition given

I want to solve the equation in python over the time Interval I = [0,10] with initial condition (x_0, y_0) = (1,0) and the parameter values μ ∈ {-2, -1, 0, 1, 2} using the function
scipy.integrate.odeint
Then I want to plot the solutions (x(t;x_0,y_0), y(t;x_0,y_0)) in the xy-plane.
The originally given linear system is
dx/dt = y, x(0) = x_0
dy/dt = - x - μy, y(0) = y_0
Please see my code below:
import numpy as np
from scipy.integrate import odeint
sol = odeint(myode, y0, t , args=(mu,1)) #mu and 1 are the coefficients when set equation to 0
y0 = 0
myode(y, t, mu) = -x-mu*y
def t = np.linspace(0,10, 101) #time interval
dydt = [y[1], -y[0] - mu*y[1]]
return dydt
Could anyone check if I defined the callable function myode correctly? This function evaluates the right hand side of the ODE.
Also an syntax error message showed up for this line of code
def t = np.linspace(0,10, 101) #time interval
saying there is invalid syntax. Should I somehow use
for * in **
to get rid of the error message? If yes, how exactly?
I am very new to Python and ODE. Could anyone help me with this question? Thank you very much!
myode should be a function definition, thus
def myode(u, t, mu): x,y = u; return [ y, -x-mu*y]
The time array is a simple variable declaration/assignment, there should be no def there. As the system is two-dimensional, the initial value also needs to have dimension two
sol = odeint(myode, [x0,y0], t, args=(mu,) )
Thus a minimal modification of your script is
def myode(u, t, mu): x,y = u; return [ y, -x-mu*y]
t = np.linspace(0,10, 101) #time interval
x0,y0 = 1,0 # initial conditions
for mu in [-2,-1,0,1,2]:
sol = odeint(myode, [x0,y0], t, args=(mu,) )
x,y = sol.T
plt.plot(x,y)
a=5; plt.xlim(-a,a); plt.ylim(-a,a)
plt.grid(); plt.show()
giving the plot
Try using the solve_ivp method.
from scipy.integrate import solve_ivp
import matplotlib.pyplot as plt
import numpy as np
i = 0
u = [-2,-1,0,1,2]
for x in u:
def rhs2(t,y):
return [y[1], -1*y[0] - u[x]*y[1]]
value = u[i]
res2 = solve_ivp(rhs2, [0,10], [1,0] , t_eval=[0,1,2,3,4,5,6,7,8,9,10], method = 'RK45')
t = np.array(res2.t[1:-1])
x = np.array(res2.y[0][1:-1])
y = np.array(res2.y[1][1:-1])
fig = plt.figure()
plt.plot(t, x, 'b-', label='X(t)')
plt.plot(t, y, 'g-', label='Y(t)')
plt.title("u = {}".format(value))
plt.legend(loc='lower right')
plt.show()
i = i + 1
Here is the solve_ivp method Documentation
Here is a very similar problem with a better explanation.

scipy cannot import integrate.solve_bvp

I have just installed scipy and tried few example codes. My scipy version is 0.17.0. But I can't figure out what's wrong going with scipy.integrate.solve_bvp. I am trying to run the following code from this link,
# In the second example we solve a simple Sturm-Liouville problem::
# y'' + k**2 * y = 0
# y(0) = y(1) = 0
# It is known that a non-trivial solution y = A * sin(k * x) is possible for
# k = pi * n, where n is an integer. To establish the normalization constant
# A = 1 we add a boundary condition::
# y'(0) = k
# Again we rewrite our equation as a first order system and implement its
# right-hand side evaluation::
# y1' = y2
# y2' = -k**2 * y1
import numpy as np
from scipy.integrate import solve_bvp
def fun(x, y, p):
k = p[0]
return np.vstack((y[1], -k**2 * y[0]))
# Note that parameters p are passed as a vector (with one element in our
# case).
# Implement the boundary conditions:
def bc(ya, yb, p):
k = p[0]
return np.array([ya[0], yb[0], ya[1] - k])
# Setup the initial mesh and guess for y. We aim to find the solution for
# k = 2 * pi, to achieve that we set values of y to approximately follow
# sin(2 * pi * x):
x = np.linspace(0, 1, 5)
y = np.zeros((2, x.size))
y[0, 1] = 1
y[0, 3] = -1
# Run the solver with 6 as an initial guess for k.
sol = solve_bvp(fun, bc, x, y, p=[6])
# We see that the found k is approximately correct:
sol.p[0]
# 6.28329460046
# And finally plot the solution to see the anticipated sinusoid:
x_plot = np.linspace(0, 1, 100)
y_plot = sol.sol(x_plot)[0]
plt.plot(x_plot, y_plot)
plt.xlabel("x")
plt.ylabel("y")
plt.show()
I am getting this error,
Traceback (most recent call last):
File "my.py", line 19, in <module>
from scipy.integrate import solve_bvp
ImportError: cannot import name solve_bvp
Why I am getting this error? Other scipy integrators like scipy.integrate.odeint, scipy.integrate.ode are working fine.
If you go to the documentation for the function, under the heading "Notes" you will see that the function is new as of version 0.18.0

Python solving 2nd order ODE with quad function

I am studying the dynamics of a damped, driven pendulum with second order ODE defined like so, and specifically I am progamming:
d^2y/dt^2 + c * dy/dt + sin(y) = a * cos(wt)
import numpy as np
import matplotlib.pyplot as plt
from scipy import integrate
def pendeq(t,y,a,c,w):
y0 = -c*y[1] - np.sin(y[0]) + a*np.cos(w*t)
y1 = y[1]
z = np.array([y0, y1])
return z
a = 2.1
c = 1e-4
w = 0.666667 # driving angular frequency
t = np.array([0, 5000]) # interval of integration
y = np.array([0, 0]) # initial conditions
yp = integrate.quad(pendeq, t[0], t[1], args=(y,a,c,w))
This problem does look quite similar to Need help solving a second order non-linear ODE in python, but I am getting the error
Supplied function does not return a valid float.
What am I doing wrong??
integrate.quad requires that the function supplied (pendeq, in your case) returns only a float. Your function is returning an array.

Categories

Resources