I don't know how to add this array to an ordinary differential equation. I don't know how to select for each time the corresponding item.
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
u = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29]
def f(z,t):
dzdt = np.zeros(2,)
x = z[0]
y = z[1]
dzdt[0] = (-x + u) / 2.0
dzdt[1] = (-y + x) / 5.0
return dzdt
z0 = [0,0]
n = 30
t = np.linspace(0,15, n)
u = np.zeros(n)
u[0] = 1
x = np.zeros(n)
y = np.zeros(n)
z = odeint(f,z0,t)
Related
I tried to solve this equation system that are two ordinary differential equations and a linear equation
dx(t)/dt = (-x(t) + u(t)) / 2.0,
dy(t)/dt = (-y(t) + x(t)) / 5.0
u(t) = x(t) + 3*y(t)
With this initial conditions x(0) = 0, y(0) = 0 and u(0)=1. I have been trying to solve the system using odeint but I don't know hoy to define the linear function, this is, the function u. I don't know if it is another way to solve this system.
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
def f(z,t,u):
dzdt = np.zeros(2,)
x = z[0]
y = z[1]
dzdt[0] = (-x + u) / 2.0
dzdt[1] = (-y + x) / 5.0
return dzdt
z0 = [0,0]
n = 150
t = np.linspace(0,15, n)
u = np.zeros(n)
u[0] = 1
x = np.zeros(n)
y = np.zeros(n)
for i in range (1,n):
tspan = [t[i-1],t[i]]
z = odeint(f,z0,t,args=(u[i],))
u[i] = x[i] + 3*y[i]
z0 = z[1]
x[i] = z0[0]
y[i] = z0[1]
plt.plot(t,u)
plt.plot(t,x)
plt.plot(t,y)
plt.show()
You can just substitute u into the other equations. Also these particular ODEs can be solved symbolically using SymPy:
In [34]: x, y, u = symbols('x, y, u', cls=Function)
In [35]: t = symbols('t')
In [36]: eqs = [Eq(x(t).diff(t), (-x(t) + u(t)) / 2.0),
...: Eq(y(t).diff(t), (-y(t) + x(t)) / 5.0),
...: Eq(u(t), x(t) + 3*y(t))]
In [37]: eqs[2]
Out[37]: u(t) = x(t) + 3⋅y(t)
In [38]: eqs_new = [eq.subs(eqs[2].lhs, eqs[2].rhs) for eq in eqs[:2]]
In [39]: eqs_new
Out[39]:
⎡d d ⎤
⎢──(x(t)) = 1.5⋅y(t), ──(y(t)) = 0.2⋅x(t) - 0.2⋅y(t)⎥
⎣dt dt ⎦
In [41]: dsolve(eqs_new)[0]
Out[41]:
-0.656776436283002⋅t 0.456776436283002⋅t
x(t) = - 2.28388218141501⋅C₁⋅ℯ + 3.28388218141501⋅C₂⋅ℯ
In [42]: dsolve(eqs_new)[1]
Out[42]:
-0.656776436283002⋅t 0.456776436283002⋅t
y(t) = 1.0⋅C₁⋅ℯ + 1.0⋅C₂⋅ℯ
I'm trying to make a diffraction plot using Simpson integration but this just plots a straight line. I know it's just evaluating a single number but I'd like it to make a diffraction pattern with the strongest maxima in the middle.
import math
import cmath
import numpy as np
import sympy as sym
import matplotlib.pyplot as plt
from scipy.integrate import simps
from scipy import integrate
from math import sin, cos, pi
n = 100 #Number of areas to be calculated for integration approximation
λ = 1*10**-6 #Wavelength
z = 0.02 #Screen distance
k = (2*math.pi)/λ #wave number
j = complex(cmath.sqrt(-1))
n = 100
b = 2E-5
a = 0
def f(x):
return np.exp((1j*k)/(2*z)*(x)**2)
x = np.linspace(-0.005, 0.005, 100)
y = np.linspace(0, 0, 100, dtype= "complex")
def g(p, q):
h = (b - a) / n
k = 0
z = 0
for i in range(1, n // 2):
k += 2 * f(a + 2 * i * h)
for i in range(1, n // 2 + 1):
z += 4 * f(a + (2 * i - 1) * h)
return h * (z+k+f(a)+f(b)) / 3.0
for i in range(0,100,n):
if( x[i] == 0 ):
y[i] = 0
else:
q = np.linspace(0,x[i],100)
p = f(q)
y[i] = abs(np.conj(g(p, q))*(g(p, q)))*8.85E-12
plt.plot(x, np.imag(y))
I wrote code for Runge-Kutta 4 for solving system of ODEs.
It works fine for 1-D ODE but when I try to solve x'' + kx = 0 I have a problem trying to define a vectorial function:
Let u1 = x and u2 = x' = u1', then the system looks like:
u1' = u2
u2' = -k*u1
If u = (u1,u2) and f(u, t) = (u2, -k*u1), then we need to solve:
u' = f(u, t)
def f(u,t, omega=2):
u, v = u
return np.asarray([v, -omega**2*u])
My entire code is:
import numpy as np
def ode_RK4(f, X_0, dt, T):
N_t = int(round(T/dt))
# Create an array for the functions ui
u = np.zeros((len(X_0),N_t+1)) # Array u[j,:] corresponds to the j-solution
t = np.linspace(0, N_t*dt, N_t + 1)
# Initial conditions
for j in range(len(X_0)):
u[j,0] = X_0[j]
# RK4
for j in range(len(X_0)):
for n in range(N_t):
u1 = f(u[j,n] + 0.5*dt* f(u[j,n], t[n])[j], t[n] + 0.5*dt)[j]
u2 = f(u[j,n] + 0.5*dt*u1, t[n] + 0.5*dt)[j]
u3 = f(u[j,n] + dt*u2, t[n] + dt)[j]
u[j, n+1] = u[j,n] + (1/6)*dt*( f(u[j,n], t[n])[j] + 2*u1 + 2*u2 + u3)
return u, t
def demo_exp():
import matplotlib.pyplot as plt
def f(u,t):
return np.asarray([u])
u, t = ode_RK4(f, [1] , 0.1, 1.5)
plt.plot(t, u[0,:],"b*", t, np.exp(t), "r-")
plt.show()
def demo_osci():
import matplotlib.pyplot as plt
def f(u,t, omega=2):
# u, v = u Here I've got a problem
return np.asarray([v, -omega**2*u])
u, t = ode_RK4(f, [2,0], 0.1, 2)
for i in [1]:
plt.plot(t, u[i,:], "b*")
plt.show()
In advance, thank you.
You are on the right path, but when applying time-integration methods such as RK to vector valued ODEs, one essentially does the exact same thing as in the scalar case, just with vectors.
Thus, you skip the for j in range(len(X_0)) loop and associated indexation and you make sure that you pass initial values as vectors (numpy arrays).
Also cleaned up the indexation for t a little and stored the solution in a list.
import numpy as np
def ode_RK4(f, X_0, dt, T):
N_t = int(round(T/dt))
# Initial conditions
usol = [X_0]
u = np.copy(X_0)
tt = np.linspace(0, N_t*dt, N_t + 1)
# RK4
for t in tt[:-1]:
u1 = f(u + 0.5*dt* f(u, t), t + 0.5*dt)
u2 = f(u + 0.5*dt*u1, t + 0.5*dt)
u3 = f(u + dt*u2, t + dt)
u = u + (1/6)*dt*( f(u, t) + 2*u1 + 2*u2 + u3)
usol.append(u)
return usol, tt
def demo_exp():
import matplotlib.pyplot as plt
def f(u,t):
return np.asarray([u])
u, t = ode_RK4(f, np.array([1]) , 0.1, 1.5)
plt.plot(t, u, "b*", t, np.exp(t), "r-")
plt.show()
def demo_osci():
import matplotlib.pyplot as plt
def f(u,t, omega=2):
u, v = u
return np.asarray([v, -omega**2*u])
u, t = ode_RK4(f, np.array([2,0]), 0.1, 2)
u1 = [a[0] for a in u]
for i in [1]:
plt.plot(t, u1, "b*")
plt.show()
The model is this:
enter image description here
From the Langtangen’s book Programming for Computations - Python.
Currently, I solve the following ODE system of equations using odeint
dx/dt = (-x + u)/2.0
dy/dt = (-y + x)/5.0
initial conditions: x = 0, y = 0
However, I would like to use solve_ivp which seems to be the recommended option for this type of problems, but honestly I don't know how to adapt the code...
Here is the code I'm using with odeint:
import numpy as np
from scipy.integrate import odeint, solve_ivp
import matplotlib.pyplot as plt
def model(z, t, u):
x = z[0]
y = z[1]
dxdt = (-x + u)/2.0
dydt = (-y + x)/5.0
dzdt = [dxdt, dydt]
return dzdt
def main():
# initial condition
z0 = [0, 0]
# number of time points
n = 401
# time points
t = np.linspace(0, 40, n)
# step input
u = np.zeros(n)
# change to 2.0 at time = 5.0
u[51:] = 2.0
# store solution
x = np.empty_like(t)
y = np.empty_like(t)
# record initial conditions
x[0] = z0[0]
y[0] = z0[1]
# solve ODE
for i in range(1, n):
# span for next time step
tspan = [t[i-1], t[i]]
# solve for next step
z = odeint(model, z0, tspan, args=(u[i],))
# store solution for plotting
x[i] = z[1][0]
y[i] = z[1][1]
# next initial condition
z0 = z[1]
# plot results
plt.plot(t,u,'g:',label='u(t)')
plt.plot(t,x,'b-',label='x(t)')
plt.plot(t,y,'r--',label='y(t)')
plt.ylabel('values')
plt.xlabel('time')
plt.legend(loc='best')
plt.show()
main()
It's important that solve_ivp expects f(t, z) as right-hand side of the ODE. If you don't want to change your ode function and also want to pass your parameter u, I recommend to define a wrapper function:
def model(z, t, u):
x = z[0]
y = z[1]
dxdt = (-x + u)/2.0
dydt = (-y + x)/5.0
dzdt = [dxdt, dydt]
return dzdt
def odefun(t, z):
if t < 5:
return model(z, t, 0)
else:
return model(z, t, 2)
Now it's easy to call solve_ivp:
def main():
# initial condition
z0 = [0, 0]
# number of time points
n = 401
# time points
t = np.linspace(0, 40, n)
# step input
u = np.zeros(n)
# change to 2.0 at time = 5.0
u[51:] = 2.0
res = solve_ivp(fun=odefun, t_span=[0, 40], y0=z0, t_eval=t)
x = res.y[0, :]
y = res.y[1, :]
# plot results
plt.plot(t,u,'g:',label='u(t)')
plt.plot(t,x,'b-',label='x(t)')
plt.plot(t,y,'r--',label='y(t)')
plt.ylabel('values')
plt.xlabel('time')
plt.legend(loc='best')
plt.show()
main()
Note that without passing t_eval=t, the solver will automatically choose the time points inside tspan at which the solution will be stored.
I try to use Lagrange multiplier to optimize a function, and I am trying to loop through the function to get a list of number, however I got the error
ValueError: setting an array element with a sequence.
Here is my code, where do I go wrong? If the n is not an array I can get the result correctly though
import numpy as np
from scipy.optimize import fsolve
n = np.arange(10000,100000,10000)
def func(X):
x = X[0]
y = X[1]
L = X[2]
return (x + y + L * (x**2 + y**2 - n))
def dfunc(X):
dLambda = np.zeros(len(X))
h = 1e-3
for i in range(len(X)):
dX = np.zeros(len(X))
dX[i] = h
dLambda[i] = (func(X+dX)-func(X-dX))/(2*h);
return dLambda
X1 = fsolve(dfunc, [1, 1, 0])
print (X1)
Helps would be appreciated, thank you very much
First, check func = fsolve()
Second, print(func([1,1,0]))` - result in not number ([2 2 2 2 2 2 2 2 2]), beause "n" is list. if you want to iterate n try:
import numpy as np
from scipy.optimize import fsolve
n = np.arange(10000,100000,10000)
def func(X,n):
x = X[0]
y = X[1]
L = X[2]
return (x + y + L * (x**2 + y**2 - n))
def dfunc(X,n):
dLambda = np.zeros(len(X))
h = 1e-3
r = 0
for i in range(len(X)):
dX = np.zeros(len(X))
dX[i] = h
dLambda[i] = (func(X+dX,n)-func(X-dX,n))/(2*h)
return dLambda
for iter_n in n:
print("for n = {0} dfunc = {1}".format(iter_n,dfunc([0.8,0.4,0.3],iter_n)))