I am currently working on implementing the Adams Bashforth Moulton Method for solving a pendulum problem.
My current code is as follows:
import numpy as np
#####################################################################################
# DEF func
#####################################################################################
def func(y,t):
n=y.size
f=np.zeros(6)
xp=np.array([y[3],y[4],y[5]])[np.newaxis]
mass=1.
F1=0.
F2=0.
F3=-mass*9.8
F=np.array([F1,F2,F3])[np.newaxis]
phix=2.*y[0]
phiy=2.*y[1]
phiz=2.*y[2]
G=np.array([phix,phiy,phiz])[np.newaxis]
H=2.*np.eye(3)
lambd=(mass*np.dot(xp,np.dot(H,xp.T))+np.dot(F,G.T))/np.dot(G,G.T)
f[0]=y[3]
f[1]=y[4]
f[2]=y[5]
for k in range(0,3):
f[k+3]=(F[0,k]-lambd*G[0,k])/mass
return f
def dF_matrix(y):
n=y.size
dF=np.zeros((6,6))
xp=np.array([y[3],y[4],y[5]])[np.newaxis]
mass=1.
F1=0.
F2=0.
F3=-mass*9.8
F=np.array([F1,F2,F3])[np.newaxis]
phix=2.*y[0]
phiy=2.*y[1]
phiz=2.*y[2]
G=np.array([phix,phiy,phiz])[np.newaxis]
H=2.*np.eye(3)
lambd=(mass*np.dot(xp,np.dot(H,xp.T))+np.dot(F,G.T))/np.dot(G,G.T)
dF[0,3]=1
dF[1,4]=1
dF[2,5]=1
dF[3,0]=(y[0]*F1+2*lambd)/mass
dF[3,1]=(y[0]*F2)/mass
dF[3,2]=(y[0]*F3)/mass
dF[3,3]=phix*y[3]
dF[3,4]=phix*y[4]
dF[3,5]=phix*y[5]
dF[4,0]=(y[1]*F1)/mass
dF[4,1]=(y[1]*F2+2*lambd)/mass
dF[4,2]=(y[1]*F3)/mass
dF[4,3]=phiy*y[3]
dF[4,4]=phiy*y[4]
dF[4,5]=phiy*y[5]
dF[5,0]=(y[2]*F1)/mass
dF[5,1]=(y[2]*F2)/mass
dF[5,2]=(y[2]*F3+2*lambd)/mass
dF[5,3]=phiz*y[3]
dF[5,4]=phiz*y[4]
dF[5,5]=phiz*y[5]
return dF
#####################################################################################
# PYTHON script:
# Solve ODE for pendulum problem
#####################################################################################
from scipy.integrate import odeint
from mpl_toolkits import mplot3d
import matplotlib.pyplot as plt
import time
### Forward Euler Method
def forward_Euler(function, y_matrix, time):
y = np.zeros((np.size(time), np.size(y_matrix)))
y[0, :] = y_matrix
for i in range(len(time) - 1):
dt = time[i + 1] - time[i]
y[i + 1, :] = y[i, :] + np.asarray(function(y[i, :], time[i])) * dt
return y
### Modified Euler Method
def modified_Euler(function, y_matrix, time):
y = np.zeros((np.size(time), np.size(y_matrix)))
y[0, :] = y_matrix
for i in range(len(time) - 1):
dt = time[i + 1] - time[i]
k1 = np.asarray(function(y[i, :], time[i]))
k2 = np.asarray(function(y[i, : + k1], time[i]))
y[i + 1, :] = y[i, :] + (k1 + k2) / 2
return y
### Adams-Bashforth 2nd order
def Adams_Bash_2nd(function, y_matrix, time):
y = np.zeros((np.size(time), np.size(y_matrix)))
y[0, :] = y_matrix
for i in range(len(time) - 1):
dt = time[i + 1] - time[i]
f_1 = function(y[i, :], time[i])
f_2 = function(f_1, time[i])
y[i + 1, :] = y[i, :] + dt * f_1 + ((dt**2)/2) * f_2
return y
### Adams Bashforth Moulton Method
def Adams_Moulton(function, y_matrix, time):
y = np.zeros((np.size(time), np.size(y_matrix)))
y[0, :] = y_matrix
### predictor formula
for i in range(len(time) - 1):
dt = time[i + 1] - time[i]
f_1 = function(y[i, :], time[i])
f_2 = function(f_1, time[i])
y[i + 1, :] = y[i, :] + dt * f_1 + ((dt**2)/2) * f_2
### Corrector formula
for i in range(len(time-1)):
dt = time[i + 1] - time[i]
k_1 = 9 * (function(y[i, :], time[i+1]))
k_2 = 19 * (function(y[i, :], time[i]))
k_3 = 5 * (function(y[i, :], time[i-1]))
k_4 = (function(y[i, :], time[i-2]))
# === ERROR HAPPENS HERE ===
y[i + 1, :] = y + (dt/24) * (k_1 + k_2 - k_3 + k_4)
return y
# initial condition
y0=np.array([0.0,1.0,0.0,0.8,0.0,1.2])
print('ODE Python ..')
time_start = time.clock()
nt = 500
# time points
t = np.linspace(0,25,nt)
# solve ODE
y1 = odeint(func,y0,t)
time_elapsed = (time.clock() - time_start)
print('elapsed time',time_elapsed)
# compute residual:
r=y1[:,0]**2+y1[:,1]**2+y1[:,2]**2-1
rmax1=np.max(np.abs(r))
print('error',rmax1)
fig = plt.figure()
ax = plt.axes(projection='3d')
ax.plot3D(y1[:,0],y1[:,1],y1[:,2], 'gray')
plt.show()
# print ODE Euler Method
time_start = time.clock()
nt = 500
# time points
t = np.linspace(0, 25, nt)
# solve ODE
y1 = forward_Euler(func, y0, t)
print(y1)
time_elapsed = (time.clock() - time_start)
print('elapsed time', time_elapsed)
# compute residual:
r = y1[:, 0] ** 2 + y1[:, 1] ** 2 + y1[:, 2] ** 2 - 1
rmax1 = np.max(np.abs(r))
print('error', rmax1)
fig = plt.figure()
ax = plt.axes(projection='3d')
ax.plot3D(y1[:, 0], y1[:, 1], y1[:, 2], 'gray')
plt.show()
### Modified Euler method
time_start = time.clock()
nt = 500
# time points
t = np.linspace(0, 25, nt)
# solve ODE
y1 = forward_Euler(func, y0, t)
print(y1)
time_elapsed = (time.clock() - time_start)
print('elapsed time', time_elapsed)
# compute residual:
r = y1[:, 0] ** 2 + y1[:, 1] ** 2 + y1[:, 2] ** 2 - 1
rmax1 = np.max(np.abs(r))
print('error', rmax1)
fig = plt.figure()
ax = plt.axes(projection='3d')
ax.plot3D(y1[:, 0], y1[:, 1], y1[:, 2], 'gray')
plt.show()
### Adams-Bashforth 2nd order
time_start = time.clock()
nt = 500
# time points
t = np.linspace(0, 25, nt)
# solve ODE
y1 = Adams_Bash_2nd(func, y0, t)
print(y1)
time_elapsed = (time.clock() - time_start)
print('elapsed time', time_elapsed)
# compute residual:
r = y1[:, 0] ** 2 + y1[:, 1] ** 2 + y1[:, 2] ** 2 - 1
rmax1 = np.max(np.abs(r))
print('error', rmax1)
fig = plt.figure()
ax = plt.axes(projection='3d')
ax.plot3D(y1[:, 0], y1[:, 1], y1[:, 2], 'gray')
plt.show()
### Adams-Moulton 1st order
# time_start = time.clock()
nt = 500
# time points
t = np.linspace(0, 25, nt)
# solve ODE
y1 = Adams_Moulton(func, y0, t)
print(y1)
# time_elapsed = (time.clock() - time_start)
# print('elapsed time', time_elapsed)
# compute residual:
r = y1[:, 0] ** 2 + y1[:, 1] ** 2 + y1[:, 2] ** 2 - 1
rmax1 = np.max(np.abs(r))
print('error', rmax1)
fig = plt.figure()
ax = plt.axes(projection='3d')
ax.plot3D(y1[:, 0], y1[:, 1], y1[:, 2], 'gray')
plt.show()
exit()
My fucntion adam_moulton() keeps returning the following error:
Traceback (most recent call last):
File "C:/Users/Andrew/Documents/solve_pendulum.py", line 249, in <module>
y1 = Adams_Moulton(func, y0, t)
File "C:/Users/Andrew/Documents/solve_pendulum.py", line 148, in Adams_Moulton
y[i + 1, :] = y + (dt/24) * (k_1 + k_2 - k_3 + k_4)
ValueError: could not broadcast input array from shape (500,6) into shape (6)
What is wrong in my thought process for implementing this multistep method?
Thank you all for the help!
The function definition for the pendulum in Cartesian coordinates, a particle moving under gravity and the constraint |x|^2=L^2=const., can be written much shorter as
def func(y,t):
x,v = y[:3],y[3:6]
grav = np.array([0., 0., -9.8 ])
lambd = (grav.dot(x)+v.dot(v))/x.dot(x)
return np.concatenate([v, grav - lambd*x] )
# initial condition
y0=np.array([0.0,1.0,0.0,0.8,0.0,1.2])
As long as no friction term is included, the mass cancels out and need not be considered in the equations.
An inefficient implementation (no use of Jacobian and Newton-like steps) of the 4th order Adams-Moulton PECE method is
def Adams_Moulton_4th(function, y_matrix, time):
y = np.zeros((np.size(time), np.size(y_matrix)))
y[0] = y_matrix
### bootstrap steps with 4th order one-step method
dt = time[1] - time[0]
y[1] = RK4_step(function,y[0], time[0], dt, N=4)
y[2] = RK4_step(function,y[1], time[1], dt, N=4)
y[3] = RK4_step(function,y[2], time[2], dt, N=4)
f_m2 = function(y[0], time[0])
f_m1 = function(y[1], time[1])
f_0 = function(y[2], time[2])
f_1 = function(y[3], time[3])
for i in range(3,len(time) - 1):
### first shift the "virtual" function value array so that
### [f_m3, f_m2, f_m1, f_0] corresponds to [ f[i-3], f[i-2], f[i-1], f[i] ]
f_m3, f_m2, f_m1, f_0 = f_m2, f_m1, f_0, f_1
### predictor formula 4th order [ 55/24, -59/24, 37/24, -3/8 ]
y[i+1] = y[i] + (dt/24) * (55*f_0 - 59*f_m1 + 37*f_m2 - 9*f_m3)
f_1 = function(y[i+1], time[i+1])
### Corrector formula 4th order [ 3/8, 19/24, -5/24, 1/24 ]
y[i+1] = y[i] + (dt/24) * (9*f_1 + 19*f_0 - 5*f_m1 + f_m2)
f_1 = function(y[i+1], time[i+1])
return y
and results in with nt=2500 steps in a radius error of 2.39e-05 with a plot that is close to the reference solution by odeint.
The classical RK4 method used in the bootstrapping process was implemented as
def RK4_step(f,y,t,dt, N=1):
dt /= N;
for k in range(N):
k1=f(y,t)*dt; k2=f(y+k1/2,t+dt/2)*dt; k3=f(y+k2/2,t+dt/2)*dt; k4=f(y+k3,t+dt)*dt;
y, t = y+(k1+2*(k2+k3)+k4)/6, t+dt
return y
Related
I am trying to minimize a function using the Nelder-Mead method in Python.
Here is the function I am trying to minimize
I am getting the following error:
Here is my code:
import numpy as np
def f(x):
return np.sum(x**2/2)
def nelder_mead(f, x0, args=(), iters=1000, tol=1e-6):
n = len(x0)
x0 = np.asarray(x0)
x1 = np.zeros((n, n+1))
x1[:, 0] = x0
f1 = np.zeros(n+1)
f1[0] = f(x0)
for i in range(iters):
x_bar = np.mean(x1[:, :n], axis=1)
xr = 2*x_bar - x1[:, n]
fr = f(xr)
if fr < f1[n]:
xe = 2*xr - x_bar
fe = f(xe)
if fe < fr:
x1[:, n+1] = xe
f1[n+1] = fe
else:
x1[:, n+1] = xr
f1[n+1] = fr
else:
xc = (x_bar + x1[:, n])/2
fc = f(xc)
if fc < f1[n]:
x1[:, n+1] = xc
f1[n+1] = fc
x1[:, n] = xr
f1[n] = fr
else:
x1[:, 1:] = x1[:, :n]
f1[1:] = f1[:n]
x1[:, 0] = (x1[:, n] + x1[:, n+1])/2
f1[0] = f(x1[:, 0])
"x1[:, n+1] = x1[:, n]"
"f1[n+1] = f1[n]"
"x1[:, n] = (x1[:, 0] + x1[:, n+1])/2"
"f1[n] = f(x1[:, n])"
if np.abs(f1[n] - f1[n+1]) < tol:
return x1[:, n], f1[n]
return x1[:, n], f1[n]
x0 = np.random.rand(2)*4 - 2
print(nelder_mead(f, x0))
I am unsure how to change the code. I believe the error is coming up because I think I am identifying index 2, which is the third position. Somehow I am identifying the third index.
In addition to my previous post ODESolver Ι try to implement antoher different numerical schemes. For example, I implement Runge-Kutta 4 order scheme for solver ODE class, and Forward Euler scheme. Basic superclass ODE_Solver code posted below:
#ODS.py
import numpy as np
class ODE_Solver(object):
"""
Supercalss sover ODE-s
Attribute:
x: array of x coords
u: solution array y(x)
k: number of steps
f: right hand side ODE equation: du/dx = f(u, x)
"""
def __init__(self, f):
if not callable(f):
# check correct function f(u, x)
raise TypeError('f is %s, not function' % type(f))
self.f = lambda u, x: np.asarray(f(u, x), float)
def solver_st(self):
"""Implement numerical scheme"""
raise NotImplementedError
def set_initial_condition(self, u0):
if isinstance(u0, (float, int)): # ODE 1-th order
self.neq = 1
u0 = float(u0)
else: # ODE high order or system of ODE-s
u0 = np.asarray(u0) # (initial conds)
self.neq = u0.size
self.u0 = u0
# check correct lenght of vector f
try:
f0 = self.f(self.u0, 0)
except IndexError:
raise IndexError(
'index out of bounds f(u,x). right index %s' % (str(range(self.neq))))
if f0.size != self.neq:
raise ValueError('f(u,x) return %d elems, u has %d elems' % (f0.size, self.neq))
def solve(self, coord_points, terminate=None):
"""
Solve equations. Default False
"""
if terminate is None:
terminate = lambda u, x, step_no: False
if isinstance(coord_points, (float, int)):
raise TypeError('solve: array lists not iterable')
self.x = np.asarray(coord_points)
if self.x.size <= 1:
raise ValueError('ODESolver.solve requre coords x array')
n = self.x.size
if self.neq == 1: # ODE
self.u = np.zeros(n)
else:
self.u = np.zeros((n, self.neq))
# Assume self.x[0] corresponds to self.u0
self.u[0] = self.u0
# looping for x coords
for k in range(n - 1):
self.k = k
self.u[k + 1] = self.solver_st()
if terminate(self.u, self.x, self.k + 1):
break
return self.u[:k + 2], self.x[:k + 2]
Forwar Euler scheme implement posted below:
# ES.py
from abc import ABC
from ODS import ODE_Solver
class FE(ODE_Solver, ABC):
"""
Attribute:
x: array of x coords
u: solution array y(x)
k: number of steps
f: right hand side ODE equation: du/dx = f(u, x)
"""
def solver_st(self):
u, f, k, x = self.u, self.f, self.k, self.x
dx = x[k+1] - x[k]
u_new = u[k] + dx*f(u[k], x[k])
return u_new
If I call Forvard Euler scheme it is workin, but now I try to implement Adams-Bashfort-Moulton Scheme:
#ADS.py
from abc import ABC
from ODS import ODE_Solver
class ABM4(ODE_Solver, ABC):
"""
Attribute:
x: array of x coords
u: solution array y(x)
k: number of steps
f: right hand side ODE equation: du/dx = f(u, x)
"""
def solver_st(self, alp=None):
u, f, k, x = self.u, self.f, self.k, self.x
for k in range(0,4):
dx = x[k + 1] - x[k]
dx2 = dx / 2.0
K1 = dx * f(u[k], x[k])
K2 = dx * f(u[k] + 0.5 * K1, x[k] + dx2)
K3 = dx * f(u[k] + 0.5 * K2, x[k] + dx2)
K4 = dx * f(u[k] + K3, x[k] + dx)
u = u[k] + (1 / 6.0) * (K1 + 2 * K2 + 2 * K3 + K4)
for k in range(4, self.x.size):
dx = x[k + 1] - x[k]
alp[k] = dx / 24 * (55 * f(u[k - 1], x[k - 1]) - 59 * f(u[k - 2], x[k - 2]) + 37 * f(u[k - 3], x[k - 3])
- 9 * f(u[k - 4], x[k - 4])) + u[k - 1]
u_new = dx / 24 * (9 * f(u[k], alp[k]) + 19 * f(u[k - 1], x[k - 1]) - 5 * f(u[k - 2], x[k - 2])
+ f(u[k - 3], x[k - 3])) + u[k - 1]
return u_new
And if I try to call this solver (Adams-Bashfort-Moulton) method from another class in main file
import matplotlib.pyplot as plt
import numpy as np
from tabulate import tabulate
from ADS import ABM4
def exact(x):
return (np.exp(-3 * x) * (-129 * (x ** 4) - 16 * (x ** 3) + 54 * (x ** 2) + 36 * x)) / 12
def f(u, x):
return (u[1],
u[2],
u[3],
u[4],
- 15 * u[4] - 90 * u[3] -
270 * u[2] - 405 * u[1] - 243 * u[0])
y0 = [0, 3, -9, -8, 0]
solver = ABM4(f)
solver.set_initial_condition(y0)
x_points = np.linspace(0, 5, 50)
u, x = solver.solve(x_points)
y = u[:, 0]
plt.plot(x, y, 'bo', linewidth=3, markersize=3)
plt.plot(x, exact(x), 'r-')
plt.grid()
plt.show()
I get the same error:
Traceback (most recent call last):
File "C:\Fin_Proj_ODE\test1.py", line 29, in <module>
u, x = solver.solve(x_points)
File "C:\Fin_Proj_ODE\ODS.py", line 71, in solve
self.u[k + 1] = self.solver_st()
File "C:\Fin_Proj_ODE\ADS.py", line 22, in solver_st
K1 = dx * f(u[k], x[k])
File "C:\Fin_Proj_ODE\ODS.py", line 20, in <lambda>
self.f = lambda u, x: np.asarray(f(u, x), float)
File "C:\Fin_Proj_ODE\test1.py", line 17, in f
return (u[1],
IndexError: invalid index to scalar variable.
Process finished with exit code 1
How to improve code and fix this bug?
Probably, this bug tied with uncorrect loop implementation in #ADS.py, so the main loop iteration in ODE_Solver compute arrays of solution throughout the range coord_points. And so,now I don't understnd how to rewrite this loop in ABM4 class.
So, I wrote this script to interpret and graph data from a dynamic light scattering experiment. However, when I run the program I get this curvefit error for p0. Does any one have any idea what the problem could be? I've tried various things without any success. I need all values, so it doesn't really make much sense. Here is the script:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
def exp_fun(x, A, tau,beta):
res = A * np.exp(-(x / tau) ** beta)
return res
def exp_fun2(x, A, tau, tau2):
res = (1-A) * np.exp(-(x / tau)) + ( A) * np.exp(-(x / tau2))
return res
def exp_fun3(x, A1, tau, tau2, tau3,A2):
res = (1 - A1-A2) * np.exp(-(x / tau)) + (A1) * np.exp(-(x / tau2))+ (A2) * np.exp(-(x / tau3))
return res
def exp_fun2_str1(x, A, tau, tau2, beta):
res = (1-A) * np.exp(-(x / tau)) + ( A) * np.exp(-(x / tau2) ** beta)
return res
def exp_fun2_str2(x, A, tau, tau2, beta, beta2):
res = (1-A)*np.exp(-(x / tau) ** beta) + ( A) * np.exp(-(x / tau2) ** beta2)
return res
filepath = "C:\\ref-bsa-10\\"
filename = 'BSA1000'
filenamestatic='bsa10table.txt'
numfiles = 24
# load the static data
static = np.loadtxt(filepath + filenamestatic , skiprows=1, usecols=[0, 1,8])
#following code changed due to unicode errors: probably because of text files
#static = pd.read_csv(filepath + filenamestatic , delimiter='\t',skiprows=1)
#staticdata= np.array(static.values)
#angles=staticdata[:,0]
q=np.sqrt(static[:,1])*10**-6
#load and analyse dynamics data
tau1 = np.zeros([numfiles])
tau2 = np.zeros([numfiles])
A = np.zeros([numfiles])
beta1 = np.zeros([numfiles])
beta2 = np.zeros([numfiles])
dbeta1 = np.zeros([numfiles])
dbeta2 = np.zeros([numfiles])
dtau2 = np.zeros([numfiles])
dtau1 = np.zeros([numfiles])
dA = np.zeros([numfiles])
colore = plt.cm.jet(np.linspace(0, 1, numfiles))
plt.figure()
ave_n=5
for i in range(numfiles):
data = pd.read_csv(filepath + filename + "{:02d}_averaged_corr.txt".format(i), delimiter='\t', skiprows=2)
print(data)
a = np.array(data.values)
g2=a[:, 1] / np.mean(a[1:10, 1])
dg2=a[:, 2] / np.mean(a[1:10, 1])
t=a[:, 0]
plt.errorbar(t, g2, dg2, color=colore[i])
popt, pcov = curve_fit(exp_fun, t, g2, dg2,
# A tau beta
bounds=([0.9, 0, 0, ],
[1.1, 10 ** 9, 2, ]),
p0 =([1, 100, 1, ]) )
plt.plot(t, exp_fun(t, popt[0], popt[1], popt[2]), color='red',
linestyle='dashed')
A[i] = popt[0]
dA[i] = np.sqrt(np.diag(pcov))[0]
tau1[i] = popt[1]
dtau1[i] = np.sqrt(np.diag(pcov))[1]
# tau2[i] = popt[2]
# dtau2[i] = np.sqrt(np.diag(pcov))[2]
beta1[i] = popt[2]
dbeta1[i] = np.sqrt(np.diag(pcov))[2]
# beta2[i] = popt[4]
# dbeta2[i] = np.sqrt(np.diag(pcov))[4]
plt.xlabel('$t$ (ms)')
plt.xscale('log')
plt.ylabel(r'$g_2$-1')
plt.grid('on')
plt.figure()
plt.errorbar(q,A, dA,marker='o',linestyle='none')
plt.xlabel('q ($\mathrm{\mu}$m$^{-1}$)')
plt.ylabel('A')
plt.grid('on')
#plt.figure()
#plt.errorbar(q**4,1/tau2, 1/(tau2**2)*dtau2,marker='o',linestyle='none')
#plt.xlabel('q$^4$ ($\mathrm{\mu}$m$^{-4}$)')
#plt.ylabel('$\Gamma_2$ (s$^{-1}$)')
#plt.grid('on')
plt.figure()
plt.errorbar(q**2,1/tau1, 1/(tau1**2)*dtau1,marker='o',linestyle='none')
poptDp, pcovDp = curve_fit(lambda x, *p: x * p[0], q ** 2,1/tau1, p0=[1, 0], bounds=(0, 1000),
sigma=1/(tau1**2)*dtau1, ftol=1e-14, xtol=1e-14) # old: 1e-15
plt.plot(q** 2 , q** 2 * poptDp[0] , color='magenta')
D=poptDp[0]
dD= np.sqrt(np.diag(pcovDp))[0]
plt.xlabel('q$^2$ ($\mathrm{\mu}$m$^{-2}$)')
plt.ylabel('$\Gamma_1$ (s$^{-1}$)')
plt.grid('on')
R=10*10**-9
Dms=D*10**3*(10**-6)**2
kb=1.380649*10**(-23)
eta=kb *(273.15+21)/(6*np.pi*R*Dms)
#comparing two functions
#plt.figure()
#plt.errorbar(q,1/tau2, 1/(tau2**2)*dtau2,marker='o',linestyle='none')
#plt.errorbar(q,1/tau1, 1/(tau1**2)*dtau1,marker='o',linestyle='none')
#plt.xlabel('q ($\mathrm{\mu}$m$^{-1}$)')
#plt.ylabel('$\Gamma$ (s$^{-1}$)')
#plt.grid('on')
#plt.xscale('log')
#plt.yscale('log')
plt.figure()
plt.errorbar(q,beta1, dbeta1,marker='o',linestyle='none')
#plt.errorbar(q,beta2, dbeta2,marker='o',linestyle='none')
plt.grid('on')
plt.xlabel('q ($\mathrm{\mu}$m$^{-1}$)')
plt.ylabel('KWW')
I have written the following code for adaptive step size RungeKutta RK 4th order integration method.
import numpy as np
import os
import matplotlib
from matplotlib import pyplot as plt
rhs_of_diff_Eq_str = "3 * t ** 2"
def first_derivative(t, y): # the first derivative of the function y(t)
first_derivative_value = 3 * t ** 2
return first_derivative_value
time_interval_lowerlimit = 0.0
time_interval_upperlimit = 1.0
dt = 0.01
ts = []
y = 0. # initial condition
t = 0. # initial condition
ys_step = ys_halfstep = ys_doublestep = ys = []
dy_min = 0.01
dy_max = 0.1
dt_min = 0.0001
y_tol = 0.0001
no_of_iterations = 0
while(t < 1):
no_of_iterations += 1
# for timestep = dt
k1 = first_derivative(t, y)
k2 = first_derivative(t + dt/2. , y + (dt/2.)*k1)
k3 = first_derivative(t + dt/2. , y + (dt/2.)*k2)
k4 = first_derivative(t + dt , y + dt *k3)
y_step = y + (dt/6.) * (k1 + 2*k2 + 2*k3 + k4)
ys_step.append(y_step) # for plotting y vs t, at the end of the script, after integration has finished
# for timestep = dt / 2
k1 = first_derivative(t, y)
k2 = first_derivative(t + dt/4. , y + (dt/4.)*k1)
k3 = first_derivative(t + dt/4. , y + (dt/4.)*k2)
k4 = first_derivative(t + dt/2. , y + (dt/2.)*k3)
y_halfstep = y + (dt/12.) * (k1 + 2*k2 + 2*k3 + k4)
ys_halfstep.append(y_halfstep)
# for timestep = dt * 2
k1 = first_derivative(t, y)
k2 = first_derivative(t + dt , y + dt * k1)
k3 = first_derivative(t + dt , y + dt * k2)
k4 = first_derivative(t + 2.*dt, y + 2.*dt * k3)
y_doublestep = y + (dt/3.) * (k1 + 2*k2 + 2*k3 + k4)
ys_doublestep.append(y_doublestep)
if (abs(y_step) <= y_tol): # fix the timestep to dt_min because otherwise we divide by 0 in comparisons below
if (dt != dt_min):
dt = dt_min
new_y = y_step
else: # can modify the timestep if needed
if ( (abs(y_step) > y_tol) and ( (abs(y_step - y_halfstep)/abs(y_step)) > dy_max ) ): # error is too large
dt = dt / 2.
new_y = y_halfstep
else:
if ( (abs(y_step) > y_tol) and ( (abs(y_step - y_doublestep)/abs(y_step)) < dy_min ) ) : # error too small, can increase dt
dt = 2. * dt
new_y = y_doublestep
else: # timestep is just right! keep it as it is and return y_step (i.e. the y-value computed using timestep = dt)
new_y = y_step
y = new_y
# print("y is :")
# print(y)
# print(len(y)) # error, object of type 'float' has no len()
ys.append(y)
# print("t is: ")
# print(t)
ts.append(t)
t += dt
print(len(ys)) #
print(len(ts)) #
print("no of iterations: ")
print(no_of_iterations)
plt.figure()
plt.plot(ts, ys, label='y values', color='red')
plt.xlabel('t')
plt.ylabel('y')
plt.title("RK4 adaptive step-size integration for dy/dt = f(y,t) \n" + "f(y,t) = " + rhs_of_diff_Eq_str)
plt.savefig("RK4_adaptive_step_size_results.pdf", bbox_inches='tight')
This results in error at the plotting instructions due to the 2 lists ts and ys having different number of elements.
I have been looking at the code for a while now and I don't see the reason why the ys always have 4 times the number of elements in the list ts after the script exits from the while-loop.
Can you please help me, maybe it's something obvious?
Thanks
The issues stile happen from this line ys_step = ys_halfstep = ys_doublestep = ys = [], there is a created four list but all refers the same memories and when you append the element one of that list it stile append the all that lists.
You can only change the as following:
ys_step = []
ys_halfstep = []
ys_doublestep = []
ys = []
it will worked.
I want to implement a custom undistortion function like in OpenCV using numpy module on Python.
From documentation is known that undistort function is just a combination of of initUndistortRectifyMap() and remap().
Since remap() is quite simple operation, the main issue is to implement maps for remap().
I wrote a code to construct maps, but it seems to me that it works quite slowly.
The code consists of three main parts:
Reshape original image points to a well-shaped array to multiply it on the inverse of the camera matrix and perform a multiplication.
Distort points in the z = 1 plane.
Reshape points again to perform another multiplication to get back to image points.
I took an image with size of (4032 x 3024).
One matrix multiplication works on my pc for about 1 sec. And the distortion function works for about 2.4 sec.
I tried to multiply same shaped matrices with OpenCV Mats on C++, and I took 0.0002 sec.
The question is how to speed up the computations, because it seems to me that I am doing something wrong, because of such a big difference.
I found here an advice to make all arrays contiguous, but this did not help
The code:
import numpy
import time
def _distort_z_1(x, y, k1, k2, k3, k4, k5, k6, p1, p2):
x2 = x * x
y2 = y * y
xy = x * y
r2 = x2 + y2
r4 = r2 * r2
r6 = r4 * r2
radial = \
(1 + k1 * r2 + k2 * r4 + k3 * r6) / \
(1 + k4 * r2 + k5 * r4 + k6 * r6)
tangential_x = 2 * p1 * xy + p2 * (r2 + 2 * x2)
tangential_y = p1 * (r2 + 2 * y2) + 2 * p2 * xy
x_distorted = x * radial + tangential_x
y_distorted = y * radial + tangential_y
return x_distorted, y_distorted
# Change dimension from [2 x H x W] to [H x W x 3 x 1] to correctly multiply with [3 x 3] matrix
def _homogeneous_reshape(points_x, points_y):
points_homogeneous_reshaped = (
# Add extra axis to change from [H x W x 3] to [H x W x 3 x 1]
numpy.expand_dims(
# Change from [3 x H x W] to [H x W x 3]
numpy.transpose(
# Change from [2 x H x W] to [3 x H x W] (homogeneous coordinates)
numpy.stack(
numpy.broadcast_arrays(points_x, points_y, 1)),
(1, 2, 0)),
-1))
return points_homogeneous_reshaped
def _homogeneous_reshape_back(points_homogeneous_reshaped):
points_homogeneous = (
# Get back from [H x W x 3] to [3 x H x W]
numpy.transpose(
# Remove extra axis: [H x W x 3 x 1] to [H x W x 3]
numpy.squeeze(
points_homogeneous_reshaped),
(2, 0, 1)))
# Get back from homogeneous coordinates
points_x, points_y, _ = points_homogeneous
return points_x, points_y
def _get_undistort_rectify_maps(distortion_coefficients, camera_matrix, image_width, image_height):
image_points = numpy.meshgrid(range(image_width), range(image_height))
# print("BEGIN: _homogeneous_reshape")
start = time.time()
image_points_homogeneous_reshaped = _homogeneous_reshape(*image_points)
end = time.time()
print("END: _homogeneous_reshape", end - start)
camera_matrix_inv = numpy.linalg.inv(camera_matrix)
# print("BEGIN: camera_matrix_inv # image_points_homogeneous_reshaped")
start = time.time()
image_points_homogeneous_z_1_reshaped = camera_matrix_inv # image_points_homogeneous_reshaped
end = time.time()
print("END: camera_matrix_inv # image_points_homogeneous_reshaped", end - start)
# print("BEGIN: _homogeneous_reshape_back")
start = time.time()
image_points_z_1 = _homogeneous_reshape_back(image_points_homogeneous_z_1_reshaped)
end = time.time()
print("END: _homogeneous_reshape_back", end - start)
# print("BEGIN: _distort_z_1")
start = time.time()
x_distorted, y_distorted = _distort_z_1(
*image_points_z_1,
**distortion_coefficients)
end = time.time()
print("END: _distort_z_1", end - start)
# print("BEGIN: _homogeneous_reshape")
start = time.time()
points_homogeneous_z_1_distorted_reshaped = _homogeneous_reshape(x_distorted, y_distorted)
end = time.time()
print("END: _homogeneous_reshape", end - start)
# print("BEGIN: _homogeneous_reshape")
start = time.time()
points_homogeneous_distorted_reshaped = camera_matrix # points_homogeneous_z_1_distorted_reshaped
end = time.time()
print("END: camera_matrix # points_homogeneous_z_1_distorted_reshaped", end - start)
# print("BEGIN: _homogeneous_reshape_back")
start = time.time()
points_homogeneous_distorted = _homogeneous_reshape_back(points_homogeneous_distorted_reshaped)
end = time.time()
print("END: _homogeneous_reshape_back", end - start)
return (map.astype(numpy.float32) for map in points_homogeneous_distorted)
if __name__ == "__main__":
image_width = 4032
image_height = 3024
distortion_coefficients = {
"k1": 0, "k2": 0, "k3": 0, "k4": 0, "k5": 0, "k6": 0,
"p1": 0, "p2": 0}
camera_matrix = numpy.array([
[1000, 0, 2016],
[0, 1000, 1512],
[0, 0, 1]])
map_x, map_y = _get_undistort_rectify_maps(
distortion_coefficients,
camera_matrix,
image_width,
image_height)