Series calculation precision - python

I need to find the sum of the first N elements of the series to satisfy some precision e (10^-3, for example):
y = -(2x + (2x)^2/2 + (2x)^3/3 + ...)
The exact sum of y is log(1 - 2*x).
I wrote a program in python, but the difference W between sum and log turns out to be non-zero in case of set precision (the last significant digit is 1 or 2 in some samples).
from math import log
def y_func(x, e):
y = 0
nom = 2*x
den = 1
a = nom / den
while abs(a) > e:
y -= a
den += 1
nom *= 2*x
a = nom / den
return y
def main(p):
print(('{:{width}}'*4).format('X','Y','Z','W',width = 14))
prec = 10**-p
x = -.25
xk = .35
h = .05
while x <= xk:
Y = y_func(x, prec)
Z = log(1-2*x)
W = Y - Z
print(('{:<{width}.{prec}f}'*4).format(x, Y, Z, W, \
prec = p, width = 14))
x += h
if __name__ == "__main__":
main(3)

Well said #NPE, unfortunately this still doesn't fix the problem.
I wanted to call your attention to the fact that such series does not converge fast enough to allow you to say that if abs(a) < e then y's precision is e.
That means that even if you make your loop do that one more iteration you'll still have less (much less!) than e precision when x approaches .50.
To fix this once for all you should change your while to something like:
while abs(y - log(1-2*x)) >= e: # > or >= depending on what you need
# y = ...

You're stopping one iteration too early: you stop as soon as nom / den goes below the threshold, but before you've subtracted it from y.
In other words, you need to restructure your while loop.

Related

JUPYTER Newtons Method

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.

Probability when throwing dice

n = 5
k = 3
x = 1
for i in range(1, n + 1):
x = x * i
y = 1
for i in range(1, k + 1):
y = y * i
z = 1
for i in range(1, n - k + 1):
z = z * i
c = x / (y * z)
p = 1
for i in range(k):
p = p * (1 / 6)
q = 1
for i in range(n - k):
q = q * (5 / 6)
result = c * p * q
So the following code calculates the probability of seeing exactly 3 sixes when throwing 5 dice. However, I'm unsure about the loops in this code.
I'm aware that:
n = number of trials
k = number of successes
And p/q success/failure?
But what are the loops doing and I'm unsure about the variables x,y,z and c. Traditionally I would just use powers to get the answer for these types of questions but I'm unsure about this method.
Thank you
Seems like c is the binomial coefficient, used in this probability calculation.
and the loops are used to calculate the required factorials (x is n!, y is k!, and z is (n-k)!).
The loops for p and q are indeed used to calculate the powers of success/fail probabilities.
This code would be much nicer using pow and math.factorial

Monte Carlo simulation of a system of Lennard-Jones + FENE potential

I want to generate two linear chains of 20 monomers each at some distance to each other. The following code generates a single chain. Could someone help me with how to generate the second chain?
The two chains are fixed to a surface i.e the first monomer of the chain is fixed and the rest of the monomers move freely in x-y-z directions but the z component of the monomers should be positive.
Something like this:
import numpy as np
import numba as nb
#import pandas as pd
#nb.jit()
def gen_chain(N):
x = np.zeros(N)
y = np.zeros(N)
z = np.linspace(0, (N)*0.9, num=N)
return np.column_stack((x, y, z)), np.column_stack((x1, y1, z1))
#coordinates = np.loadtxt('2GN_50_T_10.txt', skiprows=199950)
#return coordinates
#nb.jit()
def lj(rij2):
sig_by_r6 = np.power(sigma**2 / rij2, 3)
sig_by_r12 = np.power(sigma**2 / rij2, 6)
lje = 4 * epsilon * (sig_by_r12 - sig_by_r6)
return lje
#nb.jit()
def fene(rij2):
return (-0.5 * K * np.power(R, 2) * np.log(1 - ((np.sqrt(rij2) - r0) / R)**2))
#nb.jit()
def total_energy(coord):
# Non-bonded energy.
e_nb = 0.0
for i in range(N):
for j in range(i - 1):
ri = coord[i]
rj = coord[j]
rij = ri - rj
rij2 = np.dot(rij, rij)
if (rij2 < rcutoff_sq):
e_nb += lj(rij2)
# Bonded FENE potential energy.
e_bond = 0.0
for i in range(1, N):
ri = coord[i]
rj = coord[i - 1] # Can be [i+1] ??
rij = ri - rj
rij2 = np.dot(rij, rij)
e_bond += fene(rij2)
return e_nb + e_bond
#nb.jit()
def move(coord):
trial = np.ndarray.copy(coord)
for i in range(1, N):
while True:
delta = (2 * np.random.rand(3) - 1) * max_delta
trial[i] += delta
#while True:
if trial[i,2] > 0.0:
break
trial[i] -= delta
return trial
#nb.jit()
def accept(delta_e):
beta = 1.0 / T
if delta_e < 0.0:
return True
random_number = np.random.rand(1)
p_acc = np.exp(-beta * delta_e)
if random_number < p_acc:
return True
return False
if __name__ == "__main__":
# FENE potential parameters.
K = 40.0
R = 0.3
r0 = 0.7
# L-J potential parameters
sigma = 0.5716
epsilon = 1.0
# MC parameters
N = 20 # Numbers of monomers
rcutoff = 2.5 * sigma
rcutoff_sq = rcutoff * rcutoff
max_delta = 0.01
n_steps = 100000
T = 10
# MAIN PART OF THE CODE
coord = gen_chain(N)
energy_current = total_energy(coord)
traj = open('2GN_20_T_10.xyz', 'w')
traj_txt = open('2GN_20_T_10.txt', 'w')
for step in range(n_steps):
if step % 1000 == 0:
traj.write(str(N) + '\n\n')
for i in range(N):
traj.write("C %10.5f %10.5f %10.5f\n" % (coord[i][0], coord[i][1], coord[i][2]))
traj_txt.write("%10.5f %10.5f %10.5f\n" % (coord[i][0], coord[i][1], coord[i][2]))
print(step, energy_current)
coord_trial = move(coord)
energy_trial = total_energy(coord_trial)
delta_e = energy_trial - energy_current
if accept(delta_e):
coord = coord_trial
energy_current = energy_trial
traj.close()
I except the chain of particles to collapse into a globule.
There is some problem with the logic of the MC you are implementing.
To perform a MC you need to ATTEMPT a move, evaluate the energy of the new state and then accept/reject according to a random number.
In your code there is not the slightest sign of the attempt to move a particle.
You need to move one (or more of them), evaluate the energy, and then update your coordinates.
By the way, I suppose this is not your entire code. There are many parameters that are not defined like the "k" and the "R0" in your fene potential
The FENE potential models bond interactions. What your code is saying is that all particles within the cutoff are bonded by FENE springs, and that the bonds are not fixed but rather defined by the cutoff. With a r_cutoff = 3.0, larger than equilibrium distance of the LJ well, you are essentially considering that each particle is bonded to potentially many others. You are treating the FENE potential as a non-bonded one.
For the bond interactions you should ignore the cutoff and only evaluate the energy for the actual pairs that are bonded according to your topology, which means that first you need to define a topology. I suggest generating a linear molecule of N atoms in a box big enough to contain the whole stretched molecule, and consider the i-th atom as bonded to the (i-1)-th atom, with i = 2, ..., N. In this way the topology is well defined and persistent. Then consider both interactions separately, non-bonded and bond, and add them at the end.
Something like this, in pseudo-code:
e_nb = 0
for particle i = 1 to N:
for particle j = 1 to i-1:
if (dist(i, j) < rcutoff):
e_nb += lj(i, j)
e_bond = 0
for particle i = 2 to N:
e_bond += fene(i, i-1)
e_tot = e_nb + e_bond
Below you can find a modified version of your code. To make things simpler, in this version there is no box and no boundary conditions, just a chain in free space. The chain is initialized as a linear sequence of particles each distant 80% of R0 from the next, since R0 is the maximum length of the FENE bond. The code considers that particle i is bonded with i+1 and the bond is not broken. This code is just a proof of concept.
#!/usr/bin/python
import numpy as np
def gen_chain(N, R):
x = np.linspace(0, (N-1)*R*0.8, num=N)
y = np.zeros(N)
z = np.zeros(N)
return np.column_stack((x, y, z))
def lj(rij2):
sig_by_r6 = np.power(sigma/rij2, 3)
sig_by_r12 = np.power(sig_by_r6, 2)
lje = 4.0 * epsilon * (sig_by_r12 - sig_by_r6)
return lje
def fene(rij2):
return (-0.5 * K * R0**2 * np.log(1-(rij2/R0**2)))
def total_energy(coord):
# Non-bonded
e_nb = 0
for i in range(N):
for j in range(i-1):
ri = coord[i]
rj = coord[j]
rij = ri - rj
rij2 = np.dot(rij, rij)
if (rij2 < rcutoff):
e_nb += lj(rij2)
# Bonded
e_bond = 0
for i in range(1, N):
ri = coord[i]
rj = coord[i-1]
rij = ri - rj
rij2 = np.dot(rij, rij)
e_bond += fene(rij2)
return e_nb + e_bond
def move(coord):
trial = np.ndarray.copy(coord)
for i in range(N):
delta = (2.0 * np.random.rand(3) - 1) * max_delta
trial[i] += delta
return trial
def accept(delta_e):
beta = 1.0/T
if delta_e <= 0.0:
return True
random_number = np.random.rand(1)
p_acc = np.exp(-beta*delta_e)
if random_number < p_acc:
return True
return False
if __name__ == "__main__":
# FENE parameters
K = 40
R0 = 1.5
# LJ parameters
sigma = 1.0
epsilon = 1.0
# MC parameters
N = 50 # number of particles
rcutoff = 3.5
max_delta = 0.01
n_steps = 10000000
T = 1.5
coord = gen_chain(N, R0)
energy_current = total_energy(coord)
traj = open('traj.xyz', 'w')
for step in range(n_steps):
if step % 1000 == 0:
traj.write(str(N) + '\n\n')
for i in range(N):
traj.write("C %10.5f %10.5f %10.5f\n" % (coord[i][0], coord[i][1], coord[i][2]))
print(step, energy_current)
coord_trial = move(coord)
energy_trial = total_energy(coord_trial)
delta_e = energy_trial - energy_current
if accept(delta_e):
coord = coord_trial
energy_current = energy_trial
traj.close()
The code prints the current configuration at each step, you can just load it up on VMD and see how it behaves. The bonds will not show correctly at first on VMD, you must use a bead representation for the particles and define the bonds manually or with a script within VMD. In any case, you don't need to see the bonds to notice that the chain does not collapse.
Please bear in mind that if you want to simulate a chain at a certain density, you need to be careful to generate the correct topology. I recommend the EMC package to efficiently generate polymers at the desired thermodynamic conditions. It is by no means a trivial problem, especially for larger chains.
By the way, your code had an error in the FENE energy evaluation. rij2 is already squared, you squared it again.
Below you can see how the total energy as a function of the number of steps behaves for T = 1.0, N = 20, rcutoff = 3.5, and also the last current configuration after 10 thousand steps.
And below for N = 50, T = 1.5, max_delta = 0.01, K = 40, R = 1.5, rcutoff = 3.5, and 10 million steps. This is the last current configuration.
The full "trajectory", which isn't really a trajectory since this is MC, you can find here (it's under 6 MB).

Python newton raphson; precision in calculations

I've written this function in python:
def f2(x):
return (5.0*x + log1p(x) - 10000.0)
def dfdx2(x):
return (5.0-(1.0/x))
def newtonRaphson2(f, dfdx, x, tol):
x0 = x
for i in range(1, 2000):
if f(x) == 0.0:
return x
if dfdx(x) == 0.0:
print(dfdx(x))
break
x = x - (f(x) / dfdx(x))
#print(x)
Er = abs(x0-x)/abs(x0)
if Er <= tol:
return x
print(Er)
x0 = x
return x
Then I execute it like this:
task2 = newtonRaphson2(f2, dfdx2, 1, 0.000001);
print(task2)
For the output check the Er outputs final accuracy of 4.245665128208564e-05 before it returns x.
X is returned at 1998.479871524306, which is a pretty good estimate, but I'm preferably looking to get it down to 1.0e-06 at least. Changing tol variable to 1.0e-08 seems to do nothing.
I'm guessing maybe putting every variable into double is a better idea, but I still have no idea why my code stops where it does. I'm not that stable with python either, which is why I'm asking. I've already written one of these that works, but its for a far simpler equation.
Your code works fine, once you indent it properly and add from math import log1p . Just put the print(Er) line right after it's calculated to see its final value. Er gets to ~10^-9. This worked for me:
from math import log1p
def f2(x):
return (5.0*x + log1p(x) - 10000.0)
def dfdx2(x):
return (5.0-(1.0/x))
def newtonRaphson2(f, dfdx, x, tol):
x0 = x
for i in range(1, 2000):
if f(x) == 0.0:
return x
if dfdx(x) == 0.0:
print(dfdx(x))
break
x = x - (f(x) / dfdx(x))
#print(x)
Er = abs(x0-x)/abs(x0)
print('Er = {}'.format(Er))
if Er <= tol:
return x
x0 = x
return x
x = newtonRaphson2(f2, dfdx2, 1, 0.0000001)
print 'X = {}'.format(x)
The output was:
Er = 2498.5767132
Er = 0.200506616666
Er = 4.24566512821e-05
Er = 8.49642413214e-09
X = 1998.47987152
Consider using while here. Newton-Raphson algorithm typically converges very fast, so you won't need many iterations to run most cases.
This gives the same result:
from math import log1p
def f2(x):
return (5.0*x + log1p(x) - 10000.0)
def dfdx2(x):
return (5.0-(1.0/x))
def newtonRaphson2(f, dfdx, x, tol):
x0 = x
Er = 1
while Er >= tol:
if f(x) == 0.0:
return x
if dfdx(x) == 0.0:
print(dfdx(x))
break
x = x - (f(x) / dfdx(x))
#print(x)
Er = abs(x0-x)/abs(x0)
print('Er = {}'.format(Er))
x0 = x
return x
x = newtonRaphson2(f2, dfdx2, 1, 0.0000001)
print 'X = {}'.format(x)
As #alex-dubrovsky metioned, calculation that imply convergence should be implemented with conditional cycles, i.e.:
while True:
if f(x) == 0.0:
return x
if dfdx(x) == 0.0:
print(dfdx(x))
break
x = x - (f(x) / dfdx(x))
#print(x)
Er = abs(x0-x)/abs(x0)
if Er <= tol:
return x
print(Er)
x0 = x
With this approach you're always at risk of infinite loop, but this is more or less fine, as algo implies "running until converged"

how to do this interpolation formula faster?

I have a function of Everett interpolation and I'd like to make it a little bit faster than it is right now. It works very well b
x and y are the parameters: time and values.
xi is the time which I want to have interpolated value.
def everett(x,y,xi):
'''
function everett
INPUT:
x list float
y list float
xi float
RETURN:
yi float
'''
n = len(x) #interpolation degree
h = x[1]-x[0] #differences between epochs
D = np.zeros([n,n+1])
D[:,0] = x
D[:,1] = y
for j in range(1,n): #loop to each column
for i in range(0,n-j): #loop to cell within a column
D[i,j+1] = D[i+1,j] - D[i,j]
#Finding the value of u
for i in range(0,n):
u = ( xi - x[i] ) / h
if u == 0:
return y[i]
elif( u > 0 and u < 1.0 ):
break
if i == n-1:
return None
z = i
w = 1 - u
i = 0
yi = 0
m1 = u
m2 = w
for j in range(1,n+1,2):
yi += m1 * D[z+1-i,j] + m2 * D[z-i,j]
i = i + 1
m1 *= (u - i) * (u + i) / ((j+1)*(j+2))
m2 *= (w - i) * (w + i) / ((j+1)*(j+2))
if (z-i)<0 or (z+1-i)>(n-j-1):
break #//checks validity of index in the table
return yi
Thx!
EDIT: some modification using numpy
I change this part of code:
#Finding the value of u
for i in range(0,n):
u = ( xi - x[i] ) / h
if u == 0:
return y[i]
elif( u > 0 and u < 1.0 ):
break
if i == n-1:
return None
by this one:
#Finding the value of u
u = (xi - x) /h
u0 = np.where(u == 0)[0]
if u0.size:
return y[u0[0]]
i = np.where((u > 0) & (u < 1.0))[0]
if not i.size:
return None
z = i[0]
u = u[z]
the biggest problem I have right now is how to modify the last loop and the first loop where variable D is filled with values.
Any ideas?
Include numpy, put the data into numpy.array()s and use numpy operations. You'll simplify your code and get, potentially, orders of magnitude better performance. If you're comfortable with Matlab, you'll find numpy easy to learn.
Loops like
for i in range(0,n):
u = ( xi - x[i] ) / h
become simple one liners:
u = (xi - x) / h
(where x is an array, u will be an array and the - and / will do element-wise arithmetic if xi and h are numbers)
This even works for whole arrays. For example, a forward difference can be expressed in 1D as
Dx = X[1:] - x[:1]
The X[1:] means the elements of X excluding the first and X[:1] means the elements of X excluding the last.
You can do the same on N-dimensional arrays, eliminating nested loops.
I wrote this article a long time ago, but it's still relevant. You'll see where I use numpy to speed up a finite difference calculation on a mesh (solving the 2D diffusion equation) while also simplifying the code: http://www.timteatro.net/2010/10/29/performance-python-solving-the-2d-diffusion-equation-with-numpy/
If I get a chance, I will come back and help you work on your specific code. But actually, I think this algorithm is a perfect project to introduce yourself to numpy.
And, if you're more interested in the result than you are the method, SciPy (an extension of numpy) has interpolation functions:
http://docs.scipy.org/doc/scipy/reference/tutorial/interpolate.html

Categories