def CalculateLookupTable_3D(fluid, spread=True, Range=10000):
    U = zeros((fluid.N[0], fluid.N[1], fluid.N[2], 3, 3), float64)
    X = zeros((1, 3), float64)

    F = X.copy()

    # Calculate the lookup table for a unit force in the x direction
    F[0] = [1, 0, 0]

    FiberToGrid(fluid.N, fluid.h, 1, 1., X, F, fluid.f, fluid.DeltaType)
    fluid.FluidSolve(fluid.f)

    if (spread):
        IB_c.WholeGridSpread(fluid.Output_u, fluid.N, fluid.h, U[..., 0, :],
                             Range, fluid.DeltaType)
    else:
        U[..., 0, :] = fluid.Output_u.copy()

    # If the domain is perfectly cubic make use of symmetries
    if fluid.N[0] == fluid.N[1] == fluid.N[2]:
        U[..., 1, :] = U[..., 0, :].swapaxes(0, 1)
        U[..., 1, 0], U[..., 1, 1] = U[..., 1, 1].copy(), U[..., 1, 0].copy()
        U[..., 2, :] = U[..., 0, :].swapaxes(0, 2)
        U[..., 2, 0], U[..., 2, 2] = U[..., 2, 2].copy(), U[..., 2, 0].copy()
    # otherwise calculate y and z components from scratch
    else:
        # Calculate the lookup table for a unit force in the y direction
        F[0] = [0, 1, 0]

        FiberToGrid(fluid.N, fluid.h, 1, 1., X, F, fluid.f, fluid.DeltaType)
        fluid.FluidSolve(fluid.f)

        if (spread):
            IB_c.WholeGridSpread(fluid.Output_u, fluid.N, fluid.h,
                                 U[..., 1, :], Range, fluid.DeltaType)
        else:
            U[..., 1, :] = fluid.Output_u.copy()

        # Calculate the lookup table for a unit force in the z direction
        F[0] = [0, 0, 1]

        FiberToGrid(fluid.N, fluid.h, 1, 1., X, F, fluid.f, fluid.DeltaType)
        fluid.FluidSolve(fluid.f)

        if (spread):
            IB_c.WholeGridSpread(fluid.Output_u, fluid.N, fluid.h,
                                 U[..., 2, :], Range, fluid.DeltaType)
        else:
            U[..., 2:] = fluid.Output_u.copy()

    return U
def InitVelField(_N, _M, _h, h, dt, rho=1., mu=1., DeltaType=0):
    WideLambda = zeros((_N, _M), float64)
    ShortLambda = zeros((_N, _M), float64)
    IB_c.InitWideLaplacian(_N, _M, _h, WideLambda)
    IB_c.InitShortLaplacian(_N, _M, _h, ShortLambda)
    DxSymbol = InitDxSymbol(_N, _M, _h)
    DySymbol = InitDySymbol(_N, _M, _h)

    r = int(ceil(3. * h / _h))

    fx = zeros((_N, _M), float64)
    for j in range(-r, r + 1):
        deltx = Delta(h, j * _h, DeltaType)
        for k in range(-r, r + 1):
            delt = deltx * Delta(h, k * _h, DeltaType) * 1.
            fx[j % _N][k % _M] = fx[j % _N][k % _M] + delt
#       print j%_N, k%_M, fx[j%_N][k%_M]

    fx, fy = fft2(dt * fx), zeros((_N, _M), float64)

    P = Solve_P_Hat(dt, WideLambda, DxSymbol, DySymbol, fx, fy)
    P[0, 0] = 0.

    u, v = Solve_uv_Hat(dt, ShortLambda, DxSymbol, DySymbol, P, fx, fy, rho,
                        mu)
    u = 1. * ifft2(u).real
    v = 1. * ifft2(v).real
    #    P = ifft2(P).real

    Fx1 = array(zeros((_N, _M), float64))
    Fy1 = array(zeros((_N, _M), float64))

    IB_c.WholeGridSpread(u, float(h), float(_h), int(r), Fx1, DeltaType)
    IB_c.WholeGridSpread(v, float(h), float(_h), int(r), Fy1, DeltaType)

    fy = zeros((_N, _M), float64)
    for j in range(-r, r + 1):
        deltx = Delta(h, j * _h, DeltaType)
        for k in range(-r, r + 1):
            delt = deltx * Delta(h, k * _h, DeltaType) * 1.
            fy[j % _N][k % _M] = fy[j % _N][k % _M] + delt

#       print j%_N, k%_M, fx[j%_N][k%_M]

    fx, fy = zeros((_N, _M), float64), fft2(dt * fy)

    P = Solve_P_Hat(dt, WideLambda, DxSymbol, DySymbol, fx, fy)
    P[0, 0] = 0.

    u, v = Solve_uv_Hat(dt, ShortLambda, DxSymbol, DySymbol, P, fx, fy, rho,
                        mu)
    u = 1. * ifft2(u).real
    v = 1. * ifft2(v).real

    Fx2 = array(zeros((_N, _M), float64))
    Fy2 = array(zeros((_N, _M), float64))

    IB_c.WholeGridSpread(u, float(h), float(_h), int(r), Fx2, DeltaType)
    IB_c.WholeGridSpread(v, float(h), float(_h), int(r), Fy2, DeltaType)

    return Fx1, Fy1, Fx2, Fy2