12

是否有可用于计算矢量场散度的函数?(在matlab中)我希望它存在于 numpy/scipy 中,但我无法使用 Google 找到它。

我需要计算div[A * grad(F)],在哪里

F = np.array([[1,2,3,4],[5,6,7,8]]) # (2D numpy ndarray)

A = np.array([[1,2,3,4],[1,2,3,4]]) # (2D numpy ndarray)

2D的grad(F)列表也是如此ndarray

我知道我可以像这样计算散度,但不想重新发明轮子。(我也希望得到更优化的东西)有人有建议吗?

4

10 回答 10

20

只是对每个阅读该内容的人的提示:

上面的函数不计算向量场的散度。它们对标量域 A 的导数求和:

结果 = dA/dx + dA/dy

与向量场相比(具有三维示例):

结果 = 总和 dAi/dxi = dAx/dx + dAy/dy + dAz/dz

为所有人投票!这在数学上是完全错误的。

干杯!

于 2014-12-09T10:12:22.570 回答
12

基于 Juh_ 的回答,但针对向量场公式的正确发散进行了修改

def divergence(f):
    """
    Computes the divergence of the vector field f, corresponding to dFx/dx + dFy/dy + ...
    :param f: List of ndarrays, where every item of the list is one dimension of the vector field
    :return: Single ndarray of the same shape as each of the items in f, which corresponds to a scalar field
    """
    num_dims = len(f)
    return np.ufunc.reduce(np.add, [np.gradient(f[i], axis=i) for i in range(num_dims)])

Matlab 的文档使用这个精确的公式(向下滚动到向量场的发散)

于 2017-05-03T12:16:05.057 回答
11
import numpy as np

def divergence(field):
    "return the divergence of a n-D field"
    return np.sum(np.gradient(field),axis=0)
于 2013-09-26T10:00:22.407 回答
10

@user2818943 的回答不错,不过可以稍微优化一下:

def divergence(F):
    """ compute the divergence of n-D scalar field `F` """
    return reduce(np.add,np.gradient(F))

时间:

F = np.random.rand(100,100)
timeit reduce(np.add,np.gradient(F))
# 1000 loops, best of 3: 318 us per loop

timeit np.sum(np.gradient(F),axis=0)
# 100 loops, best of 3: 2.27 ms per loop

大约快 7 倍: sumnp.gradient. 这是避免使用reduce


现在,在您的问题中,您的意思是 div[A * grad(F)]什么?

  1. about A * grad(F):A是一个二维数组,是一个二维数组grad(f)的列表。所以我认为这意味着将每个梯度场乘以A.
  2. 关于将散度应用于(按比例缩放A)梯度场尚不清楚。根据定义,div(F) = d(F)/dx + d(F)/dy + .... 我想这只是一个表述错误。

对于1,将求和的元素乘以Bi相同的因子A可以分解:

Sum(A*Bi) = A*Sum(Bi)

因此,您可以简单地通过以下方式获得此加权梯度:A*divergence(F)

如果À 是一个因子列表,每个维度一个,那么解决方案将是:

def weighted_divergence(W,F):
    """
    Return the divergence of n-D array `F` with gradient weighted by `W`

    ̀`W` is a list of factors for each dimension of F: the gradient of `F` over
    the `i`th dimension is multiplied by `W[i]`. Each `W[i]` can be a scalar
    or an array with same (or broadcastable) shape as `F`.
    """
    wGrad = return map(np.multiply, W, np.gradient(F))
    return reduce(np.add,wGrad)

result = weighted_divergence(A,F)
于 2014-01-15T10:01:59.573 回答
4

丹尼尔修改的是正确答案,让我更详细地解释自定义函数分歧:

函数np.gradient()定义为:np.gradient(f)= df/dx, df/dy, df/dz +...

但我们需要将 func 散度定义为: 散度 ( f) = dfx/dx + dfy/dy + dfz/dz +... = np.gradient( fx) + np.gradient(fy)+ np.gradient(fz)+ ...

让我们测试一下,与matlab中的发散示例进行比较

import numpy as np
import matplotlib.pyplot as plt

NY = 50
ymin = -2.
ymax = 2.
dy = (ymax -ymin )/(NY-1.)

NX = NY
xmin = -2.
xmax = 2.
dx = (xmax -xmin)/(NX-1.)

def divergence(f):
    num_dims = len(f)
    return np.ufunc.reduce(np.add, [np.gradient(f[i], axis=i) for i in range(num_dims)])

y = np.array([ ymin + float(i)*dy for i in range(NY)])
x = np.array([ xmin + float(i)*dx for i in range(NX)])

x, y = np.meshgrid( x, y, indexing = 'ij', sparse = False)

Fx  = np.cos(x + 2*y)
Fy  = np.sin(x - 2*y)

F = [Fx, Fy]
g = divergence(F)

plt.pcolormesh(x, y, g)
plt.colorbar()
plt.savefig( 'Div' + str(NY) +'.png', format = 'png')
plt.show()

在此处输入图像描述

---------- 更新版本:包括差异步骤----------------

感谢@henry 的评论,np.gradient默认步长为1,所以结果可能有些不匹配。我们可以提供自己的微分步骤。

#https://stackoverflow.com/a/47905007/5845212
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable

NY = 50
ymin = -2.
ymax = 2.
dy = (ymax -ymin )/(NY-1.)

NX = NY
xmin = -2.
xmax = 2.
dx = (xmax -xmin)/(NX-1.)


def divergence(f,h):
    """
    div(F) = dFx/dx + dFy/dy + ...
    g = np.gradient(Fx,dx, axis=1)+ np.gradient(Fy,dy, axis=0) #2D
    g = np.gradient(Fx,dx, axis=2)+ np.gradient(Fy,dy, axis=1) +np.gradient(Fz,dz,axis=0) #3D
    """
    num_dims = len(f)
    return np.ufunc.reduce(np.add, [np.gradient(f[i], h[i], axis=i) for i in range(num_dims)])

y = np.array([ ymin + float(i)*dy for i in range(NY)])
x = np.array([ xmin + float(i)*dx for i in range(NX)])

x, y = np.meshgrid( x, y, indexing = 'ij', sparse = False)

Fx  = np.cos(x + 2*y)
Fy  = np.sin(x - 2*y)

F = [Fx, Fy]
h = [dx, dy]



print('plotting')
rows = 1
cols = 2
#plt.clf()
plt.figure(figsize=(cols*3.5,rows*3.5))
plt.minorticks_on()


#g = np.gradient(Fx,dx, axis=1)+np.gradient(Fy,dy, axis=0) # equivalent to our func
g = divergence(F,h)
ax = plt.subplot(rows,cols,1,aspect='equal',title='div numerical')
#im=plt.pcolormesh(x, y, g)
im = plt.pcolormesh(x, y, g, shading='nearest', cmap=plt.cm.get_cmap('coolwarm'))
plt.quiver(x,y,Fx,Fy)
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
cbar = plt.colorbar(im, cax = cax,format='%.1f')


g = -np.sin(x+2*y) -2*np.cos(x-2*y)
ax = plt.subplot(rows,cols,2,aspect='equal',title='div analytical')
im=plt.pcolormesh(x, y, g)
im = plt.pcolormesh(x, y, g, shading='nearest', cmap=plt.cm.get_cmap('coolwarm'))
plt.quiver(x,y,Fx,Fy)
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
cbar = plt.colorbar(im, cax = cax,format='%.1f')


plt.tight_layout()
plt.savefig( 'divergence.png', format = 'png')
plt.show()

数值比较分析结果

于 2017-12-20T11:28:59.967 回答
2

基于@paul_chen 的回答,并为 Matplotlib 3.3.0 添加了一些内容(需要传递一个着色参数,我猜默认颜色图已经改变)

import numpy as np
import matplotlib.pyplot as plt

NY = 20; ymin = -2.; ymax = 2.
dy = (ymax -ymin )/(NY-1.)
NX = NY
xmin = -2.; xmax = 2.
dx = (xmax -xmin)/(NX-1.)

def divergence(f):
    num_dims = len(f)
    return np.ufunc.reduce(np.add, [np.gradient(f[i], axis=i) for i in range(num_dims)])

y = np.array([ ymin + float(i)*dy for i in range(NY)])
x = np.array([ xmin + float(i)*dx for i in range(NX)])

x, y = np.meshgrid( x, y, indexing = 'ij', sparse = False)

Fx  = np.cos(x + 2*y)
Fy  = np.sin(x - 2*y)


F = [Fx, Fy]
g = divergence(F)

plt.pcolormesh(x, y, g, shading='nearest', cmap=plt.cm.get_cmap('coolwarm'))
plt.colorbar()
plt.quiver(x,y,Fx,Fy)
plt.savefig( 'Div.png', format = 'png')

在此处输入图像描述

于 2020-09-10T08:13:17.650 回答
1

散度作为内置函数包含在 matlab 中,但不包含在 numpy 中。这可能是值得为 pylab 做出贡献的事情,努力创建一个可行的开源替代 matlab。

http://wiki.scipy.org/PyLab

编辑:现在称为http://www.scipy.org/stackspec.html

于 2014-01-14T21:15:32.190 回答
1

据我所知,答案是 numpy 中没有原生散度函数。因此,计算散度的最佳方法是对梯度向量的分量求和,即计算散度。

于 2014-01-14T20:35:15.927 回答
0

我不认为@Daniel 的答案是正确的,尤其是当输入是有序的时候[Fx, Fy, Fz, ...]

一个简单的测试用例

请参阅 MATLAB 代码:

a = [1 2 3;1 2 3; 1 2 3];
b = [[7 8 9] ;[1 5 8] ;[2 4 7]];
divergence(a,b)

结果是:

ans =

   -5.0000   -2.0000         0
   -1.5000   -1.0000         0
    2.0000         0         0

和丹尼尔的解决方案:

def divergence(f):
    """
    Daniel's solution
    Computes the divergence of the vector field f, corresponding to dFx/dx + dFy/dy + ...
    :param f: List of ndarrays, where every item of the list is one dimension of the vector field
    :return: Single ndarray of the same shape as each of the items in f, which corresponds to a scalar field
    """
    num_dims = len(f)
    return np.ufunc.reduce(np.add, [np.gradient(f[i], axis=i) for i in range(num_dims)])


if __name__ == '__main__':
    a = np.array([[1, 2, 3]] * 3)
    b = np.array([[7, 8, 9], [1, 5, 8], [2, 4, 7]])
    div = divergence([a, b])
    print(div)
    pass

这使:

[[1.  1.  1. ]
 [4.  3.5 3. ]
 [2.  2.5 3. ]]

解释

丹尼尔解决方案的错误是,在 Numpy 中,x 轴是最后一个轴而不是第一个轴。使用 时np.gradient(x, axis=0),Numpy 实际上给出了y 方向的梯度(当 x 是二维数组时)。

我的解决方案

我的解决方案基于丹尼尔的回答。

def divergence(f):
    """
    Computes the divergence of the vector field f, corresponding to dFx/dx + dFy/dy + ...
    :param f: List of ndarrays, where every item of the list is one dimension of the vector field
    :return: Single ndarray of the same shape as each of the items in f, which corresponds to a scalar field
    """
    num_dims = len(f)
    return np.ufunc.reduce(np.add, [np.gradient(f[num_dims - i - 1], axis=i) for i in range(num_dims)])

divergence在我的测试用例中,它给出了与 MATLAB 相同的结果。

于 2019-05-05T05:49:20.870 回答
0

不知何故,以前计算散度的尝试是错误的!我来给你展示:

我们有以下向量场 F:

F(x) = cos(x+2y)
F(y) = sin(x-2y)

如果我们计算散度(使用 Mathematica):

Div[{Cos[x + 2*y], Sin[x - 2*y]}, {x, y}]

我们得到:

-2 Cos[x - 2 y] - Sin[x + 2 y]

最大值在 y [-1,2] 和 x [-2,2] 范围内:

N[Max[Table[-2 Cos[x - 2 y] - Sin[x + 2 y], {x, -2, 2 }, {y, -2, 2}]]] = 2.938

使用此处给出的散度方程:

def divergence(f):
        num_dims = len(f)
        return np.ufunc.reduce(np.add, [np.gradient(f[i], axis=i) for i in range(num_dims)])

我们得到的最大值约为0.625

正确的散度函数:用python计算散度

于 2021-06-14T12:12:15.933 回答