Combining Lebedev and Gauss chebyshev quadratures

51 Views Asked by At

My problem is that I need to compute 3D integrals, and I need to combine a Gauss-Chebyshev (for the radial part + variable substitution) and a Lebedev quadrature (for the solid angle/unit sphere surface part).

The first part is to process the quadrature points :

import numpy as np
import matplotlib.pyplot as plt
from numpy.linalg import norm
pi = np.pi

##########################
# Quadrature weights/points
##########################

# for radial component
Nr = 30
ii  = np.arange(1,Nr+1).reshape(-1,1) 
sin_i = np.sin(ii*pi/(Nr+1))
cos_i = np.cos(ii*pi/(Nr+1))

# Chebyshev quadrature points on [-1,1]
Mu_quadrature = (Nr+1.0-2.0*ii)/(Nr+1.0) + 2.0/pi*(1.0 + 2.0/3.0*sin_i**2)*cos_i*sin_i

# Chebyshev quadrature points on [0, +infty [
# Bragg-slater Radius for Hydrogen
rm = 0.35 # Angstrom
# variable substitution for the radial component 
R_quadrature = rm*(1+Mu_quadrature)/(1-Mu_quadrature)

# Chebyshev quadrature weights
Wr_quadrature = 16.0/3.0/(Nr+1)*sin_i**4

##########################
# Quadrature for solid angle / angular coordinates
##########################

# file containing integration points (theta/phi in deg) and associated weights
fn = 'lebedenev_quadrature.txt'
Data = np.loadtxt(fn)
ThetaPhi_quadrature = Data[:,:2]

# convert to rad
ThetaPhi_quadrature = ThetaPhi_quadrature*pi/180.0
Wangular_quadrature = Data[:,2:3]

# make a tensor product of the Quadrature points
X_spherical_int = np.concatenate([
        np.tile(R_quadrature,(len(ThetaPhi_quadrature),1)),
        np.repeat(ThetaPhi_quadrature,len(R_quadrature),axis=0)   
    ],
    axis=1
)

R_int   = X_spherical_int[:,0:1]
Theta_int = X_spherical_int[:,1:2]
Phi_int = X_spherical_int[:,2:3]

Mu_int  = (R_int - rm)/(R_int + rm)

Wint = np.concatenate([
        np.tile(Wr_quadrature,(len(Wangular_quadrature),1)),
        np.repeat(Wangular_quadrature,len(Wr_quadrature),axis=0)   
    ],
    axis=1
)
Wint = np.prod(Wint,axis=1,keepdims=True)

X_cartesian_int = np.zeros_like(X_spherical_int)
R, Theta, Phi = R_int, Theta_int, Phi_int
Mu = (R - rm)/(R + rm)
X_cartesian_int[:,0:1] = R*np.cos(Theta)*np.sin(Phi)
X_cartesian_int[:,1:2] = R*np.sin(Theta)*np.sin(Phi)
X_cartesian_int[:,2:3] = R*np.cos(Phi)

The file containing the Lebedev quadrature points can be found here. At the bottom of the page as text files.

Then comes the tests, I tested the Chebyshev quadrature with the Gauss integral :

#################################
# Testing integration
#################################
def f(X):
    return np.exp(-np.sum(X,axis=1,keepdims=True)**2)

# solution
I1 = np.sqrt(pi)/2

# quadrature
I2 = np.einsum(
    'ij,ij',
    f(R_quadrature)*2.0*rm/(1-Mu_quadrature)**2,
    Wr_quadrature
)

print(f'Testing Gauss-Chebyshev quadrature with Gauss Integral :\n I1 = {I1} | I2 = {I2} | I1-I2 = {I1-I2}\n')

In case, you are woundering with there is the

2.0*rm/(1-Mu_quadrature)**2

This is because the Chebyshev quadrature is on $\mu \in [-1,1]$, the actual integration on $r\in R⁺$ and the variable substitution is $r = r_m \frac{1+\mu}{1-\mu}$

The test of Lebedev with the surface of the unit sphere :

def f(Theta,Phi):
    return np.ones_like(Theta)

# solution
I1 = 4*pi #np.exp(-1)*4*pi

# quadrature
I2 = 4.0*pi*np.einsum(
    'ij,ij',
    f(ThetaPhi_quadrature[:,1:2],None),
    Wangular_quadrature
)
 
print(f'Testing Ledenev quadratude with Integral over unit sphere surface :\n I1 = {I1} | I2 = {I2} | I1-I2 = {I1-I2}\n')

Now I am trying to compute the volume of a sphere, but with no good results :

#""" Unit Sphere
def f(X):
    R = norm(X,axis=1,keepdims=True)
    return np.where(R<=1,1,0)
I1 = 4/3*pi
#"""

""" Testing with Gauss integral
def f(X):
    return np.exp(-norm(X,axis=1,keepdims=True)**2)
I1 = 4*pi*np.sqrt(pi)/2
#"""

I2 = 4*pi*np.einsum(
    'ij,ij',
    f(X_cartesian_int)*2.0*rm/(1-Mu_int)**2,
    Wint
)

print(f'Testing Ledenv + Chebyshev qudrature with Integral over unit sphere volume :\n I1 = {I1} | I2 = {I2} | I1-I2 = {I1-I2}\n')

The output is :

Testing Gauss-Chebyshev quadrature with Gauss Integral :
 I1 = 0.8862269254527579 | I2 = 0.8862570079725882 | I1-I2 = -3.0082519830276766e-05

Testing Ledenev quadratude with Integral over unit sphere surface :
 I1 = 12.566370614359172 | I2 = 12.566370614362953 | I1-I2 = -3.780087354243733e-12

Testing Ledenv + Chebyshev qudrature with Integral over unit sphere volume :
 I1 = 4.1887902047863905 | I2 = 12.623540989301834 | I1-I2 = -8.434750784515444

I also tried to only use spherical coordinates, but it did not work.

The full code :

import numpy as np
import matplotlib.pyplot as plt
from numpy.linalg import norm
pi = np.pi

##########################
# Quadrature weights/points
##########################

# for radial component
Nr = 30
ii  = np.arange(1,Nr+1).reshape(-1,1) 
sin_i = np.sin(ii*pi/(Nr+1))
cos_i = np.cos(ii*pi/(Nr+1))

# Chebyshev quadrature points on [-1,1]
Mu_quadrature = (Nr+1.0-2.0*ii)/(Nr+1.0) + 2.0/pi*(1.0 + 2.0/3.0*sin_i**2)*cos_i*sin_i

# Chebyshev quadrature points on [0, +infty [
# Bragg-slater Radius for Hydrogen
rm = 0.35 # Angstrom
# variable substitution for the radial component 
R_quadrature = rm*(1+Mu_quadrature)/(1-Mu_quadrature)

# Chebyshev quadrature weights
Wr_quadrature = 16.0/3.0/(Nr+1)*sin_i**4

##########################
# Quadrature for solid angle / angular coordinates
##########################

# file containing integration points (theta/phi in deg) and associated weights
fn = 'lebedenev_quadrature.txt'
Data = np.loadtxt(fn)
ThetaPhi_quadrature = Data[:,:2]

# convert to rad
ThetaPhi_quadrature = ThetaPhi_quadrature*pi/180.0
Wangular_quadrature = Data[:,2:3]

# make a tensor product of the Quadrature points
X_spherical_int = np.concatenate([
        np.tile(R_quadrature,(len(ThetaPhi_quadrature),1)),
        np.repeat(ThetaPhi_quadrature,len(R_quadrature),axis=0)   
    ],
    axis=1
)

R_int   = X_spherical_int[:,0:1]
Theta_int = X_spherical_int[:,1:2]
Phi_int = X_spherical_int[:,2:3]

Mu_int  = (R_int - rm)/(R_int + rm)

Wint = np.concatenate([
        np.tile(Wr_quadrature,(len(Wangular_quadrature),1)),
        np.repeat(Wangular_quadrature,len(Wr_quadrature),axis=0)   
    ],
    axis=1
)
Wint = np.prod(Wint,axis=1,keepdims=True)

X_cartesian_int = np.zeros_like(X_spherical_int)
R, Theta, Phi = R_int, Theta_int, Phi_int
Mu = (R - rm)/(R + rm)
X_cartesian_int[:,0:1] = R*np.cos(Theta)*np.sin(Phi)
X_cartesian_int[:,1:2] = R*np.sin(Theta)*np.sin(Phi)
X_cartesian_int[:,2:3] = R*np.cos(Phi)

#################################
# Testing integration
#################################
def f(X):
    return np.exp(-np.sum(X,axis=1,keepdims=True)**2)

# solution
I1 = np.sqrt(pi)/2

# quadrature
I2 = np.einsum(
    'ij,ij',
    f(R_quadrature)*2.0*rm/(1-Mu_quadrature)**2,
    Wr_quadrature
)

print(f'Testing Gauss-Chebyshev quadrature with Gauss Integral :\n I1 = {I1} | I2 = {I2} | I1-I2 = {I1-I2}\n')

def f(Theta,Phi):
    return np.ones_like(Theta)

# solution
I1 = 4*pi #np.exp(-1)*4*pi

# quadrature
I2 = 4.0*pi*np.einsum(
    'ij,ij',
    f(ThetaPhi_quadrature[:,1:2],None),
    Wangular_quadrature
)
 
print(f'Testing Ledenev quadratude with Integral over unit sphere surface :\n I1 = {I1} | I2 = {I2} | I1-I2 = {I1-I2}\n')

#""" Unit Sphere
def f(X):
    R = norm(X,axis=1,keepdims=True)
    return np.where(R<=1,1,0)
I1 = 4/3*pi
#"""

""" Testing with Gauss integral
def f(X):
    return np.exp(-norm(X,axis=1,keepdims=True)**2)
I1 = 4*pi*np.sqrt(pi)/2
#"""

I2 = 4*pi*np.einsum(
    'ij,ij',
    f(X_cartesian_int)*2.0*rm/(1-Mu_int)**2,
    Wint
)

print(f'Testing Ledenv + Chebyshev qudrature with Integral over unit sphere volume :\n I1 = {I1} | I2 = {I2} | I1-I2 = {I1-I2}\n')
```