I want to calculate integral of implicit function containing imaginary numbers
where f(iz) is something like:
and g(ix) is something like:
I want to calculate it numerically. Python scipy.quad
doesn't calculate integrals of imaginary numbers (explained in Code 1 below). Quadpy
isn't efficient also, because it passes entire numpy array instead of single values of integral (explained in code 2 below) and thus needs additional manipulation. So I am thinking about dividing integrals like in the way shown below (where Re is real part and Im is imaginary part):
and expanding above equation:
Can I do that?
And here are codes, where I show two ways to approach the problem.
Code 1:
First approach scipy.quad
. According to:
Use scipy.integrate.quad to integrate complex numbers
I tried dividing into real and imaginary parts and calculating integral values of them separately:
from scipy.integrate import quad
import numpy as np
import scipy
from scipy.special import jv
import math
import quadpy
B=8
m=4
M_x = 0.3
M_T = 1
theta=0.3
def f_D(x, z):
print("f_D:",z)
return 1*np.exp(1j*x)*z
def phi_0(z):
print("phi:",z)
return 2/(z*M_r(z))
def M_r(z):
print("M_r",z)
return np.sqrt(z*z)
def psi_D(z):
print("psi_D",z)
return quad(f_D, -0.5, 0.5, limit=50, args=(z))[0]
def integral_P_Vm(z):
print("Calling function, z=",z)
return M_r(z)**2*np.exp(1j*(phi_0(z)))*jv(m*B, ((m*B*z*np.sin(theta)/(1-M_x*np.cos(theta)))))*2*psi_D(z)
def integral_P_Vm_real(z):
print("Calling real function, z=",z)
# return np.real(2*np.exp(1j*(z))*jv(m*B, (B*z))*2)
return np.real(M_r(z)**2*np.exp(1j*(phi_0(z)))*jv(m*B, ((m*B*z*np.sin(theta)/(1-M_x*np.cos(theta)))))*2*psi_D(z))
def integral_P_Vm_imag(z):
print("Calling imag function, z=",z)
# return np.imag(2*np.exp(1j*(z))*jv(m*B, (B*z))*2)
return np.imag(M_r(z)**2*np.exp(1j*(phi_0(z)))*jv(m*B, ((m*B*z*np.sin(theta)/(1-M_x*np.cos(theta)))))*2*psi_D(z))
Quad_integral = quad(integral_P_Vm, 0, 1, limit=100)
P_Vm_integral_real = quad(integral_P_Vm_real, 0, 1, limit=100)
P_Vm_integral_imag = quad(integral_P_Vm_imag, 0, 1, limit=100)
print("Quad",Quad_integral)
print("Real part:",P_Vm_integral_real)
print("Imaginary part",P_Vm_integral_imag)
The output of this approach is:
Quad (-5.63500792439988e-12, 1.4665732299181548e-21)
Real part: (-5.63500792439988e-12, 1.4665732299181548e-21)
Imaginary part (9.08758050641791e-12, 3.696603118432144e-22)
As you can see, normal quad omits imaginary part and thus I am not sure if integral in def psi_D(z):
also needs to be divided into imaginary and real parts.
Code 2:
Second approach - Quadpy.quad
the code is:
from scipy.integrate import quad
import numpy as np
import scipy
from scipy.special import jv
import math
import quadpy
B=8
m=4
M_x = 0.3
M_T = 1
theta=0.3
def f_D(x, z):
print("f_D:",z)
return 1*np.exp(1j*x)*z
def phi_0(z):
print("phi:",z)
return 2/(z*M_r(z))
def M_r(z):
print("M_r",z)
return np.sqrt(z*z)
def psi_D(z):
print("psi_D",z)
return quad(f_D, -0.5, 0.5, limit=50, args=(z))[0]
def integral_P_Vm(z):
print("Calling function, z=",z)
return M_r(z)**2*np.exp(1j*(phi_0(z)))*jv(m*B, ((m*B*z*np.sin(theta)/(1-M_x*np.cos(theta)))))*2*psi_D(z)
Quadpy_integral = quadpy.quad(integral_P_Vm, 0, 1, limit=100)
print("Quadpy",Quadpy_integral)
and the error is in line 28:
Exception has occurred: TypeError
only size-1 arrays can be converted to Python scalars
I tried to overcome this error by iterating numpy array z by modyfing:
def psi_D(z):
print("psi_D",z)
return quad(f_D, -0.5, 0.5, limit=50, args=(z))[0]
into:
def psi_D(z):
print("psi_D",z)
for e in z:
print(e)
return quadpy.quad(f_D, -0.5, 0.5, limit=50, args=(e))[0]
But the iteration stops at first element in z array and I have an error:
Exception has occurred: TypeError
f_D() argument after * must be an iterable, not numpy.float64
I have no idea how to iterate over entire numpy array in this case.