用python计算向量场的散度

用python计算向量场的散度,python,numpy,scipy,Python,Numpy,Scipy,有一个函数可以用来计算矢量场的散度吗?(in)我希望它存在于numpy/scipy中,但我无法使用谷歌找到它 我需要计算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) 因此,grad(F)是2Dndarrays的列表 我知道我可以像这样计算散度,但我不想重新发明轮子。(我也希望有

有一个函数可以用来计算矢量场的散度吗?(in)我希望它存在于numpy/scipy中,但我无法使用谷歌找到它

我需要计算
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)
因此,
grad(F)
是2D
ndarray
s的列表

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


即使它没有为您手工打包的散度,散度也是非常简单的,他们在scipy中提供的衍生工具(上面链接的工具)以一种友好、高效的方式为您提供了大约90%的预打包代码。

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

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

import numpy as np

def divergence(field):
    "return the divergence of a n-D field"
    return np.sum(np.gradient(field),axis=0)


编辑:现在称为

@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倍:
sum
np.gradient
返回的渐变字段列表隐式构造3d数组。使用
reduce


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

  • 关于
    A*grad(F)
    A
    是二维数组,而
    grad(F)
    是二维数组的列表。所以我认为这意味着将每个梯度场乘以
    A
  • 关于将散度应用于(按
    A
    缩放)梯度场,目前尚不清楚。根据定义,
    div(F)=d(F)/dx+d(F)/dy+…
    。我想这只是一个公式上的错误
  • 对于
    1
    ,将求和的元素
    Bi
    乘以相同的因子
    a
    可以分解为:

    Sum(A*Bi) = A*Sum(Bi)
    
    因此,只需:
    A*散度(F)

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

    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)
    

    给大家一个提示:

    上述函数不计算向量场的散度。它们求标量场a的导数之和:

    result=dA/dx+dA/dy

    与矢量场不同(以三维为例):

    result=sum dAi/dxi=dAx/dx+dAy/dy+dAz/dz

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


    干杯

    基于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)])
    

    使用这个精确的公式(向下滚动到向量场的散度)

    Daniel修改的是正确的答案,让我更详细地解释一下自定义的func散度:

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

    但我们需要将函数散度定义为:散度(f)=dfx/dx+dfy/dy+dfz/dz+…=<代码>np.梯度(fx)+
    np.梯度(fy)
    +
    np.梯度(fz)
    +

    让我们测试一下,比较一下

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

    感谢@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()
    

    我认为@Daniel的答案不正确,尤其是当输入顺序正确时

    一个简单的测试用例 请参见MATLAB代码:

    a=[123;123;1233];
    b=[7 8 9];[1 5 8];[2 4 7];
    散度(a,b)
    
    结果如下:

    ans =
    
       -5.0000   -2.0000         0
       -1.5000   -1.0000         0
        2.0000         0         0
    
    丹尼尔的解决方案是:

    def散度(f):
    """
    丹尼尔溶液
    计算矢量场f的散度,对应于dFx/dx+dFy/dy+。。。
    :param f:nArray列表,其中列表中的每一项都是向量场的一维
    :return:与f中的每个项形状相同的单个数据数组,对应于标量字段
    """
    num_dims=len(f)
    返回np.ufunc.reduce(np.add,[np.gradient(f[i],axis=i)表示范围内的i(num_dims)])
    如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
    a=np.array([[1,2,3]]*3)
    b=np.数组([[7,8,9],[1,5,8],[2,4,7]]
    div=散度([a,b])
    印刷(部门)
    通过
    
    其中:

    [[1.  1.  1. ]
     [4.  3.5 3. ]
     [2.  2.5 3. ]]
    
    解释 Daniel解决方案的错误在于,在Numpy中,x轴是最后一个轴,而不是第一个轴。当使用
    np.gradient(x,axis=0)
    时,Numpy实际上给出了y方向的梯度(当x是二维数组时)

    我的解决方案 根据丹尼尔的回答,我有一个解决方案。


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

    基于@paul_chen答案,并添加了Matplotlib 3.3.0的一些内容(需要通过着色参数,我猜默认的颜色贴图已经更改)


    不知何故,以前计算散度的尝试是错误的!让我告诉你:

    我们有以下向量场F:

    F(x) = cos(x+2y)
    F(y) = sin(x-2y)
    
    如果我们计算散度(使用Mathematica):

    我们得到:

    -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


    正确的发散函数:您需要什么样的阶精度?你的阵列是等间距的吗?@mgilson是的,阵列是等间距的。我需要双精度。@ZagorulkinDmitry,Jensen–Shannon散度是完全不同的。正确的方法是:向量场F=d的散度不是吗(
    Div[{Cos[x + 2*y], Sin[x - 2*y]}, {x, y}]
    
    -2 Cos[x - 2 y] - Sin[x + 2 y]
    
    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)])