I am trying to solve a simple ODE so as to understand the new API of Scipy.
I wrote a routine for Runge Kutta of order 4 to write it and confirmed it with the old API odeint and it matched beautifully. But now that I am trying to get around the solve_ivp, it seems that is not working. What am I getting wrong?
import numpy as np
from matplotlib import pyplot as plt
from scipy.integrate import solve_ivp, odeint
import time
freq = np.arange(1, 10000, 100)
def g(q, t):
return -q ** 3 + np.sin(t)
a = 0
b = 10
npoints = 100
h = (b - a) / npoints
t = np.arange(a, b, h)
output1 = np.zeros(t.shape)
x = 0
for i in range(len(t)):
output1[i] = x
k1 = h * g(x, t[i])
k2 = h * g(x + 0.5 * k1, t[i] + 0.5 * h)
k3 = h * g(x + 0.5 * k2, t[i] + 0.5 * h)
k4 = h * g(x + k3, t[i] + 0.5 * h)
x = x + 1 / 6 * (k1 + 2 * k2 + 2 * k3 + k4)
# ---------------Solving using odeint (old API)---------------#
y1_odeint = odeint(g, 0, t)
#---------------Solving using new API-------------#
y2=solve_ivp(g,(a,b),[0],t_eval=t)
# --------------------Representação gráfica--------------------------#
fig = plt.figure()
ax = fig.add_subplot(121)
ax1=fig.add_subplot(122)
ax.plot(t, output1,label="my own")
ax.plot(t,y1_odeint,label="odeint")
ax.plot(y2.t,np.squeeze(y2.y),label="new API")
ax.legend()
ax.set_title("Output")
ax1.plot(t,output1-np.squeeze(y1_odeint),label="|odeint-my own|")
ax1.legend()
plt.tight_layout()
plt.show()
Take another look at the docstring for solve_ivp. It expects the first argument of g to be t. By default, odeint uses the opposite convention. If you have a recent version of scipy, you can tell odeint that the first argument is t by giving it the argument tfirst=True.
Related
import numpy as np
from matplotlib import pyplot as plt
xk = np.linspace(-1,1,100)
yk= 2 * xk + 3 + np.random.rand(len(xk))
x1,x2 = np.meshgrid(xk,yk)
F = (x1 - 2) ** 2 + 2 * (x2 - 3) ** 2
fig=plt.figure()
surf = fig.add_subplot(1,1,1, projection='3d')
surf.plot_surface(x1,x2,F)
surf.contour(x1,x2,F)
fig, surf=plt.subplots()
plt.contour(x1, x2, F, 20)
m = 0
c = 0
learning_rate=0.01
I think my problem to get the correct result is from here, but I cant find where is the problem
for k in range(10):
shuffel_index=np.random.permutation(len(xk))
xk = xk[shuffel_index]
yk = yk[shuffel_index]
for i in range(len(xk)):
grad_m = - 2 * xk[i] * (yk[i] - (np.dot(m,xk[i]) + c))
grad_c = - 2 * (yk[i] - (np.dot(m,xk[i])+c))
m = m - learning_rate * grad_m
c = c - learning_rate * grad_c
surf.plot(np.array([xk[0], yk[0]]),np.array([xk[1], yk[1]]),'ko-')
if (k != 10 or i != len(xk)):
surf.plot(np.array([xk[0], yk[0]]),np.array([xk[1], yk[1]]),'ko-')
plt.show()
This is my result for the above code
And I wish to get the result like I do for gradient descent algorithm. The example of my gradient descent result.
May I know where is my error?
so I saw this code for RK4 on stack and I found it very useful. However, I cannot figure out a way to plot for each y value at each increment(h) of x.
def f(x,y):
return 2*x**2-4*x+y
def RK4(x0,y0):
while x0 < b:
k1 = h*f(x0,y0)
k2 = h*f(x0+0.5*h,y0+0.5*k1)
k3 = h*f(x0+0.5*h,y0+0.5*k2)
k4 = h*f(x0+h,y0+k3)
y0+=(k1+2*k2+2*k3+k4)/6
x0+=h
return y0
b=3
h=0.001
print(RK4(1,0.7182818))
You can append each point in a list as a tuple, and then perform the line plot operation on the list of tuples. You can find it in the commented code below.
import matplotlib.pyplot as plt
def f(x, y):
return 2 * x ** 2 - 4 * x + y
def RK4(x0, y0):
pts = [] # empty list
while x0 < b:
k1 = h * f(x0, y0)
k2 = h * f(x0 + 0.5 * h, y0 + 0.5 * k1)
k3 = h * f(x0 + 0.5 * h, y0 + 0.5 * k2)
k4 = h * f(x0 + h, y0 + k3)
y0 += (k1 + 2 * k2 + 2 * k3 + k4) / 6
x0 += h
pts.append((x0, y0)) # appending the tuple
plt.plot(*zip(*pts)) # plotting the list of tuple
plt.show()
return y0
b = 3
h = 0.001
print(RK4(1, 0.7182818))
You can see the plot as follows
From a design perspective, it would be preferred if the RK4 code and the plotting code were separated, the numerical solver should not be concerned with how its results are used afterwards.
Then the next decision would be about the construction of the time array, it could be passed to the RK4 method, or be constructed inside and returned, both have advantages. If speed is a concern, the arrays should be constructed explicitly in their final form (see example on math.SE), for expediency one can also construct them incrementally. Thus the code could be changed as
def RK4(f,x0,y0,xb,dx):
x, y = [x0],[y0]
while x0 < xb:
k1 = dx*f(x0,y0)
k2 = dx*f(x0+0.5*dx,y0+0.5*k1)
k3 = dx*f(x0+0.5*dx,y0+0.5*k2)
k4 = dx*f(x0+dx,y0+k3)
y0 += (k1+2*k2+2*k3+k4)/6
x0 += dx
x.append(x0); y.append(y0) # for vector y use y0.copy()
return x,y
and then call as
x,y = RK4(f=f,x0=1.0,y0=0.7182818,xb=3.0,dx=1e-3)
plt.plot(x,y)
#title, axis labels
plt.grid(); plt.show()
I have two masses, and two springs which are atattched to a wall on one end. For context I attached the system of equations. Below is the python code for the 4th order Runge-Kutta that evaluates the following system of two 2nd order ODE:
I need help fixing it. When I run my code it plots a flat line, but I know it should oscillate because I want to plot a position versus time graph. Something is probably wrong in my last few lines for the plot commands, but I am not sure what. Thank you for any help.
import numpy as np
import matplotlib.pyplot as plt
def f(x,t):
k1=20
k2=20
m1=2
m2=5
return np.array([x[1],(-k1*x[0]-k2*x[3])/m1,x[3],(-k2*(x[3]-x[0])/m2)])
h=.01
t=np.arange(0,15+h,h)
y=np.zeros((len(t),4))
for i in range(0,len(t)-1):
k1 = h * f( y[i,:], t[i] )
k2 = h * f( y[i,:] + 0.5 * k1, t[i] + 0.5 * h )
k3 = h * f( y[i,:] + 0.5 * k2, t[i] + 0.5 * h )
k4 = h * f( y[i,:] + k3, t[i+1] )
y[i+1,:] = y[i,:] + ( k1 + 2.0 * ( k2 + k3 ) + k4 ) / 6.0
plt.plot(t,y[:,0],t,y[:,2])
plt.gca().legend(('x_1','x_2'))
plt.show()
You'll need a nonzero initial condition, e.g,
y = np.zeros((len(t), 4))
y[0, :] = [1, 0, 0, 0]
and you'll also have to fix the derivatives calculated in f:
return np.array([x[1], (-k1*x[0]-k2*(x[0] - x[2]))/m1, x[3], (-k2*(x[2]-x[0])/m2)])
With those changes, the plot is
P.S. You might be interested in this: Coupled spring-mass system
This python code can solve one non- coupled differential equation:
import numpy as np
import matplotlib.pyplot as plt
import numba
import time
start_time = time.clock()
#numba.jit()
# A sample differential equation "dy / dx = (x - y**2)/2"
def dydx(x, y):
return ((x - y**2)/2)
# Finds value of y for a given x using step size h
# and initial value y0 at x0.
def rungeKutta(x0, y0, x, h):
# Count number of iterations using step size or
# step height h
n = (int)((x - x0)/h)
# Iterate for number of iterations
y = y0
for i in range(1, n + 1):
"Apply Runge Kutta Formulas to find next value of y"
k1 = h * dydx(x0, y)
k2 = h * dydx(x0 + 0.5 * h, y + 0.5 * k1)
k3 = h * dydx(x0 + 0.5 * h, y + 0.5 * k2)
k4 = h * dydx(x0 + h, y + k3)
# Update next value of y
y = y + (1.0 / 6.0)*(k1 + 2 * k2 + 2 * k3 + k4)
# Update next value of x
x0 = x0 + h
return y
def dplot(start,end,steps):
Y=list()
for x in np.linspace(start,end,steps):
Y.append(rungeKutta(x0, y, x , h))
plt.plot(np.linspace(start,end,steps),Y)
print("Execution time:",time.clock() - start_time, "seconds")
plt.show()
start,end = 0, 10
steps = end* 100
x0 = 0
y = 1
h = 0.002
dplot(start,end,steps)
This code can solve this differential equation:
dydx= (x - y**2)/2
Now I have a system of coupled differential equations:
dydt= (x - y**2)/2
dxdt= x*3 + 3y
How can I implement these two as a system of coupled differential equations in the above code?
Is there any more generalized way for system of n-number of coupled differential equations?
With the help of others, I got to this:
import numpy as np
from math import sqrt
import matplotlib.pyplot as plt
import numba
import time
start_time = time.clock()
a=1
b=1
c=1
d=1
# Equations:
#numba.jit()
#du/dt=V(u,t)
def V(u,t):
x, y, vx, vy = u
return np.array([vy,vx,a*x+b*y,c*x+d*y])
def rk4(f, u0, t0, tf , n):
t = np.linspace(t0, tf, n+1)
u = np.array((n+1)*[u0])
h = t[1]-t[0]
for i in range(n):
k1 = h * f(u[i], t[i])
k2 = h * f(u[i] + 0.5 * k1, t[i] + 0.5*h)
k3 = h * f(u[i] + 0.5 * k2, t[i] + 0.5*h)
k4 = h * f(u[i] + k3, t[i] + h)
u[i+1] = u[i] + (k1 + 2*(k2 + k3 ) + k4) / 6
return u, t
u, t = rk4(V, np.array([1., 0., 1. , 0.]) , 0. , 10. , 100000)
x,y, vx,vy = u.T
# plt.plot(t, x, t,y)
plt.semilogy(t, x, t,y)
plt.grid('on')
print("Execution time:",time.clock() - start_time, "seconds")
plt.show()
I am currently working on a set of code that I am using to solve an ordinary differential equation... My code is working, however, I would like to be able to modify it to solve the differential equation for a set of different constant values. This is what I have currently, and if ran works.
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
def f(w, x):
# d1 = omega lambda
d1 = w
b2 = 0.0
# 0.2<c<1.4, 0.20 increments
c = 0.2
q = (1 - d1 - (2*((d1**1.5)/c))) / (2 + (3*(b2)))
f = (d1**2) * (1 - d1) * ((1 / d1) + (2 / (c * (d1**0.5))) - ((3 * b2 * q) / (d1 * (1-d1))))
return f
#determine domain, x
x = np.linspace(-80, 80, 1000001)
d1 = 10 ** -8
sol = odeint(f, d1, x)
plt.xlabel("x")
plt.ylabel("Omega Lambda")
plt.plot(x, sol, 'r')
plt.show()
However, I would like to construct a graph that consists of each line that a set of different values of c would produce... the c's I would like to produce a graph of are:
c = 0.2,0.4,0.6,0.8,1.0,1.2,1.4
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
def f(w, x , b2 , c):
# d1 = omega lambda
d1 = w
# 0.2<c<1.4, 0.20 increments
#c = 0.2
q = (1 - d1 - (2*((d1**1.5)/c))) / (2 + (3*(b2)))
f = (d1**2) * (1 - d1) * ((1 / d1) + (2 / (c * (d1**0.5))) - ((3*b2*q)/(d1*1-d1))))
return f
#determine domain, x
x = np.linspace(-80, 80, 1000001)
d1 = 10 ** -8
b2 = 0.0
c = [ 0.2,0.4,0.6,0.8,1.0,1.2,1.4 ]
for i in c:
sol = odeint(f, d1, x, args = (b2 , i))
plt.xlabel("x")
plt.ylabel("Omega Lambda")
plt.plot(x, sol, 'r')
plt.show()