如何将scipy interp1d与mpmath quadosc结合使用

huangapple go评论56阅读模式
英文:

How to combine scipy interp1d with mpmath quadosc

问题

以下是你要翻译的内容:

I have a density function (from quantum mechanics calculations) to be multiplied with the spherical Bessel function with a momentum grid (momentum q 1d array, real space distance r 1d array, so need to calculate jn(q*r) 2d array). The product will be integrated across the real space to get results as a function of momentum (results in 1d array same shape as q).

The Bessel function has oscillation, while the density function fast decays over a threshold distance. I used the adaptive quadrature in quadpy which is fine when oscillation is slow but it fails with high oscillation (for high momentum values or high orders in Bessel functions). The mpmath quadosc could be a nice option, but currently I have the problem that "object arrays are not supported," which seems to be the same as in https://stackoverflow.com/questions/59440969/relation-between-mpmath-and-scipy-type-error, what would be the best way to solve it since the density function is calculated outside of the mpmath.

from mpmath import besselj, sqrt, pi, besseljzero, inf, quadosc
from scipy.interpolate import interp1d

n = 1
q = np.geomspace(1e-7, 500, 1000)
# let's create a fake Gaussian density
x = np.geomspace(1e-7, 10, 1000)
y = np.exp(-(x-5)**2)
density = interp1d(x, y, kind='cubic', fill_value=0, bounds_error=False)

# if we just want to integrate the spherical Bessel function
def spherical_jn(x, n=n):
    return besselj(n + 1 / 2, x) * sqrt(pi / 2 / x)
# this is fine
vals = quadosc(
    spherical_jn, [0, inf], zeros=lambda m: besseljzero(n + 1 / 2, m)
)

# now we want to integrate the spherical Bessel function times the density
def spherical_jn_density(x, n=n):
    grid = q[..., None] * x
    return besselj(n + 1 / 2, grid) * sqrt(pi / 2 / grid) * density(x)

# this will fail
vals_density = quadosc(
    spherical_jn_density, [0, inf], zeros=lambda m: besseljzero(n + 1 / 2, m)
)

Expect: an accurate integral of a highly oscillating spherical Bessel function with an arbitrary decaying function (decaying to zero at a large distance).

英文:

I have a density function (from quantum mechanics calculations) to be multiplied with the spherical Bessel function with a momentum grid (momentum q 1d array, real space distance r 1d array, so need to calculate jn(q*r) 2d array). The product will be integrated across the real space to get results as function of momentum (results in 1d array same shape as q).

The Bessel function has oscillation, while the density function fast decay over a threshold distance. I used the adaptive quadrature in quadpy which is fine when oscillation is slow but it fails with high oscillation (for high momentum values or high orders in Bessel functions). The mpmath quadosc could be a nice option, but currently I have the problem that "object arrays are not supported", which seems to be the same as in https://stackoverflow.com/questions/59440969/relation-between-mpmath-and-scipy-type-error, what would be the best way to solve it since the density function is calculated outside of the mpmath.

from mpmath import besselj, sqrt, pi, besseljzero, inf,quadosc
from scipy.interpolate import interp1d

n = 1
q = np.geomspace(1e-7, 500, 1000)
# lets create a fake gaussian density 
x = np.geomspace(1e-7, 10, 1000)
y = np.exp(-(x-5)**2)
density = interp1d(x,y,kind='cubic',fill_value=0,bounds_error=False)


# if we just want to integrate the spherical bessel function
def spherical_jn(x,n=n):
    return besselj(n + 1 / 2, x) * sqrt(pi / 2 / x)
# this is fine
vals = quadosc(
    spherical_jn, [0, inf], zeros=lambda m: besseljzero(n + 1 / 2, m)
)

# now we want to integrate the spherical bessel function times the density
def spherical_jn_density(x,n=lprimeprime):
    grid = q[..., None] *x
    return besselj(n + 1 / 2,  grid) * sqrt(pi / 2 / grid)*density(x)

# this will fail
vals_density = quadosc(
    spherical_jn_density, [0, inf], zeros=lambda m: besseljzero(n + 1 / 2, m)
)

Expect: an accurate integral of highly oscillating spherical Bessel function with arbitrary decaying function (decay to zero at large distance).

答案1

得分: 2

Your density 函数是可调用的,像这样工作:

In [33]: density(.5)
Out[33]: array(1.60522789e-09)

当给定一个 mpmath 对象时,它不起作用:

In [34]: density(mpmath.mpf(.5))
ValueError: object arrays are not supported

如果首先将 x 转换为普通的浮点数,则可以使用:

In [37]: density(float(mpmath.mpf(.5)))
Out[37]: array(1.60522789e-09)

调整你的函数:

def spherical_jn_density(x, n=1):
    print(repr(x))
    grid = q[..., None] * x
    return besselj(n + 1 / 2,  grid) * sqrt(pi / 2 / grid) * density(x)

并尝试运行 quadosc(使用较小的 q):

In [57]: vals_density = quadosc(
    ...:     spherical_jn_density, [0, inf], zeros=lambda m: besseljzero(n + 1 / 2, m))
mpf('0.506414729137261838698106')
TypeError: cannot create mpf from array([[mpf('5.06414729137261815781894e-8')],
       [mpf('0.000000473559111442409924364745')],
       [mpf('0.00000442835129247081824275722')],
       [mpf('0.0000414104484439061558283487')],
       [mpf('0.000387237851532012775822723')],
       [mpf('0.00362114295531604773233197')],
       [mpf('0.0338620727569835882851491')],
       [mpf('0.316651395857188250996884')],
       [mpf('2.96107409661232278850947')],
       [mpf('27.6896294168963266721213')]], dtype=object)

换句话说,

besselj(n + 1 / 2,  grid)

在尝试评估 density(x) 之前存在问题。mpmath 函数不适用于numpy数组,而许多numpy/scipy函数不适用于 mpmath 对象。

英文:

Your density is interp callable, which works like:

In [33]: density(.5)
Out[33]: array(1.60522789e-09)

It does not work when given a mpmath object:

In [34]: density(mpmath.mpf(.5))
ValueError: object arrays are not supported

It's ok if x is first converted to ordinary float:

In [37]: density(float(mpmath.mpf(.5)))
Out[37]: array(1.60522789e-09)

Tweaking your function:

def spherical_jn_density(x,n=1):
    print(repr(x))
    grid = q[..., None] *x
    return besselj(n + 1 / 2,  grid) * sqrt(pi / 2 /grid) * density(x)

and trying to run the quadosc (with a smaller q)

In [57]: vals_density = quadosc(
    ...:     spherical_jn_density, [0, inf], zeros=lambda m: besseljzero(n + 1 / 2, m))
mpf('0.506414729137261838698106')
TypeError: cannot create mpf from array([[mpf('5.06414729137261815781894e-8')],
       [mpf('0.000000473559111442409924364745')],
       [mpf('0.00000442835129247081824275722')],
       [mpf('0.0000414104484439061558283487')],
       [mpf('0.000387237851532012775822723')],
       [mpf('0.00362114295531604773233197')],
       [mpf('0.0338620727569835882851491')],
       [mpf('0.316651395857188250996884')],
       [mpf('2.96107409661232278850947')],
       [mpf('27.6896294168963266721213')]], dtype=object)

In other words,

besselj(n + 1 / 2,  grid)

is having problems, even before trying to evaluate density(x). mpmath functions don't work with numpy arrays; and many numpy/scipy functions don't work with mpmath objects.

huangapple
  • 本文由 发表于 2023年2月7日 00:56:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/75364320.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定