Getting the derivatives of Legendre polynomials in Python - python

I have an expression for a gravitational potential (eq. 15 from here), and to calculate an orbit I need to evaluate the gravitational force which is the local gradient, and for me that means evaluating the derivative of the Legendre polynomials P2, P4 and P6 at single values tens of thousands of times.
I can calculate it using the expression in this question, but I'm wondering if there is a way to ask python for the derivative that doesn't explicitly involve me evaluating the derivative as a finite difference.
I couldn't find anything in SciPy to do this automatically. In numpy.polynomial.legendre.Legendre there is a deriv() method but I have no experience operating with polynomial classes.
What would be the fastest way to evaluate the first derivatives of low order Legendre polynomials, one value at a time suitably for numerical integration?

I am aware that this is an old question but still there is no answer on how to calculate the derivatives using numpy/scipy.
This is how it works with numpy and scipy only:
from scipy.special import legendre
import numpy as np
n = 2 # degree of Legendre polynomial
poly = legendre(n) # coefficients of n^th degree Legendre polynomial
polyd= poly.deriv() # coefficients of derivative of n^th degree Legendre Polynomial
x = np.linspace(0,1,10000) # arbitrary coordinates
evald = np.polyval(polyd,x) # evaluate derivative at desired coordinates(s)
Also the accepted answer above contains a small mistake (I am not able to comment yet maybe someone can edit the answer):
The derivative should read P2' = 3*x

If you just need the derivatives of P2, P4 and P6, that's easy enough to compute by hand and then write down as code... e.g.
P2 = .5 * (3 * x^2 - 1)
Therefore:
P2' = .75 * x
And you can write that in python as:
def P2_deriv(x):
return .75 * x
Things don't really get a whole lot faster than that ;-). If you need arbitrary legendre polynomials, well ... Things start to get a bit trickier at that point ...

Related

Compute the fraction of two functions in Fourier space and then apply inverse Fourier-transform

I want to calculate the fraction of two functions in Fourier-space where the numerator is the Fourier-transform of a known function and the denominator depends on Fourier-space variables.
Specifically I want to implement what I calculated in WolframAlpha:
My attempt to implement this formula in python:
import numpy as np
from scipy.special import erf
q = np.linspace(-2, 2,100)
Fu = np.fft.fft(np.exp(-q**2))
u = np.fft.fftfreq(len(Fu), d=0.1) # My attempt to calculate Fourier-space variable
Fu_proc = Fu/(1.0j*(u+1e-9)) # Add 1e-9 for numerical stability
Wq = np.fft.ifft(Fu_proc)
The result is very different from Wolfram's:
I guess the problem is that u is not what it should be. Note this is just a sanity-check problem, what I really want to implement is more complicated, but this simple example should work.
Help appreciated.
That's because the FFT is the works with the periodic functions, you would need an FFT of length infinity in order to make it work. You could also calculate the improper integrals.
In this case we know is that dividing by u in the spectral domain is calculating the integral in q on the original domain. Doing this in the frequency domain analytically is very interesting but if you want to compute numerically for this case it seems to me that the best approach is to compute the integral in the original domain.

Fitting Fresnel Equations Using Scipy

I am attempting a non-linear fit of Fresnel equations with data of reflectance against angle of incidence. Found on this site http://en.wikipedia.org/wiki/Fresnel_equations are two graphs that have a red and blue line. I need to basically fit the blue line when n1 = 1 to my data.
Here I use the following code where th is theta, the angle of incidence.
def Rperp(th, n, norm, constant):
numerator = np.cos(th) - np.sqrt(n**2.0 - np.sin(th)**2.0)
denominator = 1.0 * np.cos(th) + np.sqrt(n**2.0 - np.sin(th)**2.0)
return ((numerator / denominator)**2.0) * norm + constant
The parameters I'm looking for are:
the index of refraction n
some normalization to multiply by and
a constant to shift the baseline of the graph.
My attempt is the following:
xdata = angle[1:] * 1.0 # angle of incidence
ydata = greenDD[1:] # reflectance
params = curve_fit(Rperp, xdata, ydata)
What I get is a division of zero apparently and gives me [1, 1, 1] for the parameters. The Fresnel equation itself is the bit without the normalizer and the constant in Rperp. Theta in the equation is the angle of incidence also. Overall I am just not sure if I am doing this right at all to get the parameters.
The idea seems to be the first parameter in the function is the independent variable and the rest are the dependent variables going to be found. Then you just plug into scipy's curve_fit and it will give you a fit to your data for the parameters. If it is just getting around division of zero, which I had though might be integer division, then it seems like I should be set. Any help is appreciated and let me know if things need to be clarified (such as np is numpy).
Make sure to pass the arguments to the trigonometric functions, like sine, in radians, not degrees.
As for why you're getting a negative refractive index returned: it is because in your function, you're always squaring the refractive index. The curve_fit algorithm might end up in a local minimum state where (by accident) n is negative, because it has the same value as n positive.
Ideally, you'd add constraints to the minimization problem, but for this (simple) problem, just observe your formula and remember that a result of negative n is simply solved by changing the sign, as you did.
You could also try passing an initial guess to the algorithm and you might observe that it will not end up in the local minimum with negative value.

Integral of Intensity function in python

There is a function which determine the intensity of the Fraunhofer diffraction pattern of a circular aperture... (more information)
Integral of the function in distance x= [-3.8317 , 3.8317] must be about 83.8% ( If assume that I0 is 100) and when you increase the distance to [-13.33 , 13.33] it should be about 95%.
But when I use integral in python, the answer is wrong.. I don't know what's going wrong in my code :(
from scipy.integrate import quad
from scipy import special as sp
I0=100.0
dist=3.8317
I= quad(lambda x:( I0*((2*sp.j1(x)/x)**2)) , -dist, dist)[0]
print I
Result of the integral can't be bigger than 100 (I0) because this is the diffraction of I0 ... I don't know.. may be scaling... may be the method! :(
The problem seems to be in the function's behaviour near zero. If the function is plotted, it looks smooth:
However, scipy.integrate.quad complains about round-off errors, which is very strange with this beautiful curve. However, the function is not defined at 0 (of course, you are dividing by zero!), hence the integration does not go well.
You may use a simpler integration method or do something about your function. You may also be able to integrate it to very close to zero from both sides. However, with these numbers the integral does not look right when looking at your results.
However, I think I have a hunch of what your problem is. As far as I remember, the integral you have shown is actually the intensity (power/area) of Fraunhofer diffraction as a function of distance from the center. If you want to integrate the total power within some radius, you will have to do it in two dimensions.
By simple area integration rules you should multiply your function by 2 pi r before integrating (or x instead of r in your case). Then it becomes:
f = lambda(r): r*(sp.j1(r)/r)**2
or
f = lambda(r): sp.j1(r)**2/r
or even better:
f = lambda(r): r * (sp.j0(r) + sp.jn(2,r))
The last form is best as it does not suffer from any singularities. It is based on Jaime's comment to the original answer (see the comment below this answer!).
(Note that I omitted a couple of constants.) Now you can integrate it from zero to infinity (no negative radii):
fullpower = quad(f, 1e-9, np.inf)[0]
Then you can integrate from some other radius and normalize by the full intensity:
pwr = quad(f, 1e-9, 3.8317)[0] / fullpower
And you get 0.839 (which is quite close to 84 %). If you try the farther radius (13.33):
pwr = quad(f, 1e-9, 13.33)
which gives 0.954.
It should be noted that we introduce a small error by starting the integration from 1e-9 instead of 0. The magnitude of the error can be estimated by trying different values for the starting point. The integration result changes very little between 1e-9 and 1e-12, so they seem to be safe. Of course, you could use, e.g., 1e-30, but then there may be numerical instability in the division. (In this case there isn't, but in general singularities are numerically evil.)
Let us do one thing still:
import matplotlib.pyplot as plt
import numpy as np
x = linspace(0.01, 20, 1000)
intg = np.array([ quad(f, 1e-9, xx)[0] for xx in x])
plt.plot(x, intg/fullpower)
plt.grid('on')
plt.show()
And this is what we get:
At least this looks right, the dark fringes of the Airy disk are clearly visible.
What comes to the last part of the question: I0 defines the maximum intensity (the units may be, e.g. W/m2), whereas the integral gives total power (if the intensity is in W/m2, the total power is in W). Setting the maximum intensity to 100 does not guarantee anything about the total power. That is why it is important to calculate the total power.
There actually exists a closed form equation for the total power radiated onto a circular area:
P(x) = P0 ( 1 - J0(x)^2 - J1(x)^2 ),
where P0 is the total power.
Note that you also can get a closed form solution for your integration using Sympy:
import sympy as sy
sy.init_printing() # LaTeX like pretty printing in IPython
x,d = sy.symbols("x,d", real=True)
I0=100
dist=3.8317
f = I0*((2*sy.besselj(1,x)/x)**2) # the integrand
F = f.integrate((x, -d, d)) # symbolic integration
print(F.evalf(subs={d:dist})) # numeric evalution
F evaluates to:
1600*d*besselj(0, Abs(d))**2/3 + 1600*d*besselj(1, Abs(d))**2/3 - 800*besselj(1, Abs(d))**2/(3*d)
with besselj(0,r) corresponding to sp.j0(r).
They might be a singularity in the integration algorithm when doing the jacobian at x = 0. You can exclude this points from the integration with "points":
f = lambda x:( I0*((2*sp.j1(x)/x)**2))
I = quad(f, -dist, dist, points = [0])
I get then the following result (is this your desired result?)
331.4990321315221

Plotting Jacobi Elliptic Function

I've written program on Python using pygame library for plotting complex functions phase and modulus graphics.
I'm not programmer and don't have any math background. But now I want to know how I could numerically evaluate Jacobi Elliptic Function value in some point z. I've found definition of the function in Wikipedia Jacobi elliptic function and there was integral but I don't understand how I could use it to evaluate function value in point z of complex plane. I know how to numerically evaluate path integral form some point a to b in complex plane, but there are some theta and phi parameters and I don't understand it.
Could you help me?
I don't need Python code (I'll write it myself if I'll understand the principle) but it could be enough if you provide algorithm step by step how to do it.
You could just use mpmath.
from mpmath import ellipfun
print(ellipfun('cd', 1.0 + 2.0j, 0.5))
(1.90652944795345 + 0.225277477847159j)
scipyx, my collection of extensions to SciPy, has support for complex-valued arguments in Jacobi elliptic functions.
Install with
pip install scipyx
and use as
import scipyx as spx
u = 1.0 + 2.0j
m = 0.8
# sn, cn, dn, ph = scipy.special.ellipj(x, m) # not working
sn, cn, dn, ph = spx.ellipj(u, m)
If you're after plotting those, take a look at cplot (also by me):
Having read the article in Wikipedia Jacobi elliptic function and one at http://mysite.du.edu/~jcalvert/math/jacobi.htm I believe this to be an interpretation.
z is a point in the complex plain then z' is its complementary modulus where z'^2 = 1 - z^2
It seems to be the convention that for the Jacobi elliptic function k is used instead of z and that m is used for k^2 and k is such that k^2 is real and 0<k^2<1
the integral is a function u of two parameters k and phi
u(k,phi) = the integral as given
Note then that instead of starting with a z in the complex plane you are starting with a real m 0<k^2<1 and the results relate to the complex solutions of z^2=m
So for a given m you could numerically integrate for a range of values phi (for example 0 to 6π in steps of π/12) giving u
Now for a given m you have a data set plotting for u against phi
The elliptic function sn is the inverse of this ie given u what phi gives this u
So looking in the u data would give the phi results.
Note for a given u there would be more than one phi.

Python: Find principal value of an integral numerically

I'm solving the integral numerically using python:
where a(x) can take on any value; positive, negative, inside or outside the the [-1;1] and eta is an infinitesimal positive quantity. There is a second outer integral of which changes the value of a(x)
I'm trying to solve this using the Sokhotski–Plemelj theorem:
However this involves determining the principle value, which I can't find any method to in python. I know it's implemented in Matlab, but does anyone know of either a library or some other way of the determining the principal value in python (if a principle value exists)?
You can use sympy to evaluate the integral directly. Its real part with eta->0 is the principal value:
from sympy import *
x, y, eta = symbols('x y eta', real=True)
re(integrate(1/(x - y + I*eta), (x, -1, 1))).simplify().subs({eta: 0})
# -> log(Abs(-y + 1)/Abs(y + 1))
Matlab's symbolic toolbox int gives you the same result, of course (I'm not aware of other relevant tools in Matlab for this --- please specify if you know a specific one).
You asked about numerical computation of a principal value. The answer there is that if you only have a function f(y) whose analytical form or behavior you don't know, it's in general impossible to compute them numerically. You need to know things such as where the poles of the integrand are and what order they are.
If you on the other hand know your integral is of the form f(y) / (y - y_0), scipy.integrate.quad can compute the principal value for you, for example:
import numpy as np
from scipy import integrate, special
# P \int_{-1}^1 dx 1/(x - wvar) * (1 + sin(x))
print(integrate.quad(lambda x: 1 + np.sin(x), -1, 1, weight='cauchy', wvar=0))
# -> (1.8921661407343657, 2.426947531830592e-13)
# Check against known result
print(2*special.sici(1)[0])
# -> 1.89216614073
See here for details.

Categories

Resources