Using MATLAB, I am trying to solve the equation using Newtons Method but keep printing the result "None". I am not sure where the mistake is as I do not want to tamper with the formula.
def newt(p):
maxIt = 1000
tol = 10^(-5)
for i in range(maxIt):
fp = 2*p**3 + p**2 - p + 1 #double * for exponent
fprimep = 6*p**2 + 2*p - 1 #f'p
p_new = p - fp/fprimep
if abs (p - p_new) < tol:
return p
p = p_new
#initial values
p0 = -1.2
p = newt(p0)
print(p)
The error in your code is due to a partial conversion from Matlab. You define tol = 10^(-5), but this is not exponentiation in Python, it is bitwise xor. Correcting that, you get the proper result:
def newt(p):
maxIt = 1000
tol = 1e-5 # Error was here
for i in range(maxIt):
fp = 2*p**3 + p**2 - p + 1 #double * for exponent
fprimep = 6*p**2 + 2*p - 1 #f'p
p_new = p - fp/fprimep
if abs (p - p_new) < tol:
return p
p = p_new
#initial values
p0 = -1.2
p = newt(p0)
print(p)
# -1.23375
As for the return value, your function returns None when the method does not converge. I'm not sure this was a intentional decision, but it is a good convention anyway, since it allows the user to know the method did not converge. A more robust method would be to throw an exception, maybe adding the guess at the time the iteration stopped and the convergence ratio.
Related
I am trying to solve a function in an annular domain that has a change of phase with respect to the angular direction of the annulus.
My attempt to solve it is the following:
import numpy as np
from scipy import integrate
def f(x0, y0):
r = np.sqrt(x0**2 + y0**2)
if r >= rIn and r <= rOut:
theta = np.arctan(y0 / x0)
R = np.sqrt((x - x0)**2 + (y - y0)**2 + z**2)
integrand = (np.exp(-1j * (k*R + theta))) / R
return integrand
else:
return 0
# Test
rIn = 0.5
rOut = 1.5
x = 1
y = 1
z = 1
k = 3.66
I = integrate.dblquad(f, -rOut, rOut, lambda x0: -rOut, lambda x0: rOut)
My problem is that I don't know how to get rid of the division by zero occuring when I evaluate theta.
Any help will be more than appreciated!
Use numpy.arctan2 instead, it will have problems only if both x and y are zero, in which case the angle is undetermined.
Also I see you that your integrand is complex, in this case you will probably have to handle real and imaginary part separately, as done here.
I am trying to simulate a physics situation that involves calculating very small numbers. When the numbers get too small the values become garbage and/or are rounded to zero which doesn't help me. I am also using the scipy constants module for certain constants. I am trying to calculate the position using Euler's Method and calculating the velocity using momentum. The physics isn't the important part in this problem.
I have tried using the decimal module but think I am running into problems when using decimal and scipy constants together. Also, when using Decimal, do i need to convert every variable into Decimal before calculating?
In the loop below, it can only compute about 3 values before the error occurs.
# Create the arrays for velocity and position
vx = sp.zeros(n+1)
vy = sp.zeros(n+1)
x = sp.zeros(n+1)
y = sp.zeros(n+1)
time = sp.zeros(n+1)
# Initialize our values
vx[0] = vx0
vy[0] = vy0
x[0] = x0
y[0] = y0
time[0] = 0
i = 0
while y[i] > 0:
step = math.sqrt(x[i]**2 + y[i]**2) / cs.c
vx[i + 1] = vx[i] + (((cs.hbar * cs.c) / (2*cs.electron_mass)) * (x[i] / (x[i]**2 + y[i]**2)))
vy[i + 1] = vy[i] + (((cs.hbar * cs.c) / (2*cs.electron_mass)) * (y[i] / (x[i]**2 + y[i]**2)))
x[i + 1] = x[i] + (vx[i] * step)
y[i + 1] = y[i] + (vy[i] * step)
i += 1
RuntimeWarning: invalid value encountered in double_scalars
First and foremost, I'd start with using natural units , with hbar=c=m=1. Then re-evaluate if underflow persists or not.
Let (0,0) and (Xo,Yo) be two points on a Cartesian plane. We want to determine the parabolic curve, Y = AX^2 + BX + C, which passes from these two points and has a given arc length equal to S. Obviously, S > sqrt(Xo^2 + Yo^2). As the curve must pass from (0,0), it should be C=0. Hence, the curve equation reduces to: Y = AX^2 + BX. How can I determine {A,B} knowing {Xo,Yo,S}? There are two solutions, I want the one with A>0.
I have an analytical solution (complex) that gives S for a given set of {A,B,Xo,Yo}, though here the problem is inverted... I can proceed by solving numerically a complex system of equations... but perhaps there is a numerical routine out there that does exactly this?
Any useful Python library? Other ideas?
Thanks a lot :-)
Note that the arc length (line integral) of the quadratic a*x0^2 + b*x0 is given by the integral of sqrt(1 + (2ax + b)^2) from x = 0 to x = x0. On solving the integral, the value of the integral is obtained as 0.5 * (I(u) - I(l)) / a, where u = 2ax0 + b; l = b; and I(t) = 0.5 * (t * sqrt(1 + t^2) + log(t + sqrt(1 + t^2)), the integral of sqrt(1 + t^2).
Since y0 = a * x0^2 + b * x0, b = y0/x0 - a*x0. Substituting the value of b in u and l, u = y0/x0 + a*x0, l = y0/x0 - a*x0. Substituting u and l in the solution of the line integral (arc length), we get the arc length as a function of a:
s(a) = 0.5 * (I(y0/x0 + a*x0) - I(y0/x0 - a*x0)) / a
Now that we have the arc length as a function of a, we simply need to find the value of a for which s(a) = S. This is where my favorite root-finding algorithm, the Newton-Raphson method, comes into play yet again.
The working algorithm for the Newton-Raphson method of finding roots is as follows:
For a function f(x) whose root is to be obtained, if x(i) is the ith guess for the root,
x(i+1) = x(i) - f(x(i)) / f'(x(i))
Where f'(x) is the derivative of f(x). This process is continued till the difference between two consecutive guesses is very small.
In our case, f(a) = s(a) - S and f'(a) = s'(a). By simple application of the chain rule and the quotient rule,
s'(a) = 0.5 * (a*x0 * (I'(u) + I'(l)) + I(l) - I(u)) / (a^2)
Where I'(t) = sqrt(1 + t^2).
The only problem that remains is calculating a good initial guess. Due to the nature of the graph of s(a), the function is an excellent candidate for the Newton-Raphson method, and an initial guess of y0 / x0 converges to the solution in about 5-6 iterations for a tolerance/epsilon of 1e-10.
Once the value of a is found, b is simply y0/x0 - a*x0.
Putting this into code:
def find_coeff(x0, y0, s0):
def dI(t):
return sqrt(1 + t*t)
def I(t):
rt = sqrt(1 + t*t)
return 0.5 * (t * rt + log(t + rt))
def s(a):
u = y0/x0 + a*x0
l = y0/x0 - a*x0
return 0.5 * (I(u) - I(l)) / a
def ds(a):
u = y0/x0 + a*x0
l = y0/x0 - a*x0
return 0.5 * (a*x0 * (dI(u) + dI(l)) + I(l) - I(u)) / (a*a)
N = 1000
EPSILON = 1e-10
guess = y0 / x0
for i in range(N):
dguess = (s(guess) - s0) / ds(guess)
guess -= dguess
if abs(dguess) <= EPSILON:
print("Break:", abs((s(guess) - s0)))
break
print(i+1, ":", guess)
a = guess
b = y0/x0 - a*x0
print(a, b, s(a))
Run the example on CodeSkulptor.
Note that due to the rational approximation of the arc lengths given as input to the function in the examples, the coefficients obtained may ever so slightly differ from the expected values.
The program needs to compute define integral with a predetermined
accuracy (eps) with the Trapezoidal Rule and my function needs to return:
1.the approximate value of the integral.
2.the number of iterations.
My code:
from math import *
def f1(x):
return (x ** 2 - 1)**(-0.5)
def f2(x):
return (cos(x)/(x + 1))
def integral(f,a,b,eps):
n = 2
x = a
h = (b - a) / n
sum = 0.5 * (f(a) + f(b))
for i in range(n):
sum = sum + f(a + i * h)
sum_2 = h * sum
k = 0
flag = 1
while flag == 1:
n = n * 2
sum = 0
k = k + 1
x = a
h = (b - a) / n
sum = 0.5 * (f(a) + f(b))
for i in range(n):
sum = sum + f(a + i * h)
sum_new = h * sum
if eps > abs(sum_new - sum_2):
t1 = sum_new
t2 = k
return t1, t2
else:
sum_2 = sum_new
x1 = float(input("First-begin: "))
x2 = float(input("First-end: "))
y1 = float(input("Second-begin: "))
y2 = float(input("Second-end: "))
int_1 = integral(f1,x1,y1,1e-6)
int_2 = integral(f2,x2,y2,1e-6)
print(int_1)
print(int_2)
It doesn't work correct. Help, please!
You implemented the math wrong. The error is in the lines
for i in range(n):
sum = sum + f(a + i * h)
range(n) always starts at 0, so in your first iteration you just add the f(a) term again.
If you replace it with
for i in range(1, n):
sum = sum + f(a + i * h)
it works.
Also, you have a ton of redundant code; you basically coded the core of the integration algorithm twice. Try to follow the DRY-principle.
The trapezoidal rule of integration simply says that an approximation to the integral $\int_a^b f(x) dx$ is (b-a) (f(a)+f(b))/2. The error is proportional to (b-a)^2, so that it is possible to have a better estimate using the composite rule, i.e., subdividing the initial interval in a number of shorter intervals.
Is it possible to use shorter intervals and still reuse the function values previously computed, so minimizing the total number of function evaluation?
Yes, it is possible if we divide each interval in two equal parts, so that at stage 0 we use 1 intervals, at stage 1 2 equal intervals and in general, at stage n, we use 2n equal intervals.
Let's start with a simple problem and see if it possible to generalize the procedure…
a, b = 0, 32
L = b-a = 32
by the trapezoidal rule the initial approximation say I0, is given by
I0 = L * (f0+f1)/2
= L * S0
with S0 = (f0+f1)/2; a pictorial representation of the real axis, the coordinates of the interval extremes and the evaluated functions follows
x0 x1
01234567890123456789012345679012
f0 f1
Next, we divide the original interval in two,
L = L/2
x0 x2 x1
01234567890123456789012345679012
f0 f2 f1
and the new approximation, stage n=1, is obtained using two times the trapezoidal rule and applying a bit of algebra
I1 = L * (f0+f2)/2 + L * (f2+f1)/2
= L * [(f0+f1)/2 + f2]
= L * [S0 + S1]
with S1 = f2
Another subdivision, stage n=2, L = L/2 and
x0 x3 x2 x4 x1
012345678901234567890123456789012
f0 f3 f2 f4 f1
I2 = L * [(f0+f3) + (f3+f2) + (f2+f4) + (f4+f1)] / 2
= L * [(f0+f1)/2 + f2 + (f3+f4)]
= L * [S0+S1+S2]
with S2 = f3 + f4.
It is not difficult, given this picture,
x0 x5 x3 x6 x2 x7 x4 x8 x1
012345678901234567890123456789012
f0 f5 f3 f6 f2 f7 f4 f8 f1
to understand that our next approximation can be computed as follows
L = L/2
S3 = f5+f6+f7+f8
I3 = L*[S0+S1+S2+S3]
Now, we have to understand how to compute a generalization of Sn,
n = 1, … — for us, the pseudocode is
L_n = (b-a)/2**n
list_x_n = list(a + L_n + 2*Ln*j for j=0, …, 2**n-1)
Sn = Sum(f(xj) for each xj in list_x_n)
For n = 3, L = (b-a)/8 = 4, we have from the formula above list_x_n = [4, 12, 20, 28], please check with the picture...
Now we are ready to code our algorithm in Python
def trapaezia(f, a, b, tol):
"returns integ(f, (a,b)), estimated error and number of evaluations"
from math import fsum # controls accumulation of rounding errors in sums
L = b - a
S = (f(a)+f(b))/2
I = L*S
n = 1
while True:
L = L/2
new_points = (a+L+j*L for j in range(0, n+n, 2))
delta_S = fsum(f(x) for x in new_points)
new_S = S + delta_S
new_I = L*new_S
# error is estimated using Richardson extrapolation (REP)
err = (new_I - I) * 4/3
if abs(err) > tol:
n = n+n
S, I = new_S, new_I
else:
# we return a better estimate using again REP
return (4*new_I-I)/3, err, n+n+1
If you are curious about Richardson extrapolation, I recommend this document that deals exactly with the application of REP to the trapezoidal rule quadrature algorithm.
If you are curious about math.fsum, the docs don't say too much but the link to the original implementation that also includes an extended explanation of all the issues involved.
I'm trying to approximate the Bessel function with Runge-Kutta. I'm using RK4 here cause I don't know what the equations are for RK2 for a system of ODEs.....Basically it's not working, or at least it's not working very well, I don't know why.
Anyway it's written in python. Here is code:
from __future__ import division
from pylab import*
#This literally just makes a matrix
def listoflists(rows,cols):
return [[0]*cols for i in range(rows)]
def f(x,Jm,Zm,m):
def rm(x):
return (m**2 - x**2)/(x**2)
def q(x):
return 1/x
return rm(x)*Jm-q(x)*Zm
n = 100 #No Idea what to set this to really
m = 1 #Bessel function order; computes up to m (i.e. 0,1,2,...m)
interval = [.01, 10] #Interval in x
dx = (interval[1]-interval[0])/n #Step size
x = zeros(n+1)
Z = listoflists(m+1,n+1) #Matrix: Rows are Function order, Columns are integration step (i.e. function value at xn)
J = listoflists(m+1,n+1)
x[0] = interval[0]
x[n] = interval[1]
#This reproduces all the Runge-Kutta relations if you read 'i' as 'm' and 'j' as 'n'
for i in range(m+1):
#Initial Conditions, i is m
if i == 0:
J[i][0] = 1
Z[i][0] = 0
if i == 1:
J[i][0] = 0
Z[i][0] = 1/2
#Generate each Bessel function, j is n
for j in range(n):
x[j] = x[0] + j*dx
K1 = Z[i][j]
L1 = f(x[j],J[i][j],Z[i][j],i)
K2 = Z[i][j] + L1/2
L2 = f(x[j] + dx/2, J[i][j]+K1/2,Z[i][j]+L1/2,i)
K3 = Z[i][j] + L2/2
L3 = f(x[j] +dx/2, J[i][j] + K2/2, Z[i][j] + L2/2,i)
K4 = Z[i][j] + L3
L4 = f(x[j]+dx,J[i][j]+K3, Z[i][j]+L3,i)
J[i][j+1] = J[i][j]+(dx/6)*(K1+2*K2+2*K3+K4)
Z[i][j+1] = Z[i][j]+(dx/6)*(L1+2*L2+2*L3+L4)
plot(x,J[0][:])
show()
(To close this old question with at least a partial answer.) The immediate error is that the RK4 method is incorrectly implemented. For instance instead of
K2 = Z[i][j] + L1/2
L2 = f(x[j] + dx/2, J[i][j]+K1/2, Z[i][j]+L1/2, i)
it should be
K2 = Z[i][j] + L1*dx/2
L2 = f(x[j] + dx/2, J[i][j]+K1*dx/2, Z[i][j]+L1*dx/2, i)
that is, the slopes have to be scaled by the step size to get the correct update for the variables.