Showing posts with label navier stokes. Show all posts
Showing posts with label navier stokes. Show all posts

Tuesday, March 11, 2025

2D Wave Equation Code (Finite Difference Method)

     After 🎉 successfully teaching 👨‍🏫 the neural network about the 〰️ wave equation, yours truly thought it is the time ⏱️ to write a simple code 🖥️ for discretized domain as well. A code yours truly created in abundant spare time is mentioned in this blog 📖.


     A complex (sinusoidal) 🌊 boundary condition is implemented. Dirichlet and Neumann boundary conditions are also implemented. The code is vectorized ↗ so there is only one loop 😁.  CFL condition is implemented in the time-step calculation so time-step ⏳ is adjusted based on the mesh size automatically 😇.

     For simple geometries, traditional numerical methods are is still better than PINNs. 🧠

Code

#Copyright <2025> <FAHAD BUTT>
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
#The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
#THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#%% import necessary libraries
import numpy as np
import matplotlib.pyplot as plt

#%% define parameters
L = 1 # domain length
D = 1 # domain width
h = D / 100 # grid spacing
Nx = round(L / h) + 1 # grid points in x-axis
Ny = round(D / h) + 1 # grid points in y-axis
nu = 0.175 # Poisson's ratio
E = 3e10 # Young's modulus [Pa]
rho = 2350 # density [Kg/m3]
cp = np.sqrt(E * (1 - nu) / (rho * (1 + nu) * (1 - 2 * nu))) # wave speed
travel = 100 # times the disturbance travels entire length of computational domain
TT = travel * L / cp # total time
CFL = 0.1 # CFL number
dt = CFL * h / cp # time step
ns = int(TT / dt) # number of time steps

#%% initialize fields
u = np.zeros((Nx, Ny)) # u displacement (next time step) u_n+1
u_vel = np.zeros((Nx, Ny)) # initial velocity
un = np.copy(u) # u displacement (current time step) u
unn = un - dt * u_vel # u displacement (previous time step) u_n-1

#%% pre calculate for speed
P1 = dt**2 * cp**2 / h**2
f = 2 / TT # frequency
omega = 2 * np.pi * f * dt

#%% plotting
x = np.linspace(0, L, Nx) # initialize x
y = np.linspace(0, D, Ny) # initialize y
X, Y = np.meshgrid(x, y) # create combinations of sample points along the domain

#%% solve 2D-transient wave equation
for nt in range(ns):
    unn[:, :] = un[:, :] # shift u_n to u_n-1
    un[:, :] = u[:, :] # shift u_n+1 to u_n
    u[1:-1, 1:-1] = 2 * un[1:-1, 1:-1] - unn[1:-1, 1:-1] + (dt**2 * cp**2 / h**2) * (un[2:, 1:-1] + un[:-2, 1:-1] + un[1:-1, 2:] + un[1:-1, :-2] - 4 * un[1:-1, 1:-1])
    u[0, :] = 0 # u = 0 at x = 0
    u[-1, :] = 0 # u = 0 at x = L
    u[:, 0] = 0 # u = 0 at y = 0
    u[:, -1] = 0 # u = 0 at y = D
    u[int(0.5 * Nx / L) - 1:int(0.5 * Nx / L) + 2, int(0.5 * Ny / D) - 1:int(0.5 * Ny / D) + 2] = np.sin(omega * nt) # u = sin(2*pi*f*t) at x = 0.5 and y = 0.5
    if nt % 1000 == 0:
        plt.figure(dpi = 200) # make a nice crisp image :)
        plt.contourf(X, Y, u.T, cmap = 'prism', levels = 256, vmin = -0.25, vmax = 0.25) # contour plot
        plt.gca().set_aspect('equal', adjustable = 'box')
        plt.xticks([])
        plt.yticks([])
        plt.show()

     The code creates a pulse, as shown in Fig. 1. Within Fig. 1, one of several snapshots is shown. The material properties used are that of concrete.

Fig. 1, A nice wave

     Thank you for reading! If you want to hire me as a post-doc researcher in the fields of thermo-fluids and / or fracture mechanics, do reach out!

Saturday, February 1, 2025

Multi-Physics Simulations using in-House Code

     One fine morning, in abundant spare time, yours truly decided to adapt the CFD and LE code that has been developed over the years in to sort of a code capable of simulating one-way FSI. In this post details about Fluid Structure Interaction (FSI) code are made available.

     The code is very simple and basic form is less than 150 lines. A total of 50 lines for the CFD portion and around about 75 lines for the LE (Linear Elasticity) portion. The both CFD and LE codes have be thoroughly validated undependably. For CFD validation, please refer to here and here. Meanwhile the validation for LE portion is available here.

     As of now, the work process is CFD→LE. Which means the flow-field has to be calculated first. More details about the CFD portion are available here, here, and here. The pressure and shear stress on the walls of interest are extracted. This pressure and shear stress is then applied as stress loads on the a boundaries of the object in the LE code.

     The flow-field is simulated around a thin slander beam which is fixed with the floor. Within Fig. 1, From left to right u and v components of velocity are shown. Meanwhile, pressure and streamlines are shown on the bottom row. Within Fig. 2, the deflected thin beam is shown. The deflection is consistent with the intuition i.e. towards the flow and slightly below.


Fig. 1, The CFD results

Fig. 2, The results of LE simulation!

     Thank you for reading. If you want to hire me as your shining new post-doc, do reach out!

A GPU Accelerated Immersed Boundary Method for Linear Elasticity

     Immersed Boundary Methods (IBMs) have been extensively used for fluid-structure interaction (FSI) and fluid dynamics simulations. IBMs ...