I am trying to solve an ODE with two variables. I do not understand why or how I have created a tuple here. The function f should be f = 10 - x - (4xy / 1+x^2) Could anyone help with this?
def RK_step(f, g, x, y, t, dt):
x_new = x + dt*f(x + 0.5*dt*f(x, y, t), y + 0.5*dt*f(x, y, t), t + 0.5*dt)
y_new = y + dt*g(x + 0.5*dt*f(x, y, t), y + 0.5*dt*g(x, y, t), t + 0.5*dt)
return x_new, y_new
def RK_method(f, g, x, y, dt, n):
x_array = [x]
y_array = [y]
for i in range(1,n+1):
t = i*dt
x_array.append(RK_step(f, g, x_array[-1], y_array[-1], t, dt))
y_array.append(RK_step(f, g, x_array[-1], y_array[-1], t, dt))
return x_array, y_array
def f(x, y, t):
return 10 - x - ((4*x*y) / (1 + (x**2)))
def g(x, y, t):
return 4*x*(1- (y / (1 + x**2)))
T = 100
dt = 0.1
n = int(T/dt)
x_initial = 0
y_initial = 1
x_RK = RK_method(f, g, x_initial, y_initial, dt, n)
y_RK = RK_method(f, g, x_initial, y_initial, dt, n)
t = np.linspace(0,T,n+1)
plt.plot(t,x_RK)
plt.plot(t,y_RK)
plt.legend(['Runge-Kutta with $dt = ${}'.format(dt)]);
<ipython-input-7-530b1d126979> in f(x, y, t)
56
57 def f(x, y, t):
---> 58 return (10 - (x - ((4*x*y) / (1 + (x**2)))))
59
60 def g(x, y, t):
TypeError: unsupported operand type(s) for ** or pow(): 'tuple' and 'int'
Here:
x_array.append(RK_step(f, g, x_array[-1], y_array[-1], t, dt))
y_array.append(RK_step(f, g, x_array[-1], y_array[-1], t, dt))
RK_step
returns a tuple. You are putting a tuple into x_array
and into y_array
.
If you want to split the tuple between x_array
and y_array
, then you want something like this:
x,y = RK_step(f, g, x_array[-1], y_array[-1], t, dt)
x_array.append(x)
y_array.append(y)
You are computing the same values multiple times, unnecessarily. You can streamline this and at the same time remove the error by changing your code for the midpoint method to
def RK_step(f, g, x, y, t, dt):
# compute only once
f0, g0 = f(x, y, t), g(x, y, t)
# note the remaining duplicated operations in the arguments
x_new = x + dt*f(x + 0.5*dt*f0, y + 0.5*dt*g0, t + 0.5*dt)
# there is a typo ----------^ in the original code
y_new = y + dt*g(x + 0.5*dt*f0, y + 0.5*dt*g0, t + 0.5*dt)
return x_new, y_new
def RK_method(f, g, x, y, dt, n):
x_array = [x]
y_array = [y]
for i in range(1,n+1):
t = i*dt
# call the RK2 step only once, use all of the returned values
x,y = RK_step(f, g, x, y, t, dt)
x_array.append(x)
y_array.append(y)
return x_array, y_array
def f(x, y, t):
return 10 - x - ((4*x*y) / (1 + (x**2)))
def g(x, y, t):
return 4*x*(1- (y / (1 + x**2)))
T = 100
dt = 0.1
n = int(T/dt)
x_initial = 0
y_initial = 1
# call the integration procedure only once, use all of the returned values
x_RK,y_RK = RK_method(f, g, x_initial, y_initial, dt, n)
# do not rely on floating point arithmetic being accidentally correct
t = np.arange(n+1)*dt
plt.plot(t,x_RK)
plt.plot(t,y_RK)
plt.legend(['Runge-Kutta with $dt = ${}'.format(dt)]);
resulting in the plot
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.