[Python] Speeding up 3D interpolation

Discussão em 'Python' iniciado por Stack, Maio 13, 2025.

  1. Stack

    Stack Membro Participativo

    I am using python to perform the homotopy formula to obtain a vector potential A of a magnetic field B at points x in 3D space:

    A(x) = integral_L=0,1 (B(Lx)cross(Lx)dL)

    where cross represents the cross product

    Here B(x) is only known on a discrete regular grid (constant resolution in each direction, but the resolution in x,y,z are not necessarily the same) and so interpolation is required to perform the line integral.

    I was able to vectorize the loop over every point in space x with the following code and using RegularGridInterpolator:

    #stuff related to 3D linear interpolation
    print("Setting up interpolation stuff")

    interpolator_x = RegularGridInterpolator((X-x0,Y-y0,Z-z0),Bx, method='linear')
    interpolator_y = RegularGridInterpolator((X-x0,Y-y0,Z-z0),By, method='linear')
    interpolator_z = RegularGridInterpolator((X-x0,Y-y0,Z-z0),Bz, method='linear')
    print("created interpolator")

    #find an A from B using homotopy
    nlamb = 101
    lamb=np.arange(nlamb)/(nlamb-1)
    dlamb = lamb[1]-lamb[0]
    print("looping over lambda")
    start = time.time()
    dxi = x3D-x0
    dyi = y3D-y0
    dzi = z3D-z0
    for il in np.arange(nlamb):
    print(il, '/', nlamb)
    X1 = lamb[il]*dxi
    Y1 = lamb[il]*dyi
    Z1 = lamb[il]*dzi
    Bx_values = interpolator_x((X1,Y1,Z1))
    By_values = interpolator_y((X1,Y1,Z1))
    Bz_values = interpolator_z((X1,Y1,Z1))
    Ax_hom = Ax_hom + (((By_values*Z1)-(Bz_values*Y1))*dlamb)
    Ay_hom = Ay_hom + (((Bz_values*X1)-(Bx_values*Z1))*dlamb)
    Az_hom = Az_hom + (((Bx_values*Y1)-(By_values*X1))*dlamb)
    print("time to do loop over lambda :"+str(time.time()-start))


    For my test data of 128x128*82 points this takes about 110s.

    I though I should be able to vectorize the integral also. ChatGPT gave me this

    #chaGPT attempt to vectorize over lambda - acually slower
    start = time.time()
    lamb = np.linspace(0, 1, nlamb)
    X1 = lamb[:, None, None, None] * (x3D - x0)
    Y1 = lamb[:, None, None, None] * (y3D - y0)
    Z1 = lamb[:, None, None, None] * (z3D - z0)

    # Reshape to (N, points) for interpolation
    points = np.stack([X1, Y1, Z1], axis=-1).reshape(-1, 3)

    # Interpolate all at once
    Bx_values = interpolator_x(points).reshape(nlamb, *x3D.shape)
    By_values = interpolator_y(points).reshape(nlamb, *x3D.shape)
    Bz_values = interpolator_z(points).reshape(nlamb, *x3D.shape)

    # Compute Ax, Ay, Az using broadcasting
    Ax_hom = np.sum(((By_values * Z1) - (Bz_values * Y1)) * dlamb, axis=0)
    Ay_hom = np.sum(((Bz_values * X1) - (Bx_values * Z1)) * dlamb, axis=0)
    Az_hom = np.sum(((Bx_values * Y1) - (By_values * X1)) * dlamb, axis=0)
    print("trying to vectorize integral over lambda:"+str(time.time()-start))


    However, for the test grid is is actually slowr (~140s), and for larger grids it stays slower than the loop over lambda version.

    This is because the interpolation is the slowest part of the calculation. So, I think my problem is "How can I speed up this 3D interpolation"?

    Thanks

    Continue reading...

Compartilhe esta Página