有没有办法用更好的“到位”方法来做到这一点?

时间:2015-04-09 15:24:41

标签: python-2.7 numpy physics

这是Biot-Savart law的简单近似值。

我在函数calc()

中实现了积分(和)

如果空间点的数量很大,例如10 ^ 7或10 ^ 8 -ish,是否可以calc写入以更有效地使用NumPy数组?谢谢你的建议!

def calc(points, x_seg, idl_seg):

    r = points[:, None, :] - x_seg[None, :, :]             # START CALCULATION

    bottom = ((r**2).sum(axis=-1)**1.5)[...,None]     # 1/|r|**3 add axis for vector

    top = np.cross(idl_seg[None,:,:], r)                  # np.cross defaults to last axis

    db = (mu0 / four_pi) * top / bottom

    b = db.sum(axis=-2)               # sum over the segments of the current loop

    return b

编辑:例如,我可以这样做。现在只有两个大小为r的数组(holdnx * ny * nz * nseg * 3)。也许我应该一次传递更小的points块,所以它一次都可以适应缓存?

def calc_alt(points, x_seg, idl_seg):

    r = points[:, None, :] - x_seg[None, :, :]             

    hold = np.ones_like(r)*((r**2).sum(axis=-1)**-1.5)[...,None]  # note **-1.5 neg

    b = (hold * np.cross(idl_seg[None,:,:], r)).sum(axis=-2)

    return b * (mu0 / four_pi)

发布其余代码以显示calc的使用方式。

import numpy as np
import matplotlib.pyplot as plt

pi, four_pi  = np.pi,  4. * np.pi
mu0          = four_pi * 1E-07 # Tesla m/A exact, defined
r0           = 0.05   # meters
I0           = 100.0  # amps
nx, ny, nz = 48, 49, 50

x,y,z = np.linspace(0,2*r0,nx), np.linspace(0,2*r0,ny), np.linspace(0,2*r0,nz) 
xg = np.zeros((nx, ny, nz, 3))  # 3D grid of position vectors
xg[...,0] = x[:, None, None]   # fill up the positions
xg[...,1] = y[None, :, None]
xg[...,2] = z[None, None, :]
xgv = xg.reshape(nx*ny*nz, 3)  # flattened view of spatial points

nseg = 32   # approximate the current loop as a set of discrete points I*dl 
theta = np.linspace(0, 2.*pi, nseg+1)[:-1]  # get rid of the repeat

xdl = np.zeros((nseg, 3))   # these are the position vectors
idl = np.zeros((nseg, 3))   # these are the current vectors

xdl[:,0],  xdl[:,1] = r0 * np.cos(theta),   r0 * np.sin(theta)
idl[:,0],  idl[:,1] = I0 * -np.sin(theta),  I0 * np.cos(theta)

b = calc(xgv, xdl, idl)           # HERE IS THE CALCULATION

bv = b.reshape(nx, ny, nz, 3)     # make a "3D view" again to use for plotting

bx, by, bz = bv[...,0], bv[...,1], bv[...,2]  # make component views

bperp = np.sqrt(bx**2 + by**2)  # new array for perp field

zround = np.round(z, 4)
iz = 5     # choose a transverse plane for a plot
fields    = [ bz,   bperp,   bx,   by]
names     = ['Bz', 'Bperp', 'Bx', 'By']
titles = ["approx " + name + " at z = " + str(zround[iz])
          for name in names]

plt.figure()
for i, field in enumerate(fields):
    print i
    plt.subplot(2, 2, i+1)
    plt.imshow(field[..., iz], origin='lower')  # fields at iz don't use Jet !!!
    plt.title(titles[i])
    plt.colorbar()
plt.show()

最后的绘图只是为了看它似乎有效。实际上,永远不要使用默认的colormap。糟糕,可怕,顽皮的喷射!在这种情况下,具有对称vmin = -vmax的发散cmap可能是好的。 (参见Jake VanderPlas' post和matplotlib documentation,还有一些可爱的演示here

2 个答案:

答案 0 :(得分:0)

你可以压缩这些行:

b = db.sum(axis=-2)               # sum over the segments of the current loop

bv = b.reshape(nx, ny, nz, 3)     # make a "3D view" again to use for plotting

bx, by, bz = bv[...,0], bv[...,1], bv[...,2] 

bx, by, bz = np.split(db.sum(axis=-2).reshape(nx, ny, nz, 3), 3, -1)

我怀疑它是否对速度有任何影响。是否使这个更清楚是有争议的。

xdl = np.zeros((nseg, 3))   # these are the position vectors
idl = np.zeros((nseg, 3))   # these are the current vectors

xdl[:,0],  xdl[:,1] = r0 * np.cos(theta),   r0 * np.sin(theta)
idl[:,0],  idl[:,1] = I0 * -np.sin(theta),  I0 * np.cos(theta)

可以改写为(未经测试)

xdl = r0 * np.array([np.cos(theta), np.sin(theta)]
idl = I0 * np.array([-np.sin(theta), np.cos(theta)]

虽然这些会产生这些(3,nseg)。请注意,split的默认轴为0。在第一轴上组合和分割通常更自然。此外[None,...]广播也是自动的。

ng构造也可以简化。

这些都是化妆品的变化,不会在性能上产生很大的差异。

答案 1 :(得分:0)

我刚刚遇到np.numexpr,其中包括我在编辑中建议的内容 - 将数组分解为“chunks”,以便它们可以适应缓存,包括所有临时数组需要评估表达式。有很好的解释herehere