Related
I am trying to solve this equation using Runge Kutta 4th order:
applying d2Q/dt2=F(y,x,v) and dQ/dt=u Q=y in my program.
I try to run the code but i get this error:
Traceback (most recent call last):
File "C:\Users\Egw\Desktop\Analysh\Askhsh1\asdasda.py", line 28, in <module>
k1 = F(y, u, x) #(x, v, t)
File "C:\Users\Egw\Desktop\Analysh\Askhsh1\asdasda.py", line 13, in F
return ((Vo/L -(R0/L)*u -(R1/L)*u**3 - y*(1/L*C)))
OverflowError: (34, 'Result too large')
I tried using the decimal library but I still couldnt make it work properly.I might have not used it properly tho.
My code is this one:
import numpy as np
from math import pi
from numpy import arange
from matplotlib.pyplot import plot, show
#parameters
R0 = 200
R1 = 250
L = 15
h = 0.002
Vo=1000
C=4.2*10**(-6)
t=0.93
def F(y, u, x):
return ((Vo/L -(R0/L)*u -(R1/L)*u**3 - y*(1/L*C)))
xpoints = arange(0,t,h)
ypoints = []
upoints = []
y = 0.0
u = Vo/L
for x in xpoints:
ypoints.append(y)
upoints.append(u)
m1 = u
k1 = F(y, u, x) #(x, v, t)
m2 = h*(u + 0.5*k1)
k2 = (h*F(y+0.5*m1, u+0.5*k1, x+0.5*h))
m3 = h*(u + 0.5*k2)
k3 = h*F(y+0.5*m2, u+0.5*k2, x+0.5*h)
m4 = h*(u + k3)
k4 = h*F(y+m3, u+k3, x+h)
y += (m1 + 2*m2 + 2*m3 + m4)/6
u += (k1 + 2*k2 + 2*k3 + k4)/6
plot(xpoints, upoints)
show()
plot(xpoints, ypoints)
show()
I expected to get the plots of u and y against t.
Turns out I messed up with the equations I was using for Runge Kutta
The correct code is the following:
import numpy as np
from math import pi
from numpy import arange
from matplotlib.pyplot import plot, show
#parameters
R0 = 200
R1 = 250
L = 15
h = 0.002
Vo=1000
C=4.2*10**(-6)
t0=0
#dz/dz
def G(x,y,z):
return Vo/L -(R0/L)*z -(R1/L)*z**3 - y/(L*C)
#dy/dx
def F(x,y,z):
return z
t = np.arange(t0, 0.93, h)
x = np.zeros(len(t))
y = np.zeros(len(t))
z = np.zeros(len(t))
y[0] = 0.0
z[0] = 0
for i in range(1, len(t)):
k0=h*F(x[i-1],y[i-1],z[i-1])
l0=h*G(x[i-1],y[i-1],z[i-1])
k1=h*F(x[i-1]+h*0.5,y[i-1]+k0*0.5,z[i-1]+l0*0.5)
l1=h*G(x[i-1]+h*0.5,y[i-1]+k0*0.5,z[i-1]+l0*0.5)
k2=h*F(x[i-1]+h*0.5,y[i-1]+k1*0.5,z[i-1]+l1*0.5)
l2=h*G(x[i-1]+h*0.5,y[i-1]+k1*0.5,z[i-1]+l1*0.5)
k3=h*F(x[i-1]+h,y[i-1]+k2,z[i-1]+l2)
l3 = h * G(x[i - 1] + h, y[i - 1] + k2, z[i - 1] + l2)
y[i]=y[i-1]+(k0+2*k1+2*k2+k3)/6
z[i] = z[i - 1] + (l0 + 2 * l1 + 2 * l2 + l3) / 6
Q=y
I=z
plot(t, Q)
show()
plot(t, I)
show()
If I may draw your attention to these 4 lines
m1 = u
k1 = F(y, u, x) #(x, v, t)
m2 = h*(u + 0.5*k1)
k2 = (h*F(y+0.5*m1, u+0.5*k1, x+0.5*h))
You should note a fundamental structural difference between the first two lines and the second pair of lines.
You need to multiply with the step size h also in the first pair.
The next problem is the step size and the cubic term. It contributes a term of size 3*(R1/L)*u^2 ~ 50*u^2 to the Lipschitz constant. In the original IVP per the question with u=Vo/L ~ 70 this term is of size 2.5e+5. To compensate only that term to stay in the stability region of the method, the step size has to be smaller 1e-5.
In the corrected initial conditions with u=0 at the start the velocity u remains below 0.001 so the cubic term does not determine stability, this is now governed by the last term contributing a Lipschitz term of 1/sqrt(L*C) ~ 125. The step size for stability is now 0.02, with 0.002 one can expect quantitatively useful results.
You can use decimal libary for more precision (handle more digits), but it's kind of annoying every value should be the same class (decimal.Decimal).
For example:
import numpy as np
from math import pi
from numpy import arange
from matplotlib.pyplot import plot, show
# Import decimal.Decimal as D
import decimal
from decimal import Decimal as D
# Precision
decimal.getcontext().prec = 10_000_000
#parameters
# Every value should be D class (decimal.Decimal class)
R0 = D(200)
R1 = D(250)
L = D(15)
h = D(0.002)
Vo = D(1000)
C = D(4.2*10**(-6))
t = D(0.93)
def F(y, u, x):
# Decomposed for use D
a = D(Vo/L)
b = D(-(R0/L)*u)
c = D(-(R1/L)*u**D(3))
d = D(-y*(D(1)/L*C))
return ((a + b + c + d ))
xpoints = arange(0,t,h)
ypoints = []
upoints = []
y = D(0.0)
u = D(Vo/L)
for x in xpoints:
ypoints.append(y)
upoints.append(u)
m1 = u
k1 = F(y, u, x) #(x, v, t)
m2 = (h*(u + D(0.5)*k1))
k2 = (h*F(y+D(0.5)*m1, u+D(0.5)*k1, x+D(0.5)*h))
m3 = h*(u + D(0.5)*k2)
k3 = h*F(y+D(0.5)*m2, u+D(0.5)*k2, x+D(0.5)*h)
m4 = h*(u + k3)
k4 = h*F(y+m3, u+k3, x+h)
y += (m1 + D(2)*m2 + D(2)*m3 + m4)/D(6)
u += (k1 + D(2)*k2 + D(2)*k3 + k4)/D(6)
plot(xpoints, upoints)
show()
plot(xpoints, ypoints)
show()
But even with ten million of precision I still get an overflow error. Check the components of the formula, their values are way too high. You can increase precision for handle them, but you'll notice it takes time to calculate them.
Problem implementation using scipy.integrate.odeint and scipy.integrate.solve_ivp.
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint, solve_ivp
# Input data initial conditions
ti = 0.0
tf = 0.5
N = 100000
h = (tf-ti)/N
# Initial conditions
u0 = 0.0
Q0 = 0.0
t_span = np.linspace(ti,tf,N)
r0 = np.array([Q0,u0])
# Parameters
R0 = 200
R1 = 250
L = 15
C = 4.2*10**(-6)
V0 = 1000
# Systems of First Order Equations
# This function is used with odeint, as specified in the documentation for scipy.integrate.odeint
def f(r,t,R0,R1,L,C,V0):
Q,u = r
ode1 = u
ode2 = -((R0/L)*u)-((R1/L)*u**3)-((1/(L*C))*Q)+(V0/L)
return np.array([ode1,ode2])
# This function is used in our 4Order Runge-Kutta implementation and in scipy.integrate.solve_ivp
def F(t,r,R0,R1,L,C,V0):
Q,u = r
ode1 = u
ode2 = -((R0/L)*u)-((R1/L)*u**3)-((1/(L*C))*Q)+(V0/L)
return np.array([ode1,ode2])
# Resolution with oedint
sol_1 = odeint(f,r0,t_span,args=(R0,R1,L,C,V0))
sol_2 = solve_ivp(fun=F,t_span=(ti,tf), y0=r0, method='LSODA',args=(R0,R1,L,C,V0))
Q_odeint, u_odeint = sol_1[:,0], sol_1[:,1]
Q_solve_ivp, u_solve_ivp = sol_2.y[0,:], sol_2.y[1,:]
# Figures
plt.figure(figsize=[30.0,10.0])
plt.subplot(3,1,1)
plt.grid(color = 'red',linestyle='--',linewidth=0.4)
plt.plot(t_span,Q_odeint,'r',t_span,u_odeint,'b')
plt.xlabel('t(s)')
plt.ylabel('Q(t), u(t)')
plt.subplot(3,1,2)
plt.plot(sol_2.t,Q_solve_ivp,'g',sol_2.t,u_solve_ivp,'y')
plt.grid(color = 'yellow',linestyle='--',linewidth=0.4)
plt.xlabel('t(s)')
plt.ylabel('Q(t), u(t)')
plt.subplot(3,1,3)
plt.plot(Q_solve_ivp,u_solve_ivp,'green')
plt.grid(color = 'yellow',linestyle='--',linewidth=0.4)
plt.xlabel('Q(t)')
plt.ylabel('u(t)')
plt.show()
Runge-Kutta 4th
# Code development of Runge-Kutta 4 Order
# Parameters
R0 = 200
R1 = 250
L = 15
C = 4.2*10**(-6)
V0 = 1000
# Input data initial conditions #
ti = 0.0
tf = 0.5
N = 100000
h = (tf-ti)/N
# Initial conditions
u0 = 0.0
Q0 = 0.0
# First order ordinary differential equations
def f1(t,Q,u):
return u
def f2(t,Q,u):
return -((R0/L)*u)-((R1/L)*u**3)-((1/(L*C))*Q)+(V0/L)
t = np.zeros(N); Q = np.zeros(N); u = np.zeros(N)
t[0] = ti
Q[0] = Q0
u[0] = u0
for i in range(0,N-1,1):
k1 = h*f1(t[i],Q[i],u[i])
l1 = h*f2(t[i],Q[i],u[i])
k2 = h*f1(t[i]+(h/2),Q[i]+(k1/2),u[i]+(l1/2))
l2 = h*f2(t[i]+(h/2),Q[i]+(k1/2),u[i]+(l1/2))
k3 = h*f1(t[i]+(h/2),Q[i]+(k2/2),u[i]+(l2/2))
l3 = h*f2(t[i]+(h/2),Q[i]+(k2/2),u[i]+(l2/2))
k4 = h*f1(t[i]+h,Q[i]+k3,u[i]+l3)
l4 = h*f2(t[i]+h,Q[i]+k3,u[i]+l3)
Q[i+1] = Q[i] + ((k1+2*k2+2*k3+k4)/6)
u[i+1] = u[i] + ((l1+2*l2+2*l3+l4)/6)
t[i+1] = t[i] + h
plt.figure(figsize=[20.0,10.0])
plt.subplot(1,2,1)
plt.plot(t,Q_solve_ivp,'r',t,Q_odeint,'y',t,Q,'b')
plt.grid(color = 'yellow',linestyle='--',linewidth=0.4)
plt.xlabel('t(s)')
plt.ylabel(r'$Q(t)_{Odeint}$, $Q(t)_{RK4}$')
plt.subplot(1,2,2)
plt.plot(t,Q_solve_ivp,'g',t,Q_odeint,'y',t,Q,'b')
plt.grid(color = 'yellow',linestyle='--',linewidth=0.4)
plt.xlabel('t(s)')
plt.ylabel(r'$Q(t)_{solve_ivp}$, $Q(t)_{RK4}$')
I am trying to solve a 4th order ODE
EI*(d4y/dx4) = -k*y
which is a version of an ODE for a foundation on soft soil.
My system of first-order equations is the following
y1' = y2
y2' = y3
y3' = y4
y4' = -k*y1
and the BCs
y3(0) = y3(L) = 0
y4(0) = -F/(EI)
y4(L) = 0
and my code
from scipy.integrate import solve_bvp
import numpy as np
F = 300 #kN
EI = 20000 #kNm2
D = 1 #m
M_E = 45000 #kN/m2
k = 1.4*M_E/D #kN/m3
L = 10 #m
x = np.linspace(0,L,101)
p = np.array([k,EI,F])
print(p)
def fun(x, y, p):
k = p[0]
EI = p[1]
return np.vstack((y[1],y[2],y[3],-k*y[0]/EI))
def bc(ya, yb, p):
F = p[2]
EI = p[1]
return np.array([ya[2], yb[2], ya[3]+F/EI, yb[3]])
y_a = np.zeros((4, x.size))
from scipy.integrate import solve_bvp
res_a = solve_bvp(fun, bc, x, y_a, p)
I get the following error:
#ValueError: 'bc' return is expected to have shape (7,), but actually has (4,).
Could you help me understand what I am doing wrong here and what the error means?
Thanks
So, after playing around with the code, I managed to make it work. The solution would be:
from scipy.integrate import solve_bvp
import numpy as np
F = 100 #kN
D = 1 #m
M_E = 50 #MN/m2
E_cm = 33600 #MN/m2
L = 10 #m
nodes = 40
x = np.linspace(0,L,nodes)
k = 1.4*M_E/D #kN/m3
EI = E_cm*0.25*np.pi*(D*0.5)**4 #kNm2
c =k*D/EI
def fun(x, y):
return np.vstack((y[1],y[2],y[3],-c*y[0]))
def bc(ya, yb):
return np.array([ya[2], yb[2], ya[3]+F/EI, yb[3]])
y_a = np.zeros((4, x.size))
res_a = solve_bvp(fun, bc, x, y_a)
y = res_a.sol(x)[0]*10**3
theta = res_a.sol(x)[1]*10**3
M = EI*res_a.sol(x)[2]
V = EI*res_a.sol(x)[3]
I hope this helps anyone who is struggling with implementing an ODE of orders higher than 2.
I am trying to implement the algorithm of GMRES with right-preconditioner P for solving the linear system Ax = b . The code is running without error; however, it pops into unprecise result for me because the error I have is very large. For the GMRES method (without preconditioning matrix - remove P in the algorithm), the error I get is around 1e^{-12} and it converges with the same matrix.
import numpy as np
from scipy import sparse
import matplotlib.pyplot as plt
from scipy.linalg import norm as norm
import scipy.sparse as sp
from scipy.sparse import diags
"""The program is to split the matrix into D-diagonal; L: strictly lower matrix; U strictly upper matrix
satisfying: A = D - L - U """
def splitMat(A):
n,m = A.shape
if (n == m):
diagval = np.diag(A)
D = diags(diagval,0).toarray()
L = (-1)*np.tril(A,-1)
U = (-1)*np.triu(A,1)
else:
print("A needs to be a square matrix")
return (L,D,U)
"""Preconditioned Matrix for symmetric successive over-relaxation (SSOR): """
def P_SSOR(A,w):
## Split up matrix A:
L,D,U = splitMat(A)
Comp1 = (D - w*U)
Comp2 = (D - w*L)
Comp1inv = np.linalg.inv(Comp1)
Comp2inv = np.linalg.inv(Comp2)
P = w*(2-w)*np.matmul(Comp1inv, np.matmul(D,Comp2inv))
return P
"""GMRES_SSOR using right preconditioning P:
A - matrix of linear system Ax = b
x0 - initial guess
tol - tolerance
maxit - maximum iteration """
def myGMRES_SSOR(A,x0, b, tol, maxit):
matrixSize = A.shape[0]
e = np.zeros((maxit+1,1))
rr = 1
rstart = 2
X = x0
w = 1.9 ## in ssor
P = P_SSOR(A,w) ### preconditioned matrix
### Starting the GMRES ####
for rs in range(0,rstart+1):
### first check the residual:
if rr<tol:
break
else:
r0 = (b-A.dot(x0))
rho = norm(r0)
e[0] = rho
H = np.zeros((maxit+1,maxit))
Qcol = np.zeros((matrixSize, maxit+1))
Qcol[:,0:1] = r0/rho
for k in range(1, maxit+1):
### Arnodi procedure ##
Qcol[:,k] =np.matmul(np.matmul(A,P), Qcol[:,k-1]) ### This step applies P here:
for j in range(0,k):
H[j,k-1] = np.dot(np.transpose(Qcol[:,k]),Qcol[:,j])
Qcol[:,k] = Qcol[:,k] - (np.dot(H[j,k-1], Qcol[:,j]))
H[k,k-1] =norm(Qcol[:,k])
Qcol[:,k] = Qcol[:,k]/H[k,k-1]
### QR decomposition step ###
n = k
Q = np.zeros((n+1, n))
R = np.zeros((n, n))
R[0, 0] = norm(H[0:n+2, 0])
Q[:, 0] = H[0:n+1, 0] / R[0,0]
for j in range (0, n+1):
t = H[0:n+1, j-1]
for i in range (0, j-1):
R[i, j-1] = np.dot(Q[:, i], t)
t = t - np.dot(R[i, j-1], Q[:, i])
R[j-1, j-1] = norm(t)
Q[:, j-1] = t / R[j-1, j-1]
g = np.dot(np.transpose(Q), e[0:k+1])
Y = np.dot(np.linalg.inv(R), g)
Res= e[0:n] - np.dot(H[0:n, 0:n], Y[0:n])
rr = norm(Res)
#### second check on the residual ###
if rr < tol:
break
#### Updating the solution with the preconditioned matrix ####
X = X + np.matmul(np.matmul(P,Qcol[:, 0:k]), Y) ### This steps applies P here:
return X
######
A = np.random.rand(100,100)
x = np.random.rand(100,1)
b = np.matmul(A,x)
x0 = np.zeros((100,1))
maxit = 100
tol = 0.00001
x = myGMRES_SSOR(A,x0,b,tol,maxit)
res = b - np.matmul(A,x)
print(norm(res))
print("Solution with gmres\n", np.matmul(A,x))
print("---------------------------------------")
print("b matrix:", b)
I hope anyone could help me figure out this!!!
I'm not sure where you got you "Symmetric_successive_over-relaxation" SSOR code from, but it appears to be wrong. You also seem to be assuming that A is symmetric matrix, but in your random test case it is not.
Following SSOR's Wikipedia entry, I replaced your P_SSOR function with
def P_SSOR(A,w):
L,D,U = splitMat(A)
P = 2/(2-w) * (1/w*D+L)*np.linalg.inv(D)*(1/w*D+L).T
return P
and your test matrix with
A = np.random.rand(100,100)
A = A + A.T
and your code works up to a 12 digit residual error.
I want to numerically solve a system of nonlinear equations and pass numpy ndarrays as inputs. Consider the arbitrary code below:
import numpy as np
from scipy.optimize import fsolve
def eqs(A, B, C, D):
eq1 = (A - B * np.sin(C)).tolist()
eq2 = [5 * B + D * np.sum(A * np.cos(C))]
return eq1 + eq2
n = 3
A = np.zeros((n))
A0 = np.random.rand(n)
B = 0.0
B0 = np.random.rand(1)[0]
C = np.random.rand(n)
D = np.random.rand(1)[0]
sol = fsolve(func = eqs, x0 = [A0, B0], args = [C, D])
which leads to
missing required positional arguments
error and changing the function to:
def eqs(A, B, C, D):
eq1 = A - B * np.sin(C)
eq2 = C[0] * B + D * np.sum(A * np.cos(C))
return [eq1, eq2]
also doesn't help. However, I highly doubt that the error has anything to do with passing ndarrays. One approach could be to change all the ndarrays to python lists back and forth. But then I would not be able to use numpy's vectorized functions like np.sin()...
I would appreciate if you could help me know how this should be done.
P.S. Equations above are just arbitrary and they may not have solutions at all.
Check if this solve your equation:
import numpy as np
from scipy.optimize import fsolve
def eqs(X, Y):
A, B = X[:3], X[3]
C, D = Y[:3], Y[3]
eq1 = A - B * np.sin(C)
eq2 = C[0] * B + D * np.sum(A * np.cos(C))
return np.append(eq1, eq2)
n = 3
A = np.zeros((n))
A0 = np.random.rand(n)
B = 0.0
B0 = np.random.rand(1)[0]
C = np.random.rand(n)
D = np.random.rand(1)[0]
sol = fsolve(func = eqs, x0 = np.append(A0, B0), args = np.append(C, D))
sol
Output:
array([ 0.e+000, -1.e-323, 5.e-324, -1.e-323])
These scipy.optimize functions require a function with a signature like
f(x, *args)
x is a array (often 1d) that the solver will vary; args is a tuple of arguments that are just passed through from the outside.
Change your eqs to fit this pattern
In [11]: def eqs(X, C, D):
...: A, B = X[:-1], X[-1]
...: eq1 = (A - B * np.sin(C)).tolist()
...: eq2 = [5 * B + D * np.sum(A * np.cos(C))]
...: return eq1 + eq2
...: n = 3
...: A0 = np.random.rand(n)
...: B0 = np.random.rand(1)
...:
...: C = np.random.rand(n)
...: D = np.random.rand(1)
Make a test call to eqs:
In [12]: eqs(np.concatenate((A0,B0)),C,D)
Out[12]:
[-0.28460532658572657,
-0.03649115738682615,
0.7625781482352719,
array([5.46430853])]
Now try it in the fsolve:
In [13]: fsolve(eqs, np.concatenate((A0,B0)), args=(C,D))
Out[13]: array([0., 0., 0., 0.])
I need to plot the DE equation, but I have no idea how to do that.
First, solve the problem.
#10527113
from sympy import *
import numpy as np
import matplotlib.pyplot as plt
# Solve the DE: 3y'' + 2y' +y = 0
x = symbols('x')
y = symbols('y', cls=Function)
diffeq1 = Eq(3*y(x).diff(x,x) + 2*y(x).diff(x) + y(x), 0)
ans1 = dsolve ( diffeq1, y(x) )
print ( ans1 )
Then the plotting part.
#plotting
#Let x : [0, 2*pi], c1 = 1 and c2 = 0
b = []
a = np.linspace( 0, 2*np.pi )
for k in a:
b.append(ans1.subs(x, k))
plt.plot(a, b, label="curve")
I got a right 'ans1' in my code, but I can't plot it successfully.
When you plot, you said in comments that c1 = 1 and c2 = 0 but you did not set it in your DE solution ans1. I added the substitution in your code as well as selecting the evaluation value of the solution for plotting.
from sympy import *
import numpy as np
import matplotlib.pyplot as plt
# Solve the DE: 3y'' + 2y' +y = 0
from sympy.solvers.ode import classify_sysode
x = symbols('x')
y = symbols('y', cls=Function)
diffeq1 = Eq(3*y(x).diff(x,x) + 2*y(x).diff(x) + y(x), 0)
ans1 = dsolve ( diffeq1, y(x) )
print ( ans1 )
# Eq(y(x), (C1*sin(sqrt(2)*x/3) + C2*cos(sqrt(2)*x/3))/exp(x)**(1/3))
print (ans1)
#plotting
# Let x : [0, 2*pi], c1 = 1 and c2 = 0
c1 = symbols('C1')
c2 = symbols('C2')
ans1 = ans1.subs(c1, 1) # substitute for c1
ans1 = ans1.subs(c2, 0) # substitute for c2
b = []
a = np.linspace( 0, 2*np.pi )
for k in a:
sol = ans1.subs(x, k)
b.append(sol.rhs) # select the value for plotting
plt.plot(a, b, label="curve")
plt.show()