是否有可用于计算矢量场分歧的函数? (在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)
所以grad(F)
是2D ndarray
s
我知道我可以像this那样计算分歧但不想重新发明轮子。 (我也希望有更优化的东西)有人有建议吗?
答案 0 :(得分:13)
只是提醒所有人阅读:
上述函数不计算向量场的偏差。他们总结了标量场的衍生物A:
结果= dA / dx + dA / dy
与矢量场(具有三维示例)形成对比:
结果=总和dAi / dxi = dAx / dx + dAy / dy + dAz / dz
为所有人投票!这在数学上是完全错误的。
干杯!
答案 1 :(得分:10)
import numpy as np
def divergence(field):
"return the divergence of a n-D field"
return np.sum(np.gradient(field),axis=0)
答案 2 :(得分:10)
@ user2818943的答案很好,但可以稍微优化一下:
def divergence(F):
""" compute the divergence of n-D scalar field `F` """
return reduce(np.add,np.gradient(F))
Timeit:
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*divergence(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)
答案 3 :(得分:6)
基于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's documentation使用这个确切的公式(向下滚动到矢量场的发散)
答案 4 :(得分:2)
http://www.scipy.org/Topical_Software#head-85e01502b533f2477ab8c643b38ee92706a377bb
即使它没有为你手工打包的分歧,分歧也很简单,他们给你的衍生工具scipy(上面链接的那些)给你大约90%的代码预先打包好了,有效的方式。
答案 5 :(得分:2)
丹尼尔修改的是正确的答案,让我更详细地解释自我定义的函数分歧:
函数np.gradient()定义为:np.gradient(f)= df / dx,df / dy,df / dz + ...
但我们需要定义func散度为:divergence(f)= dfx / dx + dfy / dy + dfz / dz + ... = np.gradient(fx)+ np.gradient(fy)+ np.gradient( fz)+ ...
让我们进行测试,与example of divergence in 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()
答案 6 :(得分:1)
据我所知,答案是numpy中没有本地发散功能。因此,用于计算发散度的最佳方法是对梯度向量的分量求和,即计算发散度。
答案 7 :(得分:1)
作为内置函数的分歧包含在matlab中,但不是numpy。这可能是值得为pylab做出贡献的事情,这是为matlab创建一个可行的开源替代品的努力。
答案 8 :(得分:1)
基于@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')
答案 9 :(得分:1)
不知何故,之前计算散度的尝试是错误的!让我告诉你:
我们有以下向量场 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
答案 10 :(得分: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. ]]
Daniel解决方案的错误是,在Numpy中, x轴是最后一个轴,而不是第一个轴。使用np.gradient(x, axis=0)
时,Numpy实际上给出了 y方向的梯度(当x是2d数组时)。
根据丹尼尔的回答,我有解决方案。
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)])
在我的测试案例中,其结果与MATLAB divergence
相同。