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