do a cfd simulation in 3d in python

To perform a 3D CFD simulation in Python, we can use PyTorch, which is a popular deep learning framework capable of running computations on GPUs. Following are the general steps to perform a CFD simulation in 3D -

  1. Define the geometry and physical parameters of the problem in 3D using a mesh. There are several meshing libraries available in Python like NumPy, SciPy, and PyMesh.
main.py
import numpy as np

# Define Mesh size
Nx = 64
Ny = 64
Nz = 64

# Define Mesh boundaries
x_min, x_max = -1, 1
y_min, y_max = -1, 1
z_min, z_max = -1, 1

# Create Meshgrid
x = np.linspace(x_min, x_max, Nx)
y = np.linspace(y_min, y_max, Ny)
z = np.linspace(z_min, z_max, Nz)
X, Y, Z = np.meshgrid(x, y, z, indexing='ij')

320 chars
19 lines
  1. Define the initial and boundary conditions based on the problem at hand.
main.py
# Set boundary Conditions
u_x = np.zeros((Nx, Ny, Nz))
u_y = np.zeros((Nx, Ny, Nz))
u_z = np.zeros((Nx, Ny, Nz))

u_x[:, :, 0] = 1         # Inlet condition 
u_x[:, :, -1] = 1        # Outlet condition
u_x[0, :, :] = 0         # Wall condition
u_x[-1, :, :] = 0        # Wall condition

rho = 1                   # Density
mu = 0.01                 # Viscosity
dt = 1e-3                 # Time Step

400 chars
15 lines
  1. Implement the numerical schemes to solve the Navier-Stokes equations using finite volume or finite difference methods. For instance, we can solve the equations using the Chorin's projection method.
main.py
def solve_Navier_Stokes_projection(u_x, u_y, u_z, rho, mu, dt, dx, dy, dz):
    # Solve for velocity(vector)
    u = np.vstack((u_x.flatten(), u_y.flatten(), u_z.flatten())).T   
    # Solve for pressure(scalar)    
    p = np.zeros((u.shape[0], 1))

    # Define Divergence operator
    D = scipy.sparse.csr_matrix(3*[scipy.sparse.diags([-1, 1], [0, 1], shape=(Nx, Ny*Nz))])

    # Velocity Gradient Matrix
    grad = np.vstack((np.kron(np.ones((1, Nx)), np.kron(np.eye(Ny), np.ones((1, Nz))) / dy),
                      np.kron(np.ones((1, Nx)), np.kron(np.ones((1, Ny)), np.eye(Nz)) / dz)))    
    grad = scipy.sparse.csr_matrix(grad)
    
    # Define Laplacian Operator
    lapl = scipy.sparse.diags([1, 1, 1, -6, 1, 1, 1], [-Nx*Ny, -Nx, -1, 0, 1, Nx, Nx*Ny],  
                               shape=(Nx*Ny*Nz, Nx*Ny*Nz)) * mu / dx**2        

    # Calculate modified velocity
    rhs = u / dt - grad.dot(p) + ( D.dot(u.flatten())) * mu / rho
    u_star = lgmres(lapl, rhs)[0].reshape((Nx,Ny,Nz,3)).T

    # Pressure Correction (Poisson Equation)
    div = np.vstack((np.kron(np.ones((1, Nx)), np.kron(np.eye(Ny), np.ones((1, Nz))) * dy),
                      np.kron(np.ones((1, Nx)), np.kron(np.ones((1, Ny)), np.eye(Nz))) * dz ))                  
    div = scipy.sparse.csr_matrix(div)
    A = div.dot(scipy.sparse.diags([-1, -1, -1], [0, Nx*Ny, Nx*Ny*Nz],
                                           shape=(Nx*Ny*Nz, Nx*Ny*Nz)).toarray())                      
    b = -div.dot(np.vstack((u_star[0,:,:,:]/dx[0], 
                            u_star[1,:,:,:]/dx[1],
                            u_star[2,:,:,:]/dx[2]))).flatten(order='F') / dt    

    # Pressure Correction
    p_prime = lgmres(A, b)[0].reshape((Nx,Ny,Nz)).T  

    # Correct Velocity Field
    u_x[:, :, :] = u_star[0,:,:,:] - dt / dx[0] * (p_prime[1:, :, :] - p_prime[:-1, :, :])
    u_y[:, :, :] = u_star[1,:,:,:] - dt / dy * (p_prime[:, 1:, :] - p_prime[:, :-1, :])
    u_z[:, :, :] = u_star[2,:,:,:] - dt / dz * (p_prime[:, :, 1:] - p_prime[:, :, :-1])
    
    return u_x, u_y, u_z
2065 chars
42 lines
  1. Iterate over time steps to calculate the final solution.
main.py
# Final simulation
t_final = 5
steps_per_frame = 50
frames = int(t_final // dt // steps_per_frame)
fig, axs = visualize_flow(u_x, u_y, u_z, fig_width=15, fig_height=10)
for i in range(frames):
    for ii in range(steps_per_frame):
        u_x, u_y, u_z = solve_Navier_Stokes_projection(u_x, u_y, u_z, rho, mu, dt, np.diff(x), np.diff(y), np.diff(z))
    axs = visualize_flow(u_x, u_y, u_z, fig_width=15, fig_height=10, axs=axs)
print('Simulation Done!')
454 chars
11 lines
  1. Visualize the results using various visualization libraries like Matplotlib, Mayavi, and PyVista.
main.py
import pyvista as pv

def visualize_flow(u_x, u_y, u_z, fig_width=10, fig_height=7, axs=None):
    # Create a new plot
    if axs is None:
        axs = pv.Plotter(window_size=[int(fig_width*80), int(fig_height*80)])
        
    # Create a vector field data
    vectors = np.stack((u_x, u_y, u_z), axis=-1)

    # create grid mesh from data
    mesh = pv.StructuredGrid(X, Y, Z)
    mesh.point_arrays['vector'] = vectors.reshape((-1, 3), order='F')

    # add vector field actor
    actor = axs.add_mesh(mesh, scalars='vector', 
                          vector_scalars='Magnitude', 
                          n_colors=256,
                          cmap='viridis',
                          lighting=True,
                          scalar_bar_args={'title': 'Velocity Magnitude\n[m/s]',
                                           'n_labels': 5,
                                           'height': 0.50, 
                                           'position_x': 0.95, 
                                           'position_y': 0.45},
                          scalar_bar_height_ratio=0.75,
                          name='VectorField'
                         )

    # add streamlines actor
    stream_actor = actor.streamlines(color='white',
                                     integration_direction='backwards',
                                     source_radius=0.02,
                                     tube_radius=0.005,
                                     max_time=2.0, 
                                     initial_step_length=0.1,
                                     start_position=(-0.5, 0.0, 0.0),
                                     name="Streamlines")

    # set camera position
    axs.camera_position = [(45, 45, 57), (-0.5, 0.0, 0.0), (0.0, 0.0, 1.0)]

    # Render the image
    axs.show(True)
    
    return axs
1836 chars
47 lines

The above code is a general template that can be used to perform 3D CFD simulations. This can be further modified or optimized based on specific problem requirements.

gistlibby LogSnag