├── 1D Burgers Equation.py ├── 1D Diffusion Equation.py ├── 1D Linear Convection Equation.py ├── 1D Non Linear Convection Equationn.py ├── 1D_Linear Convection_Fine_Mesh.py ├── 2D Burgers Equation.py ├── 2D Diffusion Equation.py ├── 2D Laplace Equation.py ├── 2D Linear Convection Equation .py ├── 2D Non Linear Convection Equation .py ├── 2D Poisson Equation.py ├── Cavity Flow.py ├── Channel Flow.py ├── FVM_1D_Convection_Diffusion.py ├── FVM_1D_Convection_Diffusion_Upwind.py ├── FVM_1D_Diffusion_Dirichlet_BC.py ├── FVM_1D_Diffusion_Equation_Stadard_Wall_Function.py ├── FVM_1D_Diffusion_Neumann_BC.py ├── FVM_2D_Diffusion.py ├── LBM_solver_flow_past_2Dcylinder.py └── README.md /1D Burgers Equation.py: -------------------------------------------------------------------------------- 1 | import numpy #give mathamatical or matrix expressions 2 | import sympy #SymPy is the symbolic math library for Python. 3 | 4 | from sympy import init_printing 5 | init_printing(use_latex = True) #Output Rendering using LATEX. 6 | 7 | lineSingle = '------------------------------------------------' 8 | 9 | print("Solving 1D Burgers Equation using Finite Difference Method") 10 | print("Convection Term: Backward Difference Scheme") 11 | print("Diffusion Term: Central Difference Scheme\n") 12 | 13 | #setting up symbolic variables for the three variables in our initial condition then type full eqn of phi 14 | 15 | #innitial condition 16 | 17 | x, nu, t = sympy.symbols('x nu t') 18 | phi = (sympy.exp(-(x - 4*t)**2/(4*nu*(t + 1))) + sympy.exp(-(x - 4*t - 2*sympy.pi)**2/(4*nu*(t+1)))) #phi expression 19 | 20 | print(lineSingle) 21 | print("printing phi expression") 22 | print(lineSingle) 23 | print(phi) 24 | 25 | 26 | phiprime = phi.diff(x) #differentiation wrt x 27 | phiprime 28 | 29 | from sympy.utilities.lambdify import lambdify #translate sympy symbolic initial condition equation into a usable Python expression. 30 | 31 | u = -2*nu*(phiprime/phi) + 4 #Initial condition expression 32 | 33 | print(lineSingle) 34 | print("Initial Condition expression") 35 | print(lineSingle) 36 | print(u) 37 | 38 | ufunc = lambdify((t, x, nu), u) #putting value of t, x and nu in u and getting the output 39 | 40 | 41 | from matplotlib import pyplot 42 | 43 | #seting up the grid 44 | 45 | nx = 101 #grid points 46 | nt = 20 #number of timesteps 47 | dx = 2 * numpy.pi / (nx - 1) #grid spacing 48 | nu = .07 #viscosity 49 | dt = dx * nu #timestep size 50 | 51 | x = numpy.linspace(0, 2 * numpy.pi, nx) 52 | un = numpy.empty(nx) 53 | t = 0 #initial time t = 0 54 | 55 | u = numpy.asarray([ufunc(t, x0, nu) for x0 in x]) #initial condition plot using our lambdify-ed function 56 | 57 | print(lineSingle) 58 | print("Computing Innitial Solution") 59 | print(lineSingle) 60 | print(u) 61 | 62 | print(lineSingle) 63 | print("Plotting Innitial Solution") 64 | print(lineSingle) 65 | 66 | pyplot.figure(figsize=(11, 7), dpi=100) 67 | pyplot.plot(x, u, marker='o', lw=2, label='Initial Solution') 68 | pyplot.title('1D Burgers Convection') 69 | pyplot.xlabel('Grid Space') 70 | pyplot.ylabel('Velocity') 71 | pyplot.xlim([0, 2 * numpy.pi]) 72 | pyplot.ylim([0, 10]); 73 | 74 | pyplot.legend(); 75 | pyplot.show() 76 | 77 | print(lineSingle) 78 | print("Computing Analytical Solution") 79 | print(lineSingle) 80 | 81 | u_analytical = numpy.asarray([ufunc(nt * dt, xi, nu) for xi in x]) #computing analytical solution 82 | 83 | print(lineSingle) 84 | print("Printing Analytical Solution") 85 | print(lineSingle) 86 | 87 | print(u_analytical) 88 | 89 | print(lineSingle) 90 | print("Calculating Numerical Solution......") 91 | print(lineSingle) 92 | 93 | for n in range(nt): #time marching 94 | un = u.copy() 95 | for i in range(1, nx - 1): #space marching 96 | 97 | #Backward Difference for Convection Term 98 | #Central Difference for Diffusion Term 99 | 100 | u[i] = un[i] - un[i]*dt/dx*(un[i] - un[i-1]) + nu*dt/dx**2*(un[i+1]-2*un[i]+un[i-1]) 101 | 102 | #periodic boudnary condition 103 | 104 | u[0] = un[0] - un[0]*dt/dx*(un[0] - un[-2]) + nu*dt/dx**2*(un[1]-2*un[0]+un[-2]) 105 | u[-1] = u[0] 106 | 107 | print(lineSingle) 108 | print("Printing Numerical Solution......") 109 | print(lineSingle) 110 | 111 | print(u) 112 | 113 | 114 | print(lineSingle) 115 | print("Plotting Innitial, Analytical & Numerical Solution") 116 | print(lineSingle) 117 | 118 | pyplot.figure(figsize=(11,7), dpi=100) 119 | 120 | pyplot.plot(x,u, marker = 'o', lw = 2, label='Computational Solution') 121 | pyplot.plot(x, u_analytical, label = 'Analytical Solution') 122 | pyplot.xlim([0, 2*numpy.pi]) 123 | pyplot.ylim([0, 10]) 124 | 125 | pyplot.title('1D Burgers Convecction') 126 | pyplot.xlabel('Grid Space') 127 | pyplot.ylabel('Velocity') 128 | 129 | pyplot.legend(); 130 | pyplot.show() 131 | -------------------------------------------------------------------------------- /1D Diffusion Equation.py: -------------------------------------------------------------------------------- 1 | import numpy #here we load numpy library that provides a bunch of useful matrix operations akin to MATLAB 2 | from matplotlib import pyplot #2D plotting library that we will use to plot our results 3 | 4 | lineSingle = '------------------------------------------------' 5 | 6 | print("Solving 1D Diffusion Equation using Finite Difference Method\n") 7 | 8 | #setting the grid 9 | 10 | nx = 41 #grid points 11 | dx = 2 / (nx - 1) #grid spacing 12 | nt = 20 #number of timesteps 13 | nu = 0.3 #viscosity 14 | cfl = 0.4 15 | dt = cfl*dx**2/nu #based on von neumaan stability analysis 16 | 17 | #innitial condition 18 | 19 | print(lineSingle) 20 | print("Computing Innitial Solution...") 21 | 22 | 23 | u = numpy.ones(nx) 24 | u[int(0.5/dx):int(1/dx+1)] = 2 #Square Wave Profile 25 | 26 | print("Printing Innitial Solution...") 27 | print(lineSingle) 28 | 29 | print(u) 30 | 31 | pyplot.plot(numpy.linspace(0,2,nx), u, label='Initial Solution') 32 | 33 | #discritization 34 | 35 | print(lineSingle) 36 | print("Calculating Numerical Solution......") 37 | print(lineSingle) 38 | 39 | un = numpy.ones(nx) 40 | 41 | for n in range(nt+1): #time marching 42 | un = u.copy() 43 | for i in range(1, nx-1): #Space marching 44 | 45 | u[i] = un[i] + nu * dt/dx**2 *(un[i+1] - 2*un[i] + un[i-1]) #Central Differnece Scheme 46 | 47 | print(lineSingle) 48 | print("Printing Numerical Solution......") 49 | print(lineSingle) 50 | 51 | print(u) 52 | 53 | print(lineSingle) 54 | print("Plotting Innitial & Numerical Solution") 55 | print(lineSingle) 56 | 57 | pyplot.plot(numpy.linspace(0,2,nx), u, label='Numerical Solution') 58 | pyplot.title('1D Diffusion Convecction') 59 | pyplot.xlabel('Grid Space') 60 | pyplot.ylabel('Velocity') 61 | 62 | pyplot.legend() 63 | pyplot.show() 64 | -------------------------------------------------------------------------------- /1D Linear Convection Equation.py: -------------------------------------------------------------------------------- 1 | import numpy #here we load numpy library that provides a bunch of useful matrix operations akin to MATLAB 2 | from matplotlib import pyplot #2D plotting library that we will use to plot our results 3 | 4 | lineSingle = '------------------------------------------------' 5 | 6 | print("Solving 1D Linear Equation using Finite Difference Method\n") 7 | 8 | nx = 60 #grip points 9 | dx = 4 / (nx -1) #grid spacing 10 | nt = 90 #number of timesteps 11 | dt = 0.025 #timestep size 12 | c = 1 #wavespeed 13 | 14 | #innitial condition 15 | 16 | #innitial condition 17 | 18 | print(lineSingle) 19 | print("Computing Innitial Solution...") 20 | 21 | u = numpy.ones(nx) #u = 1 across all grid points 22 | u[int(0.5/dx):int(1/dx+1)] = 2 #u = 2 from x = 0.5 to 1, Square Profile 23 | 24 | print("Printing Innitial Solution...") 25 | print(lineSingle) 26 | 27 | print(u) 28 | 29 | pyplot.plot(numpy.linspace(0, 4, nx), u, label='Initial Solution') 30 | 31 | print(lineSingle) 32 | print("Calculating Numerical Solution......") 33 | print(lineSingle) 34 | 35 | #discritization 36 | 37 | un = numpy.ones(nx) #initialize a temporary array, un is solution for next time step 38 | 39 | for n in range(nt): #time marching 40 | un = u.copy() 41 | for i in range(1, nx): #Space marching 42 | u[i] = un[i] - c*dt/dx*(un[i] - un[i - 1]) #Backward Differnece Scheme 43 | 44 | print(lineSingle) 45 | print("Printing Numerical Solution......") 46 | print(lineSingle) 47 | 48 | print(u) 49 | 50 | print(lineSingle) 51 | print("Plotting Innitial & Numerical Solution") 52 | print(lineSingle) 53 | 54 | pyplot.plot(numpy.linspace(0, 4, nx), u, label='Convected Solution') 55 | pyplot.title('1D Linear Convecction') 56 | pyplot.xlabel('Grid Space') 57 | pyplot.ylabel('Velocity') 58 | 59 | pyplot.legend() 60 | pyplot.show() 61 | 62 | -------------------------------------------------------------------------------- /1D Non Linear Convection Equationn.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy 3 | from matplotlib import pyplot 4 | 5 | lineSingle = '------------------------------------------------' 6 | 7 | print("Solving 1D Non Linear Equation using Finite Difference Method\n") 8 | 9 | while True: 10 | nx = input('Enter the number of Grid Points: ') #grip points 11 | 12 | if nx.isdigit() == False: 13 | print("Please provide an integer\n") 14 | continue 15 | else: 16 | nx = int(nx) 17 | 18 | dx = 2/ (nx - 1) #grid spacing 19 | nt = 20 #number of timesteps 20 | cfl = 0.5 21 | 22 | dt = cfl * dx #timestep size 23 | 24 | #innitial condition 25 | 26 | print(lineSingle) 27 | print("Computing Innitial Solution...") 28 | 29 | u = numpy.ones(nx) 30 | u[int(0.5/dx):int(1/dx+1)] = 2 #Square Wave Profile 31 | 32 | print("Printing Innitial Solution...") 33 | print(lineSingle) 34 | print(u) 35 | 36 | pyplot.plot(numpy.linspace(0,2,nx), u, label='Initial Solution') 37 | 38 | print(lineSingle) 39 | print("Calculating Numerical Solution......") 40 | print(lineSingle) 41 | 42 | #discritization 43 | 44 | un = numpy.ones(nx) 45 | for n in range(nt): #time marching 46 | un = u.copy() 47 | for i in range(1,nx): #Space marching 48 | u[i] = un[i] - un[i]*dt/dx* (un[i] - un[i-1]) #Backward Differnece Scheme 49 | 50 | print(lineSingle) 51 | print("Printing Numerical Solution......") 52 | print(lineSingle) 53 | 54 | print(u) 55 | 56 | print(lineSingle) 57 | print("Plotting Innitial & Numerical Solution") 58 | print(lineSingle) 59 | pyplot.plot(numpy.linspace(0,2,nx), u, label='Convected Solution') 60 | pyplot.title('1D Non Linear Convecction') 61 | pyplot.xlabel('Grid Space') 62 | pyplot.ylabel('Velocity') 63 | 64 | pyplot.legend() 65 | pyplot.show() 66 | break 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /1D_Linear Convection_Fine_Mesh.py: -------------------------------------------------------------------------------- 1 | import numpy #here we load numpy library that provides a bunch of useful matrix operations akin to MATLAB 2 | from matplotlib import pyplot #2D plotting library that we will use to plot our results 3 | 4 | lineSingle = '------------------------------------------------' 5 | 6 | print("Solving 1D Linear Equation with Fine Mesh using Finite Difference Method\n") 7 | 8 | nx = 800 #grip points 9 | dx = 2 / (nx -1) #grid spacing 10 | nt = 220 #number of timesteps 11 | dt = 0.0025 #timestep size 12 | c = 1 #wavespeed 13 | 14 | #innitial condition 15 | 16 | print(lineSingle) 17 | print("Computing Innitial Solution...") 18 | 19 | x = numpy.linspace(0, 2, nx) 20 | u = numpy.ones(nx) #u = 1 across all grid points 21 | for j in range(nx): 22 | if 0.5 <= x[j] and x[j] <= 1: 23 | u[j] = 2 #u = 2 from x = 0.5 to 1, Square Profile 24 | else: 25 | u[j] = 1 26 | 27 | print("Printing Innitial Solution...") 28 | print(lineSingle) 29 | print(u) 30 | 31 | pyplot.plot(numpy.linspace(0, 2, nx), u, label='Initial Solution'); 32 | 33 | #discritization 34 | 35 | un = numpy.ones(nx) 36 | 37 | for n in range(nt): #time marching 38 | un = u.copy() 39 | for i in range(1, nx): #Space marching 40 | u[i] = un[i] - c*dt/dx*(un[i] - un[i - 1]) #Backward Differnece Scheme 41 | 42 | print(lineSingle) 43 | print("Printing Numerical Solution......") 44 | print(lineSingle) 45 | 46 | print(u) 47 | 48 | print(lineSingle) 49 | print("Plotting Innitial & Numerical Solution") 50 | print(lineSingle) 51 | 52 | pyplot.plot(numpy.linspace(0, 2, nx), u, label='Convected Solution'); 53 | pyplot.title('1D Linear Convecction') 54 | pyplot.xlabel('Grid Space') 55 | pyplot.ylabel('Velocity') 56 | 57 | pyplot.legend() 58 | pyplot.show() 59 | 60 | -------------------------------------------------------------------------------- /2D Burgers Equation.py: -------------------------------------------------------------------------------- 1 | import numpy 2 | from matplotlib import pyplot, cm 3 | from mpl_toolkits.mplot3d import Axes3D 4 | 5 | lineSingle = '------------------------------------------------' 6 | 7 | print("Solving 2D Burgers Equation using Finite Difference Method") 8 | print("Convection Term: Backward Difference Scheme") 9 | print("Diffusion Term: Central Difference Scheme\n") 10 | 11 | nx = 41 #Grid Points Along X direction 12 | ny = 41 #Grid Points Along Y direction 13 | 14 | nt = 100 #Number of Time Steps 15 | 16 | #Grid Spacing 17 | 18 | dx = 2 / (nx - 1) 19 | dy = 2 / (ny - 1) 20 | 21 | cfl = 0.009 22 | 23 | nu = 0.01 #viscosity 24 | 25 | dt = cfl*dx*dy/nu #timestep size 26 | 27 | 28 | 29 | x = numpy.linspace(0,2,nx) #Coordinate Along X direction 30 | y = numpy.linspace(0,2,ny) #Coordinate Along Y direction 31 | 32 | #2d temporaray array where we copy our velocity field 33 | 34 | u = numpy.ones((ny,nx)) 35 | v = numpy.ones((ny, nx)) 36 | un = numpy.ones((ny,nx)) 37 | vn = numpy.ones((ny,nx)) 38 | comb = numpy.ones((ny,nx)) 39 | 40 | #innitial condition 41 | #Cuboidic Wave Profile 42 | 43 | u[int(0.5/dy):int(1/dy+1),int(0.5/dx):int(1/dx+1)] = 2 44 | v[int(0.5/dy):int(1/dy+1),int(0.5/dx):int(1/dx+1)] = 2 45 | 46 | print(lineSingle) 47 | print("Plotting Innitial Solution: Cuboidic Wave Profile") 48 | print(lineSingle) 49 | 50 | fig = pyplot.figure(figsize=(11,7),dpi=100) #Initializing the figure 51 | ax = fig.gca(projection='3d') 52 | X,Y = numpy.meshgrid(x,y) 53 | 54 | ax.plot_surface(X,Y,u[:],cmap=cm.viridis,rstride=1,cstride=1) 55 | ax.plot_surface(X,Y,v[:],cmap=cm.viridis,rstride=1,cstride=1) 56 | 57 | ax.set_title('Initial Velocity Field') 58 | ax.set_xlabel('X Spacing') 59 | ax.set_ylabel('Y Spacing') 60 | ax.set_zlabel('Velocity') 61 | pyplot.show() 62 | 63 | print(lineSingle) 64 | print("Calculating Numerical Solution......") 65 | print(lineSingle) 66 | 67 | for n in range(nt+1): #time marching 68 | un = u.copy() 69 | vn = v.copy() 70 | 71 | #Backward Difference Scheme for Convection Term 72 | #Central Difference Scheme for Diffusion Term 73 | 74 | u[1:-1,1:-1] = (un[1:-1,1:-1] - dt/dx*un[1:-1,1:-1]*(un[1:-1,1:-1]-un[1:-1,0:-2])- 75 | dt/dy*vn[1:-1,1:-1]*(un[1:-1,1:-1] - un[0:-2,1:-1])+ 76 | nu*dt/dx**2 * (un[1:-1,2:]-2*un[1:-1,1:-1]+un[1:-1,0:-2])+ 77 | nu*dt/dy**2 * (un[2:,1:-1]-2*un[1:-1,1:-1]+un[0:-2,1:-1])) 78 | 79 | v[1:-1,1:-1] =(vn[1:-1,1:-1] - dt/dx*un[1:-1,1:-1]*(vn[1:-1,1:-1]-vn[1:-1,0:-2])- 80 | dt/dy*vn[1:-1,1:-1]*(vn[1:-1,1:-1] - vn[0:-2,1:-1])+ 81 | nu*dt/dx**2 * (vn[1:-1,2:]-2*vn[1:-1,1:-1]+vn[1:-1,0:-2])+ 82 | nu*dt/dy**2 * (vn[2:,1:-1]-2*vn[1:-1,1:-1]+vn[0:-2,1:-1])) 83 | 84 | #boundary condition 85 | 86 | u[0,:] = 1 87 | u[-1,:] = 1 88 | u[:,0] = 1 89 | u[:,-1] = 1 90 | 91 | v[0,:] = 1 92 | v[-1,:] = 1 93 | v[:,0] = 1 94 | v[:,-1] = 1 95 | 96 | print(lineSingle) 97 | print("Plotting Numerical Solution") 98 | print(lineSingle) 99 | 100 | fig = pyplot.figure(figsize=(11,7),dpi=100) 101 | ax = fig.gca(projection='3d') 102 | 103 | X,Y = numpy.meshgrid(x,y) 104 | ax.plot_surface(X,Y,u[:],cmap=cm.viridis,rstride=1,cstride=1) 105 | ax.plot_surface(X,Y,v[:],cmap=cm.viridis,rstride=1,cstride=1) 106 | ax.set_title('Final Velocity Field') 107 | ax.set_xlabel('X Spacing') 108 | ax.set_ylabel('Y Spacing') 109 | ax.set_zlabel('Velocity') 110 | pyplot.show() 111 | -------------------------------------------------------------------------------- /2D Diffusion Equation.py: -------------------------------------------------------------------------------- 1 | import numpy 2 | from matplotlib import pyplot, cm 3 | from mpl_toolkits.mplot3d import Axes3D 4 | 5 | lineSingle = '------------------------------------------------' 6 | 7 | print("Solving 2D Diffusion Convection Equation using Finite Difference Method\n") 8 | 9 | nx = 31 #grid points in x-Direction 10 | ny = 31 #grid points in y-Direction 11 | nu = 0.05 #viscosity 12 | 13 | #grid spacing 14 | 15 | dx = 2/(nx-1) 16 | dy = 2/(ny-1) 17 | 18 | cfl = 0.25 19 | dt = cfl*dx*dy/nu #time step based on von neumann stability analysis 20 | nt = 10 #number of time step 21 | 22 | x = numpy.linspace(0, 2, nx) #array along x 23 | y = numpy.linspace(0, 2, ny) #array along y 24 | 25 | #2d temporaray array where we copy our velocity field 26 | 27 | u = numpy.ones((ny,nx)) 28 | un = numpy.ones((ny,nx)) 29 | 30 | #innitial condition 31 | #Cuboidic Wave Profile 32 | 33 | u[int(0.5/dy):int(1/dy + 1),int(0.5/dx):int(1/dx+1)] = 2 34 | 35 | #plotting innitial condition 36 | 37 | print(lineSingle) 38 | print("Plotting Innitial Solution: Cuboidic Wave Profile") 39 | print(lineSingle) 40 | 41 | 42 | fig = pyplot.figure() 43 | ax = fig.gca(projection='3d') 44 | X,Y = numpy.meshgrid(x, y) 45 | surf = ax.plot_surface(X,Y,u, rstride=1, cstride=1, cmap=cm.viridis, linewidth=0, antialiased=False) 46 | 47 | ax.set_title('Initial Velocity Field') 48 | ax.set_xlabel('X Spacing') 49 | ax.set_ylabel('Y Spacing') 50 | ax.set_zlabel('Velocity') 51 | 52 | 53 | ax.set_xlim(0,2) 54 | ax.set_ylim(0,2) 55 | ax.set_zlim(1,2.5) 56 | 57 | pyplot.show() 58 | 59 | print(lineSingle) 60 | print("Calculating Numerical Solution......") 61 | print(lineSingle) 62 | 63 | for n in range(nt+1): 64 | un = u.copy() 65 | 66 | #Central Difference Scheme 67 | 68 | u[1:-1,1:-1] = (un[1:-1,1:-1] + (nu*dt/dx**2)*(un[2:,1:-1] -2*un[1:-1,1:-1] + un[0:-2,1:-1]) + (nu*dt/dy**2)*(un[1:-1,2:] - 2*un[1:-1,1:-1] + un[1:-1,0:-2])) 69 | 70 | #Boundary Condition 71 | 72 | u[0,:] = 1 73 | u[-1,:] = 1 74 | u[:,0] = 1 75 | u[:,-1] = 1 76 | 77 | print(lineSingle) 78 | print("Plotting Numerical Solution") 79 | print(lineSingle) 80 | 81 | fig = pyplot.figure() 82 | ax = fig.gca(projection='3d') 83 | surf = ax.plot_surface(X,Y,u[:], rstride=1, cstride=1, cmap=cm.viridis,linewidth=0, antialiased=True) 84 | ax.set_zlim(1, 2.5) 85 | 86 | ax.set_title('Final Velocity Field') 87 | ax.set_xlabel('X Spacing') 88 | ax.set_ylabel('Y Spacing') 89 | ax.set_zlabel('Velocity') 90 | pyplot.show() 91 | -------------------------------------------------------------------------------- /2D Laplace Equation.py: -------------------------------------------------------------------------------- 1 | import numpy 2 | from matplotlib import pyplot, cm 3 | from mpl_toolkits.mplot3d import Axes3D 4 | 5 | lineSingle = '------------------------------------------------' 6 | 7 | print("Solving Laplace Equation using Finite Difference Method\n") 8 | 9 | #Function for plotting initial & steady state solution 10 | 11 | def plot2D(x, y, p): 12 | 13 | fig = pyplot.figure(figsize=(11,7),dpi=100) 14 | ax = fig.gca(projection='3d') 15 | 16 | X,Y=numpy.meshgrid(x,y) #Generating 2D Mesh 17 | 18 | surf = ax.plot_surface(X,Y,p[:],rstride=1,cstride=1,cmap=cm.viridis,linewidth=0,antialiased=False) 19 | ax.set_xlim(0, 2) 20 | ax.set_ylim(0, 1) 21 | ax.set_xlabel('X Spacing') 22 | ax.set_ylabel('Y Spacing') 23 | ax.set_zlabel('Velocity') 24 | ax.view_init(30, 225) 25 | 26 | 27 | #Function for solving Laplace Equation 28 | 29 | def laplace2d(p, y, dx, dy, residual_target): 30 | 31 | residual = 1 #innitial error 32 | pm = numpy.empty_like(p) 33 | 34 | iteration = 0 35 | while residual > residual_target: #Convergence Criteria 36 | pn = p.copy() 37 | p[1:-1,1:-1] = ((dy**2*(pn[2:,1:-1]+pn[0:-2,1:-1]) + 38 | dx**2*(pn[1:-1,2:]+pn[1:-1,0:-2]))/ 39 | (2*(dx**2 + dy**2))) 40 | 41 | #Boundary Condition 42 | 43 | p[:,0] = 0 # p = 0 @ x = 0 44 | p[:,-1] = y # p = y @ x = 2 45 | p[0,:] = p[1,:] # dp/dy = 0 @ y = 0 46 | p[-1,:] = p[-2,:] # dp/dy = 0 @ y = 1 47 | 48 | residual = (numpy.sum(numpy.abs(p[:]) - numpy.abs(pn[:]))/ 49 | numpy.sum(numpy.abs(pn[:]))) 50 | 51 | iteration += 1 52 | 53 | print('number of iteration :', iteration) 54 | return p 55 | 56 | 57 | nx = 31 #Grid Point Along X 58 | ny = 31 #Grid Point Along Y 59 | 60 | #Grid Spacing 61 | 62 | dx = 2 / (nx-1) 63 | dy = 2 / (ny-1) 64 | 65 | #initial condition 66 | p = numpy.zeros((ny,nx)) # innitial guess, pressure everywhere is 0 67 | 68 | 69 | 70 | #array 71 | x = numpy.linspace(0,2,nx) 72 | y = numpy.linspace(0,1,ny) 73 | 74 | #Innitial Condition 75 | 76 | p[:,0] = 0 # p = 0 @ x = 0 77 | p[:,-1] = y # p = y @ x = 2 78 | p[0,:] = p[1,:] # dp/dy = 0 @ y = 0 79 | p[-1,:] = p[-2,:] # dp/dy = 0 @ y = 1 80 | 81 | #Calling function to plot initial state solution 82 | 83 | plot2D(x,y,p) 84 | 85 | print(lineSingle) 86 | print("Plotting Innitial Solution") 87 | print(lineSingle) 88 | 89 | 90 | pyplot.show() 91 | 92 | print(lineSingle) 93 | print("Calculating Numerical Solution......") 94 | print(lineSingle) 95 | print(lineSingle) 96 | print("Solution Converged!") 97 | print(lineSingle) 98 | 99 | p = laplace2d(p, y, dx, dy, 1e-5) #Calling function to start the simulation 100 | 101 | print(lineSingle) 102 | print("Plotting Numerical Solution") 103 | print(lineSingle) 104 | 105 | #Calling function to plot stead state solution 106 | 107 | plot2D(x,y,p) 108 | pyplot.show() 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /2D Linear Convection Equation .py: -------------------------------------------------------------------------------- 1 | from mpl_toolkits.mplot3d import Axes3D #To plot a projected 3D result, make sure that you have added the Axes3D library 2 | 3 | import numpy 4 | from matplotlib import pyplot, cm 5 | import time 6 | 7 | lineSingle = '------------------------------------------------' 8 | 9 | print("Solving 2D Linear Convection Equation using Finite Difference Method\n") 10 | 11 | print(lineSingle) 12 | print("METHOD - I") 13 | print("Using Nested FOR Loop") 14 | print(lineSingle) 15 | 16 | 17 | #meshing 18 | 19 | nx = 81 #grid points in x-Direction 20 | ny = 81 #grid points in y-Direction 21 | 22 | nt = 80 #number of time step 23 | c = 1 #wave speed kept constant 24 | 25 | #grid spacing 26 | 27 | dx = 2 / (nx - 1) 28 | dy = 2 / (ny - 1) 29 | 30 | CFL = 0.2 31 | dt = CFL*dx #timestep size 32 | 33 | x = numpy.linspace(0, 2, nx) #array along x 34 | y = numpy.linspace(0, 2, ny) #array along y 35 | 36 | u = numpy.ones((ny, nx)) 37 | un = numpy.ones((ny, nx)) #2d temporaray array where we copy our velocity field 38 | 39 | #innitial condition 40 | 41 | u[int(0.5/dy):int(1/dy+1),int(0.5/dx):int(1/dx+1)] = 2 #Cuboidic Wave Profile 42 | 43 | #plotting innitial condition 44 | 45 | print(lineSingle) 46 | print("Plotting Innitial Solution: Cuboidic Wave Profile") 47 | print(lineSingle) 48 | 49 | fig = pyplot.figure(figsize=(11, 7), dpi=100) #innitilize plot window 50 | ax = fig.gca(projection = '3d') #defining axis is 3d 51 | X,Y = numpy.meshgrid(x, y) #Generating 2D Mesh 52 | 53 | #assign plot window the axes label ax, specifies its 3d projection plot 54 | #plot_surface is regular plot command but it takes a grid of x and y for data point position 55 | 56 | surf = ax.plot_surface(X, Y, u[:], cmap=cm.viridis) 57 | ax.set_title('Innitial Velocity Field') 58 | ax.set_xlabel('X Spacing') 59 | ax.set_ylabel('Y Spacing') 60 | ax.set_zlabel('Velocity') 61 | pyplot.show() 62 | 63 | 64 | start1 = time.time() #calculating solving time 65 | start1 = numpy.around(start1, decimals = 2) 66 | 67 | print(lineSingle) 68 | print("Calculating Numerical Solution......") 69 | print(lineSingle) 70 | 71 | for n in range(nt + 1): #time marching 72 | un = u.copy() 73 | row, col = u.shape 74 | 75 | #space marching 76 | 77 | for j in range(1,row): 78 | for i in range(1,col): 79 | 80 | #Backward Difference Scheme 81 | 82 | u[j,i] = (un[j,i] - (c * dt/dx * (un[j,i] - un[j,i-1])) - (c * dt/dx * (un[j,i] - un[j-1,i]))) 83 | 84 | #Boundary Conditions, U = 1 for x = 0,2 & Y = 0,2 85 | 86 | u[0, :] = 1 87 | u[-1, :] = 1 88 | u[:, 0] = 1 89 | u[:, -1] = 1 90 | 91 | print("Solving time with Nested FOR loop: %.4s seconds"% (time.time() - start1)) 92 | 93 | print(lineSingle) 94 | print("Plotting Numerical Solution") 95 | print(lineSingle) 96 | 97 | fig = pyplot.figure(figsize=(11,7), dpi=100) 98 | ax = fig.gca(projection = '3d') 99 | surf2 = ax.plot_surface(X, Y, u[:], cmap=cm.viridis) 100 | ax.set_title('Method - I:Using Nested FOR Loop') 101 | ax.set_xlabel('X Spacing') 102 | ax.set_ylabel('Y Spacing') 103 | ax.set_zlabel('Velocity') 104 | pyplot.show() 105 | 106 | 107 | 108 | #using array operation 109 | 110 | print(lineSingle) 111 | print("METHOD - II") 112 | print("Using ARRAYS Operation") 113 | print(lineSingle) 114 | 115 | print(lineSingle) 116 | print("Calculating Numerical Solution......") 117 | print(lineSingle) 118 | 119 | start2 = time.time() 120 | for n in range(nt + 1): 121 | un = u.copy() #itterative process 122 | u[1:, 1:] = (un[1:,1:] - (c * dt / dx * (un[1:,1:] - un[1:,:-1])) - (c * dt / dy * (un[1:,1:] - un[:-1,1:]))) #Backward Difference Scheme 123 | 124 | u[0, :] = 1 125 | u[-1, :] = 1 126 | u[:, 0] = 1 127 | u[:, -1] = 1 128 | 129 | print("Solving time with Array Operation: %.4s seconds"% (time.time() - start2)) 130 | 131 | print(lineSingle) 132 | print("Plotting Numerical Solution") 133 | print(lineSingle) 134 | 135 | fig = pyplot.figure(figsize=(11,7), dpi = 100) 136 | ax = fig.gca(projection = '3d') 137 | surf3 = ax.plot_surface(X, Y, u[:], cmap = cm.viridis) 138 | ax.set_title('Method - II: Using ARRAYS Operation') 139 | ax.set_xlabel('X Spacing') 140 | ax.set_ylabel('Y Spacing') 141 | ax.set_zlabel('Velocity') 142 | pyplot.show() 143 | -------------------------------------------------------------------------------- /2D Non Linear Convection Equation .py: -------------------------------------------------------------------------------- 1 | from mpl_toolkits.mplot3d import Axes3D 2 | from matplotlib import pyplot, cm 3 | import numpy 4 | 5 | lineSingle = '------------------------------------------------' 6 | 7 | print("Solving 2D Non - Linear Convection Equation using Finite Difference Method\n") 8 | 9 | nx = 101 #grid points in x-Direction 10 | ny = 101 #grid points in y-Direction 11 | 12 | nt = 80 #number of time step 13 | 14 | #grid spacing 15 | 16 | dx = 2/(nx - 1) 17 | dy = 2/(ny - 1) 18 | 19 | cfl = 0.2 20 | dt = cfl*dx #timestep size 21 | 22 | x = numpy.linspace(0 ,2, nx) #array along x 23 | y = numpy.linspace(0, 2, ny) #array along y 24 | 25 | #2d temporaray array where we copy our velocity field 26 | 27 | u = numpy.ones((ny,nx)) 28 | v = numpy.ones((ny,nx)) 29 | un = numpy.ones((ny,nx)) 30 | vn = numpy.ones((ny,nx)) 31 | 32 | #innitial condition 33 | #Cuboidic Wave Profile 34 | 35 | u[int(0.5/dy):int(1/dy+1),int(0.5/dx):int(1/dx+1)] = 2 36 | v[int(0.5/dy):int(1/dy+1),int(0.5/dx):int(1/dx+1)] = 2 37 | 38 | #plotting innitial condition 39 | 40 | print(lineSingle) 41 | print("Plotting Innitial Solution: Cuboidic Wave Profile") 42 | print(lineSingle) 43 | 44 | fig = pyplot.figure(figsize=(11, 7), dpi = 100) 45 | ax = fig.gca(projection = '3d') 46 | X,Y = numpy.meshgrid(x, y) #Generating 2D Mesh 47 | 48 | ax.plot_surface(X, Y, u[:],cmap=cm.viridis, rstride=2, cstride=2) 49 | ax.plot_surface(X, Y, v[:],cmap=cm.viridis, rstride=2, cstride=2) 50 | ax.set_title('Initial Velocity Field') 51 | ax.set_xlabel('X Spacing') 52 | ax.set_ylabel('Y Spacing') 53 | ax.set_zlabel('Velocity') 54 | pyplot.show() 55 | 56 | print(lineSingle) 57 | print("Calculating Numerical Solution......") 58 | print(lineSingle) 59 | 60 | for n in range(nt + 1): #time marching 61 | un = u.copy() 62 | vn = v.copy() 63 | 64 | #Backward Difference Scheme 65 | 66 | u[1:,1:] = (un[1:,1:] - (un[1:,1:]*dt/dx*(un[1:,1:] - un[1:,:-1])) - vn[1:,1:]*dt/dy*(un[1:,1:]-un[:-1,1:])) #Discretized U-Equation 67 | v[1:,1:] = (vn[1:,1:] - (un[1:,1:]*dt/dx*(vn[1:,1:] - vn[1:,:-1])) - vn[1:,1:]*dt/dy*(vn[1:,1:]-vn[:-1,1:])) #Discretized V-Equation 68 | 69 | #boundary condition 70 | 71 | u[0,:] = 1 72 | u[-1,0] = 1 73 | u[:,0] = 1 74 | u[:,-1] = 1 75 | 76 | v[0,:] = 1 77 | v[-1,0] = 1 78 | v[:,0] = 1 79 | v[:,-1] = 1 80 | 81 | print(lineSingle) 82 | print("Plotting Numerical Solution") 83 | print(lineSingle) 84 | 85 | fig = pyplot.figure(figsize=(11, 7), dpi = 100) 86 | ax = fig.gca(projection = '3d') 87 | X,Y = numpy.meshgrid(x, y) 88 | 89 | ax.plot_surface(X, Y, u[:],cmap=cm.viridis, rstride=2, cstride=2) 90 | ax.set_title('Convected Velocity Field') 91 | ax.set_xlabel('X Spacing') 92 | ax.set_ylabel('Y Spacing') 93 | ax.set_zlabel('Velocity') 94 | pyplot.show() 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /2D Poisson Equation.py: -------------------------------------------------------------------------------- 1 | import numpy #give mathamatical or matrix expressions like array 2 | from matplotlib import pyplot, cm #plotting library that we will use to plot our results 3 | from mpl_toolkits.mplot3d import Axes3D #To plot a projected 3D result, make sure that you have added the Axes3D library 4 | 5 | lineSingle = '------------------------------------------------' 6 | 7 | print("Solving Poisson Equation for Pressure using Finite Difference Method\n") 8 | 9 | #meshing 10 | 11 | nx = 60 #Grid Points along X direction 12 | ny = 60 #Grid Points along Y direction 13 | 14 | iteration = input('Enter the number of Iterations to Solve: ') 15 | 16 | if iteration.isdigit() == False: 17 | print("Please provide an integer\n") 18 | else: 19 | iteration = int(iteration) 20 | 21 | #Grid Spacing 22 | 23 | xmin = 0 24 | xmax = 2 25 | ymin = 0 26 | ymax = 1 27 | 28 | dx = (xmax - xmin) / (nx - 1) 29 | dy = (ymax - ymin) / (ny - 1) 30 | 31 | #initilization 32 | 33 | p = numpy.zeros((ny,nx)) 34 | pd = numpy.zeros((ny,nx)) 35 | b = numpy.zeros((ny,nx)) 36 | x = numpy.linspace(xmin,xmax,nx) 37 | y = numpy.linspace(ymin,ymax,ny) 38 | 39 | #sourceterm on RHS of Poisson Equation 40 | 41 | b[int(ny/4),int(nx/4)] = 100 42 | b[int(3*ny/4),int(3*nx/4)] = -100 43 | 44 | #Defining a Function for plotting initial & steady state solution 45 | 46 | def plot2D(x, y, p): 47 | fig = pyplot.figure(figsize=(11, 7), dpi=100) 48 | ax = fig.gca(projection='3d') 49 | 50 | #Generating 2D Mesh 51 | X, Y = numpy.meshgrid(x, y) 52 | 53 | surf = ax.plot_surface(X, Y, b, rstride=1, cstride=1, cmap=cm.viridis,linewidth=0, antialiased=False) 54 | ax.view_init(30, 225) 55 | ax.set_title('Initial Solution') 56 | ax.set_xlabel('X Spacing') 57 | ax.set_ylabel('Y Spacing') 58 | ax.set_zlabel('Velocity') 59 | 60 | print(lineSingle) 61 | print("Plotting Innitial Solution") 62 | print(lineSingle) 63 | 64 | plot2D(x,y,p) 65 | pyplot.show() 66 | 67 | #Solving the Poisson Equation 68 | 69 | print(lineSingle) 70 | print("Calculating Numerical Solution......") 71 | print(lineSingle) 72 | 73 | for it in range(iteration): 74 | 75 | pd = p.copy() 76 | 77 | #Central Difference Scheme 78 | 79 | p[1:-1,1:-1] = (((pd[1:-1,2:] + pd[1:-1,:-2])*dy**2 + (pd[2:,1:-1] + pd[:-2,1:-1])*dx**2 80 | - b[1:-1,1:-1]*dx**2 * dy**2) / (2*(dx**2 + dy**2))) 81 | 82 | #Boundary Condition 83 | 84 | p[0,:] = 0 85 | p[ny-1,:] = 0 86 | p[:,0] = 0 87 | p[:,nx-1] = 0 88 | 89 | print(lineSingle) 90 | print("Iterations Completed!") 91 | print(lineSingle) 92 | 93 | print(lineSingle) 94 | print("Plotting Solution") 95 | print(lineSingle) 96 | 97 | def plot2D(x, y, p): 98 | fig = pyplot.figure(figsize=(11, 7), dpi=100) 99 | ax = fig.gca(projection='3d') 100 | 101 | X, Y = numpy.meshgrid(x, y) #Generating 2D Mesh 102 | 103 | surf = ax.plot_surface(X, Y, p[:], rstride=1, cstride=1, cmap=cm.viridis,linewidth=0, antialiased=False) 104 | ax.view_init(30, 225) 105 | ax.set_title('Steady State Solution') 106 | ax.set_xlabel('X Spacing') 107 | ax.set_ylabel('Y Spacing') 108 | ax.set_zlabel('Velocity') 109 | 110 | plot2D(x,y,p) 111 | pyplot.show() 112 | -------------------------------------------------------------------------------- /Cavity Flow.py: -------------------------------------------------------------------------------- 1 | import numpy 2 | from matplotlib import pyplot, cm 3 | from mpl_toolkits.mplot3d import Axes3D 4 | 5 | lineSingle = '------------------------------------------------' 6 | 7 | print("Cavity Flow in 2D using Finite Difference Method\n") 8 | 9 | print("Unsteady Term : Forward Euler Scheme") 10 | print("Convection Term: Backward Difference Scheme") 11 | print("Diffusion Term : Central Difference Scheme\n") 12 | 13 | print("Velocity of Cavity Lid: 1 m/s") 14 | 15 | nx = 41 #Grid Points along X direction 16 | ny = 41 #Grid Points along Y direction 17 | 18 | iteration = input('Enter the number of Iterations to Solve: ') 19 | 20 | if iteration.isdigit() == False: 21 | print("Please provide an integer\n") 22 | else: 23 | iteration = int(iteration) 24 | 25 | 26 | nt = 100 #Number of Time Step 27 | 28 | #Grid Spacing 29 | 30 | dx = 2 / (nx - 1) 31 | dy = 2 / (ny - 1) 32 | 33 | x = numpy.linspace(0, 2, nx) 34 | y = numpy.linspace(0, 2, ny) 35 | X,Y = numpy.meshgrid(x, y) #Generating a 2D Mesh 36 | 37 | #fluid property 38 | 39 | rho = 1 #Density 40 | nu = 0.1 #Viscosity 41 | 42 | dt = 0.001 #time step size 43 | 44 | #initilization 45 | 46 | u = numpy.zeros((ny,nx)) 47 | v = numpy.zeros((ny,nx)) 48 | p = numpy.zeros((ny,nx)) 49 | b = numpy.zeros((ny,nx)) 50 | 51 | #Solving RHS of poisson eqution in a separate function 52 | 53 | def build_up_p(b, rho, dt, u, v, dx, dy): 54 | 55 | b[1:-1,1:-1] = (rho *(1 / dt * ((u[1:-1,2:] - u[1:-1,0:-2]) / (2*dx) + (v[2:,1:-1] - v[:-2,1:-1]) / (2 * dy)) 56 | - ((u[1:-1,2:] - u[1:-1,0:-2]) / (2 * dx))**2 - 57 | 2 * ((u[2:,1:-1] - u[:-2,1:-1]) / (2 * dy) * (v[1:-1,2:] - v[1:-1,:-2]) / (2 * dx)) 58 | - ((v[2:,1:-1] - v[:-2,1:-1]) / (2 * dy))**2)) 59 | 60 | return b 61 | 62 | #Solving Poisson Equation for Pressure 63 | 64 | def pressure_poisson(p, dx, dy, b): 65 | pn = numpy.empty_like(p) 66 | pn = p.copy() 67 | 68 | for q in range(iteration): 69 | pn = p.copy() 70 | p[1:-1,1:-1] = (((pn[1:-1,2:]+pn[1:-1,:-2])*dy**2 + (pn[2:,1:-1]+pn[:-2,1:-1])*dx**2) / 71 | (2*(dx**2 + dy**2)) - dx**2 * dy**2 /(2*(dx**2 + dy**2)) * b[1:-1,1:-1]) 72 | 73 | #Boundary Condition 74 | 75 | p[:,-1] = p[:,-2] #dp/dx = 0 at x = 2 76 | p[0,:] = p[1,:] #dp/dy = 0 at y = 0 77 | p[:,0] = p[:,1] #dp/dx = 0 at x = 0 78 | p[-1,:] = 0 #p = 0 at y = 0 pressure outlet, atmospheric presure 79 | 80 | return p 81 | 82 | 83 | def cavity_flow(nt, u, v, dt, dx, dy, p, rho, nu): 84 | un = numpy.empty_like(u) 85 | vn = numpy.empty_like(v) 86 | b = numpy.zeros((ny,nx)) 87 | 88 | for n in range(nt): 89 | un = u.copy() 90 | vn = v.copy() 91 | 92 | b = build_up_p(b, rho, dt, u, v, dx, dy) 93 | 94 | #Calling the Pressure Field 95 | 96 | p = pressure_poisson(p, dx, dy, b) 97 | 98 | #Solving X Momentum 99 | 100 | u[1:-1,1:-1] = (un[1:-1,1:-1]- 101 | un[1:-1,1:-1] * dt / dx * 102 | (un[1:-1,1:-1] - un[1:-1,:-2])- 103 | vn[1:-1,1:-1] * dt / dy * 104 | (un[1:-1,1:-1] - un[:-2,1:-1]) - 105 | dt / (2 * rho * dx) * (p[1:-1,2:] - p[1:-1,:-2]) + 106 | nu * (dt / dx**2 * 107 | (un[1:-1,2:] - 2 * un[1:-1,1:-1] + un[1:-1,:-2]) + 108 | dt / dy**2 * 109 | (un[2:,1:-1] - 2 * un[1:-1,1:-1] + un[:-2,1:-1]))) 110 | 111 | #Solving Y Momentum 112 | 113 | v[1:-1,1:-1] = (vn[1:-1,1:-1]- 114 | un[1:-1,1:-1] * dt / dx * 115 | (vn[1:-1,1:-1] - vn[1:-1,:-2]) - 116 | vn[1:-1,1:-1] * dt / dy * 117 | (vn[1:-1,1:-1] - vn[:-2,1:-1]) - 118 | dt / (2 * rho * dy) * (p[2:,1:-1] - p[:-2,1:-1]) + 119 | nu * (dt / dx**2 * 120 | (vn[1:-1,2:] - 2 * vn[1:-1,1:-1] + vn[1:-1,:-2]) + 121 | dt / dy**2 * 122 | (vn[2:,1:-1] - 2 * vn[1:-1,1:-1] + vn[:-2,1:-1]))) 123 | 124 | #Boundary Condition 125 | 126 | u[0,:] = 0 127 | u[:,0] = 0 128 | u[:,-1] = 0 129 | u[-1,:] = 2 #at cavity lid velocity is 1 130 | v[0,:] = 0 131 | v[-1,:] = 0 132 | v[:,0] = 0 133 | v[:,-1] = 0 134 | 135 | return u, v, p 136 | 137 | print(lineSingle) 138 | print("Calculating Numerical Solution......") 139 | print(lineSingle) 140 | 141 | u, v, p = cavity_flow(nt, u, v, dt, dx, dy, p, rho, nu) 142 | 143 | print(lineSingle) 144 | print("Iteration Completed!") 145 | print(lineSingle) 146 | 147 | 148 | fig = pyplot.figure(figsize=(11,7),dpi=100) 149 | 150 | #plotting pressure contour 151 | 152 | print(lineSingle) 153 | print("Plotting Pressure Field") 154 | print(lineSingle) 155 | 156 | pyplot.contourf(X,Y,u, alpha=0.5,cmap=cm.viridis) 157 | pyplot.colorbar() 158 | pyplot.contour(X, Y, p) 159 | pyplot.xlabel('X') 160 | pyplot.ylabel('Y') 161 | pyplot.title('Pressure Contour') 162 | pyplot.show() 163 | 164 | #plotting vector field 165 | 166 | print(lineSingle) 167 | print("Plotting Velocity Vectors") 168 | print(lineSingle) 169 | 170 | pyplot.quiver(X[::2, ::2], Y[::2, ::2], u[::2, ::2], v[::2, ::2]) 171 | pyplot.xlabel('X') 172 | pyplot.ylabel('Y') 173 | pyplot.title('Velocity Vectors') 174 | pyplot.show() 175 | 176 | #plotting velocity contour 177 | 178 | print(lineSingle) 179 | print("Plotting Velocity Field") 180 | print(lineSingle) 181 | 182 | fig = pyplot.figure(figsize=(11, 7), dpi=100) 183 | pyplot.contourf(X, Y, p, alpha=0.5, cmap=cm.viridis) 184 | pyplot.colorbar() 185 | pyplot.contour(X, Y, p, cmap=cm.viridis) 186 | pyplot.streamplot(X, Y, u, v) 187 | pyplot.xlabel('X') 188 | pyplot.ylabel('Y') 189 | pyplot.title('Velocity Contour') 190 | pyplot.show() 191 | -------------------------------------------------------------------------------- /Channel Flow.py: -------------------------------------------------------------------------------- 1 | import numpy 2 | from matplotlib import pyplot, cm 3 | from mpl_toolkits.mplot3d import Axes3D 4 | 5 | lineSingle = '------------------------------------------------' 6 | 7 | print("Solving Channel Flow in 2D using Finite Difference Method\n") 8 | 9 | print("Unsteady Term : Forward Euler Scheme") 10 | print("Convection Term: Backward Difference Scheme") 11 | print("Diffusion Term : Central Difference Scheme\n") 12 | 13 | print("Channel Flow Velocity: 1 m/s") 14 | 15 | #Solving RHS of poisson eqution in a separate function 16 | 17 | def build_up_b(rho, dt, dx, dy, u, v): 18 | b = numpy.zeros_like(u) 19 | 20 | b[1:-1,1:-1] = (rho*(1/dt*((u[2:,1:-1]-u[:-2,1:-1])/(2*dx) + (v[1:-1,2:]-v[1:-1,:-2])/(2*dy)) 21 | - ((u[2:,1:-1]-u[:-2,1:-1])/(2*dx))**2 - 22 | 2*((u[1:-1,2:]-u[1:-1,:-2])/(2*dy) * (v[2:,1:-1]-v[:-2,1:-1])/(2*dx)) - 23 | ((v[1:-1,2:] - v[1:-1,:-2])/(2*dy))**2)) 24 | 25 | #periodic BC Pressure @ x = 2 26 | 27 | b[-1,1:-1] = (rho*(1/dt*((u[0,1:-1]-u[-2,1:-1])/(2*dx) + (v[-1,2:]-v[-1,:-2])/(2*dy)) 28 | - ((u[0,1:-1]-u[-2,1:-1])/(2*dx))**2 - 29 | 2*((u[-1,2:]-u[-1,:-2])/(2*dy) * (v[0,1:-1]-v[-2,1:-1])/(2*dx)) - 30 | ((v[-1,2:] - v[-1,:-2])/(2*dy))**2)) 31 | 32 | 33 | 34 | #periodic BC Pressure @ x = 0 35 | 36 | b[0,1:-1] = (rho*(1/dt*((u[1,1:-1]-u[-1,1:-1])/(2*dx) + (v[0,2:]-v[0,:-2])/(2*dy)) 37 | - ((u[1,1:-1]-u[-1,1:-1])/(2*dx))**2 - 38 | 2*((u[0,2:]-u[0,:-2])/(2*dy) * (v[1,1:-1]-v[-1,1:-1])/(2*dx)) - 39 | ((v[0,2:] - v[0,:-2])/(2*dy))**2)) 40 | 41 | return b 42 | 43 | #Solving Poisson Equation for Pressure 44 | 45 | def pressure_poisson_periodic(p, dx, dy): 46 | pn = numpy.empty_like(p) 47 | 48 | for q in range(iteration): 49 | pn = p.copy() 50 | 51 | p[1:-1,1:-1] = (((pn[2:,1:-1] + pn[:-2,1:-1])*(dy**2) 52 | + (pn[1:-1,2:]+p[1:-1,:-2])*(dx**2)) /(2*(dx**2 + dy**2)) 53 | - dx**2 * dy**2/(2 * (dx**2 + dy**2)) * b[1:-1,1:-1]) 54 | 55 | 56 | 57 | #periodic BC Pressure @ x = 2 58 | 59 | p[-1,1:-1] = (((pn[0,1:-1] + pn[-2,1:-1])*(dy**2) + (pn[-1,2:]+p[-1,:-2])*(dx**2)) / 60 | (2*(dx**2 + dy**2)) - dx**2 * dy**2/(2 * (dx**2 + dy**2)) * b[-1,1:-1]) 61 | 62 | #periodic BC Pressure @ x = 0 63 | 64 | p[0,1:-1] = (((pn[1,1:-1] + pn[-1,1:-1])*(dy**2) + (pn[0,2:]+p[0,:-2])*(dx**2)) / 65 | (2*(dx**2 + dy**2)) - dx**2 * dy**2/(2 * (dx**2 + dy**2)) * b[0,1:-1]) 66 | 67 | #wall bc, pressure 68 | 69 | p[:,-1] = p[:,-2] #dp/dy = 0 at y = 2 70 | p[:,0] = p[:,1] #dp/dy = 0 at y = 0 71 | 72 | return p 73 | 74 | #meshing 75 | 76 | nx = 41 #Grid Points along X direction 77 | ny = 41 #Grid Points along Y direction 78 | nt = 100 #Number of Time Step 79 | 80 | iteration = input('Enter the number of Iterations to Solve: ') 81 | 82 | if iteration.isdigit() == False: 83 | print("Please provide an integer\n") 84 | else: 85 | iteration = int(iteration) 86 | 87 | #Grid Spacing 88 | 89 | dx = 2 / (nx - 1) 90 | dy = 2 / (ny - 1) 91 | 92 | x = numpy.linspace(0, 2, nx) 93 | y = numpy.linspace(0, 2, ny) 94 | 95 | Y,X = numpy.meshgrid(x,y) #Generating a 2D Mesh 96 | 97 | #fluid property and timestep and source 98 | 99 | rho = 1 #Density 100 | nu = 0.1 #Viscosity 101 | 102 | #Source Term to the U-Momemtum Equation 103 | F = 1 104 | 105 | dt = 0.01 #time step size 106 | 107 | #innitial conditions 108 | 109 | u = numpy.zeros((nx, ny)) 110 | un = numpy.zeros((nx, ny)) 111 | 112 | v = numpy.zeros((nx, ny)) 113 | vn = numpy.zeros((nx, ny)) 114 | 115 | p = numpy.ones((nx, ny)) 116 | pn = numpy.ones((nx, ny)) 117 | 118 | b = numpy.zeros((nx, ny)) 119 | 120 | residual = 1 #Initial error 121 | iterations = 0 122 | 123 | print(lineSingle) 124 | print("Calculating Numerical Solution......") 125 | print(lineSingle) 126 | 127 | while residual > 0.01: #Convergence Criteria 128 | un = u.copy() 129 | vn = v.copy() 130 | 131 | #Calling the Pressure Field 132 | 133 | b = build_up_b(rho, dt, dx, dy, u, v) 134 | p = pressure_poisson_periodic(p, dx, dy) 135 | 136 | #Solving X Momentum 137 | 138 | u[1:-1,1:-1] = (un[1:-1,1:-1] - un[1:-1,1:-1]*((dt/dx)*(un[1:-1,1:-1]-un[:-2,1:-1])) 139 | - vn[1:-1,1:-1]*((dt/dy)*(un[1:-1,1:-1]-un[1:-1,:-2])) - ((dt/rho*2*dx)*(p[2:,1:-1]-p[:-2,1:-1])) 140 | + nu*(((dt/dx**2)*(un[2:,1:-1]-2*un[1:-1,1:-1]+un[:-2,1:-1])) 141 | + ((dt/dy**2)*(un[1:-1,2:]-2*un[1:-1,1:-1]+un[1:-1,:-2]))) + F * dt) 142 | 143 | #Solving Y Momentum 144 | 145 | v[1:-1,1:-1] = (vn[1:-1,1:-1] - un[1:-1,1:-1]*((dt/dx)*(vn[1:-1,1:-1]-vn[:-2,1:-1])) 146 | - vn[1:-1,1:-1]*((dt/dy)*(vn[1:-1,1:-1]-vn[1:-1,:-2])) - ((dt/rho*2*dy)*(p[1:-1,2:]-p[1:-1,:-2])) 147 | + nu*(((dt/dx**2)*(vn[2:,1:-1]-2*vn[1:-1,1:-1]+vn[:-2,1:-1])) 148 | + ((dt/dy**2)*(vn[1:-1,2:]-2*vn[1:-1,1:-1]+vn[1:-1,:-2])))) 149 | 150 | 151 | # Periodic BC u @ x = 2 152 | 153 | u[-1,1:-1] = (un[-1,1:-1] - un[-1,1:-1]*((dt/dx)*(un[-1,1:-1]-un[-2,1:-1])) 154 | - vn[-1,1:-1]*((dt/dy)*(un[-1,1:-1]-un[-1,:-2])) - ((dt/rho*2*dx)*(p[0,1:-1]-p[-2,1:-1])) 155 | + nu*(((dt/dx**2)*(un[0,1:-1]-2*un[-1,1:-1]+un[-2,1:-1])) 156 | + ((dt/dy**2)*(un[-1,2:]-2*un[-1,1:-1]+un[-1,:-2]))) + F * dt) 157 | 158 | # Periodic BC u @ x = 0 159 | 160 | u[0,1:-1] = (un[0,1:-1] - un[0,1:-1]*((dt/dx)*(un[0,1:-1]-un[-1,1:-1])) 161 | - vn[0,1:-1]*((dt/dy)*(un[0,1:-1]-un[0,:-2])) - ((dt/rho*2*dx)*(p[1,1:-1]-p[-1,1:-1])) 162 | + nu*(((dt/dx**2)*(un[1,1:-1]-2*un[0,1:-1]+un[-1,1:-1])) 163 | + ((dt/dy**2)*(un[0,2:]-2*un[0,1:-1]+un[0,:-2]))) + F * dt) 164 | 165 | # Periodic BC v @ X = 2 166 | 167 | v[-1,1:-1] = (vn[-1,1:-1] - un[-1,1:-1]*((dt/dx)*(vn[-1,1:-1]-vn[-2,1:-1])) 168 | - vn[-1,1:-1]*((dt/dy)*(vn[-1,1:-1]-vn[-1,:-2])) - ((dt/rho*2*dy)*(p[-1,2:]-p[-1,:-2])) 169 | + nu*(((dt/dx**2)*(vn[0,1:-1]-2*vn[-1,1:-1]+vn[-2,1:-1])) 170 | + ((dt/dy**2)*(vn[-1,2:]-2*vn[-1,1:-1]+vn[-1,:-2])))) 171 | 172 | # Periodic BC v @ X = 0 173 | 174 | v[0,1:-1] = (vn[0,1:-1] - un[0,1:-1]*((dt/dx)*(vn[0,1:-1]-vn[-1,1:-1])) 175 | - vn[0,1:-1]*((dt/dy)*(vn[0,1:-1]-vn[0,:-2])) - ((dt/rho*2*dy)*(p[0,2:]-p[0,:-2])) 176 | + nu*(((dt/dx**2)*(vn[1,1:-1]-2*vn[0,1:-1]+vn[-1,1:-1])) 177 | + ((dt/dy**2)*(vn[0,2:]-2*vn[0,1:-1]+vn[0,:-2])))) 178 | 179 | #WALL no slip condition 180 | 181 | u[:,0] = 0 182 | u[:,-1]= 0 183 | 184 | #WALL no penetration condition 185 | 186 | v[:,0] = 0 187 | v[:,-1]= 0 188 | 189 | residual = (numpy.sum(u) - numpy.sum(un)) / numpy.sum(u) 190 | iterations += 1 191 | 192 | print(lineSingle) 193 | print("Solution Converged!") 194 | print(lineSingle) 195 | 196 | print('number of iterations :', iteration) 197 | 198 | print(lineSingle) 199 | print("Plotting Velocity Vectors & Contour") 200 | print(lineSingle) 201 | 202 | fig = pyplot.figure(figsize = (11,7), dpi=100) 203 | pyplot.contourf(X,Y, u, alpha=0.5, cmap=cm.viridis) 204 | pyplot.colorbar() 205 | pyplot.contour(X,Y, u, cmap=cm.viridis) 206 | pyplot.quiver(X[::3, ::3], Y[::3, ::3], u[::3, ::3], v[::3, ::3]) 207 | pyplot.xlabel('X') 208 | pyplot.ylabel('Y') 209 | pyplot.show() 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | -------------------------------------------------------------------------------- /FVM_1D_Convection_Diffusion.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | print("\n") 5 | print("Finite Volume Method\n") 6 | print("Solving 1D Heat Convection Diffusion Equation with Dirichlet Boundary Condition\n") 7 | print("Discretization for Diffusion Term : Central Difference Scheme") 8 | print("Discretization for Convection Term: Central Difference Scheme\n") 9 | 10 | k = 100 11 | print("Conductivity of the Material:",k,'W/m-K') 12 | 13 | rho = 1 14 | print("Density of the Fluid:",rho,'Kg/m3') 15 | 16 | cp = 1000 17 | print("Specific Heat Capacity of the Fluid:",cp,'J/Kg-K') 18 | print("\n") 19 | 20 | u = float(input('Enter the flow velocity: ')) 21 | 22 | area = 0.1 23 | print("Cross Section Area of Rod:",area,'m2') 24 | 25 | barLength = 5 26 | print("\nLength of the rod:",barLength,'m') 27 | 28 | tempLeft = 100 29 | tempRight = 200 30 | print("Temperature at the Left End of the Rod:",tempLeft,'C') 31 | print("Temperature at the Right End of the Rod:",tempRight,'C') 32 | 33 | heatSourcePerVol = 1000 34 | print("Heat Source in the Rod:",heatSourcePerVol,'W/m3') 35 | print("\n") 36 | 37 | nCell = int(input('Enter the number of Cells for Meshing the Rod: ')) 38 | 39 | 40 | print ('------------------------------------------------') 41 | print (' Creating Mesh') 42 | print ('------------------------------------------------') 43 | 44 | #cell coordinates 45 | xFace = np.linspace(0, barLength, nCell+1) 46 | 47 | #cell centroids 48 | xCentroid = 0.5*(xFace[1:] + xFace[0:-1]) 49 | 50 | #cell length 51 | cellLength = xFace[1:] - xFace[:-1] 52 | 53 | #distance between cell centroids 54 | dCentroid = xCentroid[1:] - xCentroid[:-1] 55 | 56 | # For the boundary cell on the left, the distance is double the distance 57 | # from the cell centroid to the boundary face 58 | dLeft = 2*(xCentroid[0] - xFace[0]) 59 | 60 | # For the boundary cell on the right, the distance is double the distance 61 | #from the cell centroid to the boundary cell face 62 | dRight = 2*(xFace[-1] - xCentroid[-1]) 63 | 64 | # Append these to the vector of distances 65 | dCentroid = np.hstack([dLeft, dCentroid, dRight]) 66 | 67 | dCentroidLeft = dCentroid[0:-1] 68 | dCentroidRight = dCentroid[1:] 69 | areaLeftFaces = area*np.ones(nCell) 70 | areaRightFaces = area*np.ones(nCell) 71 | 72 | conductivityFaces = k*np.ones(nCell+1) 73 | conductivityLeftFaces = conductivityFaces[0:-1] 74 | conductivityRightFaces = conductivityFaces[1:] 75 | 76 | 77 | #cellVolume 78 | cellVolume = cellLength*area 79 | 80 | print ('------------------------------------------------') 81 | print (' Calculating Matrix Coefficients') 82 | print ('------------------------------------------------') 83 | 84 | #diffusive flux 85 | DA = area*np.divide(k, dCentroid) 86 | DA_LeftFaces = np.divide(np.multiply(conductivityLeftFaces,areaLeftFaces),dCentroidLeft) 87 | DA_RightFaces= np.divide(np.multiply(conductivityRightFaces,areaRightFaces),dCentroidRight) 88 | 89 | #convective flux 90 | velocityVector = u*np.ones(nCell+1) 91 | densityVector = rho*np.ones(nCell+1) 92 | F = np.multiply(velocityVector, densityVector)*area*cp 93 | F_LeftFaces = F[0:-1] 94 | F_RightFaces = F[1:] 95 | 96 | #peclet no. 97 | Pe = F/DA 98 | 99 | #source term Sp 100 | Sp = np.zeros(nCell) 101 | 102 | #Sp is not zero in left and right boundaries 103 | Sp[0] = -(2*(DA[0]) + F[0]) 104 | Sp[-1] = -(2*(DA[-1]) - F[-1]) 105 | 106 | #souce term Su 107 | Su = heatSourcePerVol*cellVolume 108 | 109 | #source term on left and right boundary 110 | Su[0] = Su[0] + tempLeft*(2*DA[0] + F[0]) 111 | Su[-1] = Su[-1] + tempRight*(2*DA[-1] - F[-1]) 112 | 113 | #left and right coefficient 114 | aL = DA[0:-1] + 0.5*(F[:-1]) 115 | aR = DA[0:-1] - 0.5*(F[:-1]) 116 | 117 | aL[0] = 0 118 | aR[-1] = 0 119 | 120 | #central coeff Ap 121 | aP = aL + aR - Sp 122 | 123 | #create matrix 124 | 125 | print ('------------------------------------------------') 126 | print (' Assembling Matrices') 127 | print ('------------------------------------------------') 128 | 129 | # create empty matrix A & empty vector B 130 | Amatrix = np.zeros([nCell, nCell]) 131 | Bvector = np.zeros(nCell) 132 | 133 | for i in range(nCell): 134 | 135 | #leftboundary 136 | if i == 0: 137 | Amatrix[i,i] = aP[i] 138 | Amatrix[i,i+1] = -1*aR[i] 139 | 140 | #rightboundary 141 | elif i == nCell-1: 142 | Amatrix[i,i] = aP[i] 143 | Amatrix[i,i-1] = -1*aL[i] 144 | 145 | #interior cells 146 | else: 147 | Amatrix[i,i-1] = -1*aL[i] 148 | Amatrix[i,i] = aP[i] 149 | Amatrix[i,i+1] = -1*aR[i] 150 | 151 | Bvector[i] = Su[i] 152 | 153 | #Print the setup 154 | 155 | 156 | 157 | print('aL:',aL) 158 | print('aR:',aR) 159 | print('aP:',aP) 160 | print('Sp:',Sp) 161 | print('Su:',Su) 162 | print('\nCell Peclet Number:',Pe) 163 | print('\nAmatrix:') 164 | print(Amatrix) 165 | print('\nBvector:',Bvector) 166 | print('\n') 167 | 168 | #Solve the matrices 169 | 170 | print ('------------------------------------------------') 171 | print (' Solving ...') 172 | print ('------------------------------------------------') 173 | 174 | # Use the built-in python solution module 175 | Tvector = np.linalg.solve(Amatrix, Bvector) 176 | 177 | print ('------------------------------------------------') 178 | print (' Equations Solved') 179 | print ('------------------------------------------------') 180 | 181 | #print result 182 | 183 | print('---------------------------------------------') 184 | print('Solution: Temperature Field') 185 | Tvector = np.around(Tvector, decimals = 2) 186 | print(Tvector) 187 | print("\n") 188 | 189 | temperatureStack = np.hstack([tempLeft, np.copy(Tvector), tempRight]) 190 | 191 | temperatureDifferenceLeft = temperatureStack[1:-1] - temperatureStack[0:-2] 192 | temperatureDifferenceRight = temperatureStack[2:] - temperatureStack[1:-1] 193 | 194 | temperatureFaces = 0.5*(Tvector[0:-1]+Tvector[1:]) 195 | temperatureFacesStack = np.hstack([tempLeft, np.copy(temperatureFaces), tempRight]) 196 | temperatureLeftFaces = temperatureFacesStack[0:-1] 197 | temperatureRightFaces = temperatureFacesStack[1:] 198 | 199 | normalLeft = -1*np.ones(nCell) 200 | normalRight = 1*np.ones(nCell) 201 | 202 | heatfluxLeftCond = -1*np.prod([normalLeft, temperatureDifferenceLeft, DA_LeftFaces],0) 203 | heatfluxRightCond = -1*np.prod([normalRight, temperatureDifferenceRight, DA_RightFaces],0) 204 | 205 | heatfluxLeftConv = 1 * np.prod([temperatureLeftFaces, F_LeftFaces],0) 206 | heatfluxRightConv = 1 * np.prod([temperatureRightFaces, F_RightFaces],0) 207 | 208 | heatfluxLeftCond[0] *= 2.0 209 | heatfluxRightCond[-1] *= 2.0 210 | 211 | heatSource = heatSourcePerVol*cellVolume 212 | heatBalanceError = heatSource - heatfluxLeftCond - heatfluxRightCond + heatfluxLeftConv - heatfluxRightConv 213 | 214 | 215 | 216 | print ('Energy Balance:') 217 | print ('------------------------------------------------') 218 | print ('Cell | QL_Cond | QR_Cond | QL_Conv | QR_Conv | SV | Error') 219 | print ('------------------------------------------------') 220 | for i in range(nCell): 221 | print('%4i %10.1f %12.1f %12.1f %11.1f %10.1f %7.1f' %(i+1, heatfluxLeftCond[i], heatfluxRightCond[i], heatfluxLeftConv[i], heatfluxRightConv[i], 222 | heatSource[i], heatBalanceError[i])) 223 | 224 | if Pe[i]>2: 225 | print("\n") 226 | print("Solution is diverged!") 227 | print("\n") 228 | print("Osillation observed in the solution!") 229 | print("This is due to High Convective Strength.") 230 | print("Central Differnce Scheme is not stable for highly Convective Flow.") 231 | print("Try to reduce Flow Velocity or Refine the Mesh or Switch to Upwind Scheme for Convection Term.\n") 232 | print("Use another code where Upwind Scheme for Convection Term is used.\n") 233 | 234 | 235 | 236 | 237 | #plot result 238 | 239 | 240 | print ('------------------------------------------------') 241 | print ('Plotting the results ...') 242 | print ('------------------------------------------------') 243 | 244 | #Append the boundary temperature values to the vector, so we can 245 | #plot the complete solution 246 | 247 | xPlotting = np.hstack([xFace[0], np.copy(xCentroid), xFace[-1]]) 248 | temperaturePlotting = np.hstack([tempLeft, np.copy(Tvector), tempRight]) 249 | 250 | # Configure the plot to look how you want 251 | tickPad = 8 252 | tickPad2 = 16 253 | labelPadY = 10 254 | labelPadX = 8 255 | boxPad = 5 256 | darkBlue = (0.0,0.129,0.2784) 257 | darkRed = (0.7176, 0.0705, 0.207) 258 | 259 | plt.rc('font', family='serif') 260 | plt.rcParams["figure.figsize"] = (6.2,4.2) 261 | plt.rcParams['axes.linewidth'] = 2 262 | 263 | fig1 = plt.figure() 264 | ax = fig1.add_subplot() 265 | fig1.tight_layout(pad=boxPad) 266 | 267 | ax.plot(xPlotting , temperaturePlotting, 'b-o',linewidth = 2, label='CFD', color=darkBlue) 268 | 269 | plt.xlabel(r'$x$ [m]', fontsize=14, labelpad = labelPadX) 270 | plt.ylabel(r'$T$ [$^{\circ}$C]', fontsize=14, labelpad = labelPadY) 271 | 272 | plt.yticks(fontsize = 14) 273 | plt.xticks(fontsize = 14) 274 | plt.xlim([xFace[0], xFace[-1]]) 275 | 276 | leg = plt.legend(fontsize = 14, loc='best', fancybox=False, edgecolor = 'k') 277 | leg.get_frame().set_linewidth(2) 278 | 279 | ax.tick_params(which = 'both', direction='in', length=6, width=2, gridOn = False) 280 | ax.yaxis.set_ticks_position('both') 281 | ax.xaxis.set_ticks_position('both') 282 | 283 | ax.tick_params(pad=tickPad) 284 | plt.show() 285 | -------------------------------------------------------------------------------- /FVM_1D_Convection_Diffusion_Upwind.py: -------------------------------------------------------------------------------- 1 | import numpy 2 | import matplotlib.pyplot as plt 3 | 4 | print("\n") 5 | print("Finite Volume Method\n") 6 | print("Solving 1D Heat Convection Diffusion Equation with Dirichlet Boundary Condition\n") 7 | print("Discretization for Diffusion Term : Central Difference Scheme") 8 | print("Discretization for Convection Term: Upwind Scheme\n") 9 | 10 | k = 100 11 | print("Conductivity of the Material:",k,'W/m-K') 12 | 13 | rho = 1 14 | print("Density of the Fluid:",rho,'Kg/m3') 15 | 16 | cp = 1000 17 | print("Specific Heat Capacity of the Fluid:",cp,'J/Kg-K') 18 | print("\n") 19 | 20 | u = float(input('Enter the flow velocity: ')) 21 | 22 | area = 0.1 23 | print("Cross Section Area of Rod:",area,'m2') 24 | 25 | barLength = 5 26 | print("\nLength of the rod:",barLength,'m') 27 | 28 | tempLeft = 100 29 | tempRight = 200 30 | print("Temperature at the Left End of the Rod:",tempLeft,'C') 31 | print("Temperature at the Right End of the Rod:",tempRight,'C') 32 | 33 | heatSourcePerVol = 1000 34 | print("Heat Source in the Rod:",heatSourcePerVol,'W/m3') 35 | print("\n") 36 | 37 | nCell = int(input('Enter the number of Cells for Meshing the Rod: ')) 38 | 39 | 40 | print ('------------------------------------------------') 41 | print (' Creating Mesh') 42 | print ('------------------------------------------------') 43 | 44 | #cell coordinates 45 | xFace = numpy.linspace(0, barLength, nCell+1) 46 | 47 | #cell centroids 48 | xCentroid = 0.5*(xFace[1:] + xFace[:-1]) 49 | 50 | #cell length 51 | cellLength = xFace[1:] - xFace[:-1] 52 | 53 | #distance between cell centroids 54 | dCentroid = xCentroid[1:] - xCentroid[:-1] 55 | 56 | # For the boundary cell on the left, the distance is double the distance 57 | # from the cell centroid to the boundary face 58 | dLeft = 2*(xCentroid[0] - xFace[0]) 59 | 60 | # For the boundary cell on the right, the distance is double the distance 61 | #from the cell centroid to the boundary cell face 62 | dRight = 2*(xFace[-1] - xCentroid[-1]) 63 | 64 | # Append these to the vector of distances 65 | dCentroid = numpy.hstack([dLeft, dCentroid, dRight]) 66 | 67 | #cellVolume 68 | cellVolume = area*cellLength 69 | 70 | print ('------------------------------------------------') 71 | print (' Calculating Matrix Coefficients') 72 | print ('------------------------------------------------') 73 | 74 | #diffusive flux 75 | DA = area*numpy.divide(k, dCentroid) 76 | 77 | #convective flux 78 | velocityVector = u*numpy.ones(nCell+1) 79 | F = velocityVector*rho*area*cp 80 | 81 | #peclet no. 82 | Pe = F/DA 83 | 84 | #source term Sp 85 | Sp = numpy.zeros(nCell) 86 | Sp[0] = -(2*numpy.copy(DA[0]) + numpy.maximum(numpy.copy(F[0]),0)) 87 | Sp[-1] = -(2*numpy.copy(DA[-1]) + numpy.maximum(-numpy.copy(F[-1]),0)) 88 | 89 | #souce term Su 90 | Su = heatSourcePerVol*cellVolume 91 | Su[0] =Su[0] + tempLeft*(2*numpy.copy(DA[0]) + numpy.maximum(numpy.copy(F[0]),0)) 92 | Su[-1] =Su[-1] + tempRight*(2*numpy.copy(DA[-1]) + numpy.maximum(-numpy.copy(F[-1]),0)) 93 | 94 | #left and right coefficient 95 | aL = numpy.copy(DA[0:-1]) + numpy.maximum(numpy.copy(F[0:-1]),numpy.zeros(nCell)) 96 | aR = numpy.copy(DA[0:-1]) + numpy.maximum(-numpy.copy(F[0:-1]),numpy.zeros(nCell)) 97 | aL[0] = 0 98 | aR[-1] = 0 99 | 100 | #central coeff Ap 101 | aP = numpy.copy(aL) + numpy.copy(aR) - numpy.copy(Sp) 102 | 103 | print ('------------------------------------------------') 104 | print (' Assembling Matrices') 105 | print ('------------------------------------------------') 106 | 107 | Amatrix = numpy.zeros([nCell, nCell]) 108 | Bvector = numpy.zeros(nCell) 109 | 110 | for i in range(nCell): 111 | 112 | if i == 0: 113 | Amatrix[i,i] = aP[i] 114 | Amatrix[i,i+1] = -1*aR[i] 115 | 116 | elif i == nCell - 1: 117 | Amatrix[i,i] = aP[i] 118 | Amatrix[i,i-1] = -1*aL[i] 119 | 120 | else: 121 | Amatrix[i,i-1] = -1*aL[i] 122 | Amatrix[i,i] = aP[i] 123 | Amatrix[i,i+1] = -1*aR[i] 124 | 125 | Bvector[i] = Su[i] 126 | 127 | 128 | 129 | print('aL:',aL) 130 | print('aR:',aR) 131 | print('aP:',aP) 132 | print('Sp:',Sp) 133 | print('Su:',Su) 134 | print('\nCell Peclet Number:',Pe) 135 | print('\nAmatrix:') 136 | print(Amatrix) 137 | print('\nBvector:',Bvector) 138 | 139 | print ('------------------------------------------------') 140 | print (' Solving ...') 141 | print ('------------------------------------------------') 142 | 143 | Tvector = numpy.linalg.solve(Amatrix, Bvector) 144 | 145 | print ('------------------------------------------------') 146 | print (' Equations Solved') 147 | print ('------------------------------------------------') 148 | 149 | print('---------------------------------------------') 150 | print('Solution: Temperature Field') 151 | Tvector = numpy.around(Tvector, decimals = 2) 152 | print(Tvector) 153 | print("\n") 154 | 155 | print ('------------------------------------------------') 156 | print (' Plotting ...') 157 | print ('------------------------------------------------') 158 | 159 | xPlotting = numpy.hstack([xFace[0], xCentroid, xFace[-1]]) 160 | temperaturePlotting = numpy.hstack([tempLeft, Tvector, tempRight]) 161 | 162 | tickPad = 8 163 | tickPad2 = 16 164 | labelPadY = 10 165 | labelPadX = 8 166 | boxPad = 5 167 | darkBlue = (0.0,0.129,0.2784) 168 | darkRed = (0.7176, 0.0705, 0.207) 169 | 170 | fig1 = plt.figure() 171 | ax = fig1.add_subplot() 172 | fig1.tight_layout(pad=boxPad) 173 | 174 | ax.plot(xPlotting , temperaturePlotting, 'b-o',linewidth = 2, label='CFD', color=darkBlue) 175 | 176 | plt.xlabel(r'$x$ [m]', fontsize=14, labelpad = labelPadX) 177 | plt.ylabel(r'$T$ [$^{\circ}$C]', fontsize=14, labelpad = labelPadY) 178 | plt.yticks(fontsize = 14) 179 | plt.xticks(fontsize = 14) 180 | plt.xlim([xFace[0], xFace[-1]]) 181 | 182 | leg = plt.legend(fontsize = 14, loc='best', fancybox=False, edgecolor = 'k') 183 | leg.get_frame().set_linewidth(2) 184 | ax.tick_params(which = 'both', direction='in', length=6,width=2, gridOn = False) 185 | 186 | ax.yaxis.set_ticks_position('both') 187 | ax.xaxis.set_ticks_position('both') 188 | ax.tick_params(pad=tickPad) 189 | plt.show() 190 | -------------------------------------------------------------------------------- /FVM_1D_Diffusion_Dirichlet_BC.py: -------------------------------------------------------------------------------- 1 | import numpy 2 | import matplotlib.pyplot as plt 3 | 4 | print("\n") 5 | print("Finite Volume Method\n") 6 | print("Solving 1D Heat Diffusion Equation with Dirichlet Boundary Condition\n") 7 | print("Discretization for Diffusion Term: Central Difference Scheme\n") 8 | 9 | cond = 100 10 | print("Conductivity of the Material:",cond,'W/m-K') 11 | 12 | area = 0.1 13 | print("Cross Section Area of Rod:",area,'m2') 14 | 15 | barLength = 5 16 | print("\nLength of the rod:",barLength,'m') 17 | 18 | #Dirichlet BC 19 | 20 | tempLeft = 100 21 | tempRight = 200 22 | print("Temperature at the Left End of the Rod:",tempLeft,'C') 23 | print("Temperature at the Right End of the Rod:",tempRight,'C') 24 | 25 | heatSourcePerVol = 1000 26 | print("Heat Source in the Rod:",heatSourcePerVol,'W/m3') 27 | print("\n") 28 | 29 | nCells = int(input('Enter the number of Cells for Meshing the Rod: ')) #Number of Cells 30 | 31 | #create mesh 32 | 33 | print ('------------------------------------------------') 34 | print (' Creating Mesh') 35 | print ('------------------------------------------------') 36 | 37 | #cell coordinates 38 | xFace = numpy.linspace(0, barLength, nCells+1) 39 | 40 | #cell centroids 41 | xCentroid = 0.5*(xFace[1:] + xFace[0:-1]) 42 | 43 | #cell length 44 | cellLength = xFace[1:] - xFace[:-1] 45 | 46 | #distance between cell centroids 47 | dCentroid = xCentroid[1:] - xCentroid[:-1] 48 | 49 | # For the boundary cell on the left, the distance is double the distance 50 | # from the cell centroid to the boundary face 51 | dLeft = 2*(xCentroid[0] - xFace[0]) 52 | 53 | # For the boundary cell on the right, the distance is double the distance 54 | #from the cell centroid to the boundary cell face 55 | dRight = 2*(xFace[-1] - xCentroid[-1]) 56 | 57 | # Append these to the vector of distances 58 | dCentroid = numpy.hstack([dLeft, dCentroid, dRight]) 59 | 60 | #cellvolume 61 | cellVolume = cellLength*area 62 | 63 | #Calculate the Matrix Coefficients 64 | 65 | print ('------------------------------------------------') 66 | print (' Calculating Matrix Coefficients') 67 | print ('------------------------------------------------') 68 | 69 | #diffusive flux per unit area 70 | DA = area*numpy.divide(cond, dCentroid) 71 | 72 | #source term Sp 73 | Sp = numpy.zeros(nCells) 74 | 75 | #Sp is not zero in left and right bounndaries 76 | Sp[0] = -2*numpy.copy(DA[0]) 77 | Sp[-1] = -2*numpy.copy(DA[-1]) 78 | 79 | #souce term Su 80 | Su = heatSourcePerVol*cellVolume 81 | 82 | #source term on left & right boundary 83 | Su[0] = Su[0] + 2*tempLeft*numpy.copy(DA[0]) 84 | Su[-1] = Su[-1] + 2*tempRight*numpy.copy(DA[-1]) 85 | 86 | #left coefficient aL 87 | aL = numpy.copy(DA[0:-1]) 88 | 89 | #right coefficient aR 90 | aR = numpy.copy(DA[0:-1]) 91 | 92 | aL[0] = 0 93 | aR[-1] = 0 94 | 95 | #central coeff Ap 96 | aP = numpy.copy(aL) + numpy.copy(aR) - numpy.copy(Sp) 97 | 98 | #creat matrix 99 | 100 | print ('------------------------------------------------') 101 | print (' Assembling Matrices') 102 | print ('------------------------------------------------') 103 | 104 | 105 | # creat empty matrix A & empty vector B 106 | 107 | Amatrix = numpy.zeros([nCells, nCells]) 108 | BVector = numpy.zeros(nCells) 109 | 110 | for i in range(nCells): 111 | 112 | #left boundary 113 | if i == 0: 114 | Amatrix[i,i] = aP[i] 115 | Amatrix[i,i+1] = -1*aR[i] 116 | 117 | #right boundary 118 | elif i == nCells - 1: 119 | Amatrix[i,i-1] = -1*aL[i] 120 | Amatrix[i,i] = aP[i] 121 | 122 | #interior cells 123 | else: 124 | 125 | Amatrix[i,i-1] = -1*aL[i] 126 | Amatrix[i,i] = aP[i] 127 | Amatrix[i,i+1] = -1*aR[i] 128 | 129 | BVector[i] = Su[i] 130 | 131 | #Print the setup 132 | 133 | print('aL:',aL) 134 | print('aR:',aR) 135 | print('aP:',aP) 136 | print('Sp:',Sp) 137 | print('\nSu:',Su) 138 | print('\nAmatrix:') 139 | print(Amatrix) 140 | print('\nBVector:',numpy.around(BVector,decimals=2)) 141 | print('\n') 142 | 143 | print ('------------------------------------------------') 144 | print ('Printing Cell Summary..') 145 | print ('------------------------------------------------') 146 | 147 | print(' aL aR Sp Su aP') 148 | for i in range(nCells): 149 | print('Cell%2i %5.1f %5.1f %5.1f %7.1f %5.1f' %(i+1, aL[i], aR[i], Sp[i], Su[i], aP[i])) 150 | 151 | #Solve the matrices 152 | 153 | print ('------------------------------------------------') 154 | print (' Solving ...') 155 | print ('------------------------------------------------') 156 | 157 | # Use the built-in python solution module 158 | Tvector = numpy.linalg.solve(Amatrix, BVector) 159 | 160 | print ('------------------------------------------------') 161 | print (' Equations Solved') 162 | print ('------------------------------------------------') 163 | 164 | #print the result 165 | 166 | 167 | print ('------------------------------------------------') 168 | print (' Solution: Temperature Field') 169 | Tvector = numpy.around(Tvector, decimals = 2) 170 | print(Tvector) 171 | 172 | #plot result 173 | 174 | 175 | 176 | print ('------------------------------------------------') 177 | print (' Plotting ...') 178 | print ('------------------------------------------------') 179 | 180 | 181 | #append the boundary temperature & interior temperature 182 | #plot the solution 183 | 184 | xPlotting = numpy.hstack([xFace[0], numpy.copy(xCentroid), xFace[-1]]) 185 | tempPlotting = numpy.hstack([tempLeft, numpy.copy(Tvector), tempRight]) 186 | 187 | #assemble analytical solution for comparison 188 | xAnalytical = numpy.linspace(0, barLength, 100) 189 | 190 | tempAnalytical = (tempLeft + ((tempRight-tempLeft)*(xAnalytical/barLength)) + 191 | (heatSourcePerVol/(2*cond))*xAnalytical*(barLength*numpy.ones(len(xAnalytical)) - xAnalytical)) 192 | 193 | #Configure the plot to look how you want 194 | tickPad = 8 195 | tickPad2 = 16 196 | labelPadY = 1 197 | labelPadX = 2 198 | boxPad = 5 199 | darkBlue = (0.0,0.129,0.2784) 200 | darkRed = (0.7176, 0.0705, 0.207) 201 | 202 | 203 | plt.rc('font', family='serif') 204 | plt.rcParams["figure.figsize"] = (6.2,4.2) 205 | plt.rcParams['axes.linewidth'] = 2 206 | 207 | fig1 = plt.figure() 208 | ax = fig1.add_subplot() 209 | fig1.tight_layout(pad=boxPad) 210 | 211 | ax.plot(xPlotting , tempPlotting, 'bo',linewidth = 2, label='CFD', color=darkRed) 212 | ax.plot(xAnalytical, tempAnalytical, 'k--',linewidth = 2, label = 'Analytical', color=darkBlue) 213 | 214 | plt.xlabel(r'$x$ [m]', fontsize=14, labelpad = labelPadX) 215 | plt.ylabel(r'$T$ [$^{\circ}$C]', fontsize=14, labelpad = labelPadY) 216 | 217 | plt.yticks(fontsize = 14) 218 | plt.xticks(fontsize = 14) 219 | plt.xlim([xFace[0], xFace[-1]]) 220 | leg = plt.legend(fontsize = 14, loc='best', edgecolor = 'r') 221 | leg.get_frame().set_linewidth(2) 222 | plt.show() 223 | -------------------------------------------------------------------------------- /FVM_1D_Diffusion_Equation_Stadard_Wall_Function.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | print("\n") 5 | print("Finite Volume Method\n") 6 | print("Standard Wall Function Approach\n") 7 | print("Solving 1D Heat Diffusion Equation with Dirichlet BC\n") 8 | print("Discretization for Diffusion Term: Central Difference Scheme\n") 9 | 10 | cond = 100 11 | print("Conductivity of the Material:",cond,'W/m-K') 12 | 13 | area = 0.1 14 | print("Cross Section Area of Rod:",area,'m2') 15 | 16 | barLength = 5 17 | print("\nLength of the rod:",barLength,'m') 18 | 19 | nCells = int(input('Enter the number of Cells for Meshing the Rod: ')) 20 | 21 | heatfluxLeftEnd = 100 22 | print("Heat Flux at the Left End of the Rod:",heatfluxLeftEnd,'C/m') 23 | 24 | TRightEnd = 200 25 | print("Temperature at the Right End of the Rod:",TRightEnd,'C') 26 | 27 | heatSourcePerVol = 1000 28 | print("Heat Source in the Rod:",heatSourcePerVol,'W/m3') 29 | print("\n") 30 | 31 | density = 8000 32 | print("Density of the Rod:",density,'Kg/m3') 33 | 34 | cp = 500 35 | print("Specific Heat Capacity of the Rod:",density,'J/kg-C') 36 | 37 | yPlus = int(input('Enter the value of Target Y+: ')) 38 | 39 | Pr = 0.71 40 | 41 | lineSingle = '------------------------------------------------' 42 | lineDouble = '================================================' 43 | 44 | print ('Creating Mesh') 45 | print(lineSingle) 46 | 47 | xFaces = np.linspace(0, barLength, nCells+1) 48 | xCentroid = 0.5*(xFaces[1:] + xFaces[0:-1]) 49 | dCentroid = xCentroid[1:] - xCentroid [0:-1] 50 | dLeft = 2*(xCentroid[0] - xFaces[0]) 51 | dRight = 2*(xFaces[-1] - xCentroid[-1]) 52 | 53 | dCentroids = np.hstack([dLeft, dCentroid, dRight]) 54 | dCentroidsLeft = dCentroids[0:-1] 55 | dCentroidsRight = dCentroids[1:] 56 | 57 | areaLeftFaces = area*np.ones(nCells) 58 | areaRightFaces = area*np.ones(nCells) 59 | 60 | cellLength = xFaces[1:] -xFaces[0:-1] 61 | cellVolume = cellLength*area 62 | 63 | print ('Computing Wall Function') 64 | print(lineSingle) 65 | 66 | Prt = 0.85 67 | 68 | E = 9.7983 69 | kappa = 0.4187 70 | 71 | P_Pr = Pr/Prt 72 | P = 9.24*(np.power(P_Pr, 0.75)-1)*(1 + 0.28*np.exp(-0.007*P_Pr)) 73 | 74 | 75 | yPlusL = 11.0 76 | for i in range(10): 77 | f = ((Pr*yPlusL) - (Prt*(np.log(E*yPlusL)/kappa + P))) 78 | df = Pr - (Prt/(kappa*yPlusL)) 79 | yPlusLNew = yPlusL - f/df 80 | if (np.abs(yPlusLNew - yPlusL) < 1e-6): 81 | break 82 | else: 83 | yPlusL = yPlusLNew 84 | 85 | alpha = cond/(density*cp) 86 | 87 | if yPlus < yPlusL: 88 | alphaWall = alpha 89 | else: 90 | alphaWall = alpha*((Pr*yPlus)/(Prt*(((1/kappa)*(np.log(E*yPlus))+P)))) 91 | 92 | 93 | 94 | print('Wall Function: Summmary') 95 | print(lineSingle) 96 | print('Pr = %6.3f'%Pr) 97 | print('Prt = %6.3f'%Prt) 98 | print('P = %5.3f'% P) 99 | print('y+ = %5.3f'%yPlus) 100 | print('y+_L = %5.3f'%yPlusL) 101 | print('alphaWall/alpha = %6.3f'%(alphaWall/alpha)) 102 | print(lineSingle) 103 | 104 | print (' Assigning Material Properties') 105 | print(lineSingle) 106 | 107 | conductivityFaces = cond*np.ones(nCells+1) 108 | 109 | kWall = alphaWall*density*cp 110 | conductivityFaces[-1] = kWall 111 | 112 | conductivityLeftFaces = conductivityFaces[0:-1] 113 | conductivityRightFaces = conductivityFaces[1:] 114 | 115 | print (' Calculating Matrix Coefficients') 116 | print(lineSingle) 117 | 118 | DA_LeftFaces = np.divide( 119 | np.multiply(conductivityLeftFaces, areaLeftFaces), dCentroidsLeft) 120 | DA_RightFaces = np.divide( 121 | np.multiply(conductivityRightFaces, areaRightFaces),dCentroidsRight) 122 | 123 | 124 | Su = heatSourcePerVol*cellVolume 125 | 126 | Su[0] = Su[0] - heatfluxLeftEnd*area 127 | Su[-1] = Su[-1] + TRightEnd*(2*np.copy(DA_RightFaces[-1])) 128 | 129 | Sp = np.zeros(nCells) 130 | Sp[0] = 0 131 | Sp[-1] = -2*np.copy(DA_RightFaces[-1]) 132 | 133 | aL = np.copy(DA_LeftFaces) 134 | aR = np.copy(DA_RightFaces) 135 | 136 | aL[0] = 0 137 | aR[-1] = 0 138 | 139 | aP = np.around(np.copy(aL) + np.copy(aR) - np.copy(Sp),decimals = 2) 140 | 141 | print(' Assembling Matrices') 142 | print(lineSingle) 143 | 144 | Amatrix = np.zeros([nCells, nCells]) 145 | BVector = np.zeros(nCells) 146 | 147 | for i in range(nCells): 148 | 149 | if i == 0: 150 | Amatrix[i,i] = aP[i] 151 | Amatrix[i,i+1] = -aR[i] 152 | 153 | if i == nCells-1: 154 | Amatrix[i,i] = aP[i] 155 | Amatrix[i,i-1] = -aL[i] 156 | 157 | else: 158 | Amatrix[i,i+1] = -aR[i] 159 | Amatrix[i,i] = aP[i] 160 | Amatrix[i,i-1] = -aL[i] 161 | 162 | BVector[i] = np.around(Su[i],decimals = 2) 163 | 164 | 165 | 166 | print (' Summary: Set Up') 167 | print(lineSingle) 168 | print ('Cell | aL | aR | ap | Sp | Su ') 169 | print(lineSingle) 170 | for i in range(nCells): 171 | print('%4i %5.1f %5.1f %5.1f %5.1f %8.1f ' 172 | % (i+1, aL[i], aR[i], aP[i], Sp[i], Su[i])) 173 | print(lineSingle) 174 | np.set_printoptions(linewidth=np.inf) 175 | print ('A matrix:') 176 | print(lineSingle) 177 | print(Amatrix) 178 | print('B vector') 179 | print(lineSingle) 180 | print(BVector) 181 | print(lineSingle) 182 | 183 | 184 | print (' Solving ...') 185 | print(lineSingle) 186 | 187 | # Use the built-in python solution module 188 | Tvector = np.around(np.linalg.solve(Amatrix, BVector),decimals = 2) 189 | 190 | print (' Equations Solved') 191 | print(lineSingle) 192 | 193 | 194 | 195 | print (' Solution: Temperature Vector') 196 | print(lineSingle) 197 | print(Tvector) 198 | print(lineSingle) 199 | 200 | print (' Calculating Heat Fluxes ...') 201 | print(lineSingle) 202 | 203 | tempLeft = (Tvector[0] - (heatfluxLeftEnd*area)/(2*np.copy(DA_LeftFaces[0]))) 204 | 205 | temperatureStack = np.hstack([tempLeft, np.copy(Tvector), TRightEnd]) 206 | 207 | temperatureDifferenceLeft = temperatureStack[1:-1] - temperatureStack[0:-2] 208 | temperatureDifferenceRight = temperatureStack[2:] - temperatureStack[1:-1] 209 | 210 | normalsLeft = -1.0*np.ones(nCells) 211 | normalsRight = np.ones(nCells) 212 | 213 | heatFluxLeft = -1*np.prod([normalsLeft,temperatureDifferenceLeft,DA_LeftFaces],0) 214 | heatFluxRight = -1*np.prod([normalsRight,temperatureDifferenceRight,DA_RightFaces],0) 215 | 216 | heatFluxLeft[0] *= 2.0 217 | heatFluxRight[-1] *= 2.0 218 | 219 | heatSource = heatSourcePerVol*cellVolume*np.ones(nCells) 220 | heatBalanceError = heatSource - heatFluxLeft - heatFluxRight 221 | 222 | 223 | print(' Heat Fluxes') 224 | print(lineSingle) 225 | print ('Cell | QL | QR | SV | Error') 226 | print(lineSingle) 227 | for i in range(nCells): 228 | print ('%4i %7.1f %7.1f %7.1f %7.1f' % ( 229 | i+1, heatFluxLeft[i], heatFluxRight[i], 230 | heatSource[i], heatBalanceError[i])) 231 | print(lineSingle) 232 | 233 | 234 | 235 | print (' Plotting ...') 236 | print (lineSingle) 237 | 238 | xPlotting = np.hstack([xFaces[0], np.copy(xCentroid), xFaces[-1]]) 239 | 240 | fontSize = 11 241 | fontSizeLegend = 11 242 | lineWidth = 1.5 243 | tickPad = 8 244 | tickPad2 = 16 245 | labelPadY = 3 246 | labelPadX = 2 247 | boxPad = 2 248 | tickLength = 4 249 | markerSize = 4 250 | 251 | lightBlue = '#bfc8d1' 252 | shadeBlue = '#8091a4' 253 | darkBlue = '#002147' 254 | 255 | 256 | plt.rc('font', family='serif') 257 | plt.rcParams['axes.linewidth'] = 1.5 258 | plt.rcParams["figure.figsize"] = (3.1,2.5) 259 | 260 | fig1 = plt.figure(1) 261 | ax = fig1.add_subplot(111) 262 | fig1.tight_layout(pad=boxPad) 263 | ax.plot(xPlotting, temperatureStack, 'b-o',markersize=markerSize,linewidth = 1.5, label='CFD', color=darkBlue) 264 | plt.xlabel(r'$x$ [m]', fontsize=fontSize, labelpad = labelPadX) 265 | plt.ylabel(r'$T$ [$^{\circ}$C]', fontsize=fontSize, labelpad = labelPadY) 266 | plt.title('Temperature Distribution Along the Bar') 267 | plt.yticks(fontsize = fontSize) 268 | plt.xticks(np.linspace(xFaces[0], xFaces[-1], int(barLength)+1), fontsize = fontSize) 269 | plt.xlim([xFaces[0], xFaces[-1]]) 270 | ax.tick_params(which = 'both', direction='in', length=tickLength,width=1.5, gridOn = False, pad=tickPad, color=darkBlue) 271 | ax.yaxis.set_ticks_position('both') 272 | ax.xaxis.set_ticks_position('both') 273 | ax.spines['bottom'].set_color(darkBlue) 274 | ax.spines['top'].set_color(darkBlue) 275 | ax.spines['right'].set_color(darkBlue) 276 | ax.spines['left'].set_color(darkBlue) 277 | 278 | 279 | if yPlus < 11.0: 280 | print("\n!!!!!!!!! ----- NOTE -----!!!!!!!!!") 281 | print("\nTemperature Gradient is resolved as y+ is less than 11\n") 282 | else: 283 | print("\n!!!!!!!!! ----- NOTE -----!!!!!!!!!") 284 | print("\nTemperature Gradient is not resolved as y+ is more than < 11") 285 | print("Heat Flux is corrected by using Standard Wall Function.\n") 286 | 287 | plt.show() 288 | -------------------------------------------------------------------------------- /FVM_1D_Diffusion_Neumann_BC.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | print("\n") 5 | print("Finite Volume Method\n") 6 | print("Solving 1D Heat Diffusion Equation with Neumann Boundary Condition\n") 7 | print("Discretization for Diffusion Term: Central Difference Scheme\n") 8 | 9 | cond = 100 10 | print("Conductivity of the Material:",cond,'W/m-K') 11 | 12 | area = 0.1 13 | print("Cross Section Area of Rod:",area,'m2') 14 | 15 | barLength = 5 16 | print("\nLength of the rod:",barLength,'m') 17 | 18 | heatfluxLeftbc = 200 19 | print("Heat Flux at the Left End of the Rod:",heatfluxLeftbc,'C/m') 20 | 21 | tempRight = 200 22 | print("Temperature at the Right End of the Rod:",tempRight,'C') 23 | 24 | heatSourcePerVol = 1000 25 | print("Heat Source in the Rod:",heatSourcePerVol,'W/m3') 26 | print("\n") 27 | 28 | nCell = int(input('Enter the number of Cells for Meshing the Rod: ')) #Number of Cells 29 | 30 | lineSingle = '------------------------------------------------' 31 | lineDouble = '================================================' 32 | 33 | print('Creating Mesh') 34 | print(lineSingle) 35 | 36 | #cell coordinates 37 | xFace = np.linspace(0, barLength, nCell+1) 38 | 39 | #cell centroids 40 | xCentroid = 0.5*(xFace[1:] + xFace[0:-1]) 41 | 42 | #cell length 43 | cellLength = xFace[1:] - xFace[0:-1] 44 | 45 | #distance between cell centroids 46 | dCentroid = xCentroid[1:] - xCentroid[0:-1] 47 | 48 | # For the boundary cell on the left, the distance is double the distance 49 | # from the cell centroid to the boundary face 50 | dLeft = 2*(xCentroid[0] - xFace[0]) 51 | 52 | # For the boundary cell on the right, the distance is double the distance 53 | #from the cell centroid to the boundary cell face 54 | dRight = 2*(xFace[-1] - xCentroid[-1]) 55 | 56 | # Append these to the vector of distances 57 | dCentroid = np.hstack([dLeft, dCentroid, dRight]) 58 | dCentroidLeft = dCentroid[0:-1] 59 | dCentroidRight = dCentroid[1:] 60 | 61 | #Area of cell Faces 62 | areaLeftFaces = area*np.ones(nCell) 63 | areaRightFaces = area*np.ones(nCell) 64 | 65 | #cellvolume 66 | cellVolume = cellLength*area 67 | 68 | print('Assigning Material Properties') 69 | print(lineSingle) 70 | 71 | conductivityFaces = cond*np.ones(nCell+1) 72 | conductivityLeftFaces = conductivityFaces[0:-1] 73 | conductivityRightFaces = conductivityFaces[1:] 74 | 75 | print ('Calculating Matrix Coefficients') 76 | print(lineSingle) 77 | 78 | #diffusive flux per unit area 79 | DA_LeftFaces = np.divide(np.multiply(conductivityLeftFaces,areaLeftFaces),dCentroidLeft) 80 | DA_RightFaces= np.divide(np.multiply(conductivityRightFaces,areaRightFaces),dCentroidRight) 81 | 82 | #souce term Su 83 | Su = heatSourcePerVol*cellVolume 84 | Su[0] = Su[0] - heatfluxLeftbc*area 85 | Su[-1] = Su[-1] + 2*tempRight*np.copy(DA_RightFaces[-1]) 86 | 87 | #source term Sp 88 | Sp = np.zeros(nCell) 89 | Sp[0] = 0 90 | Sp[-1] = -2*np.copy(DA_RightFaces[-1]) 91 | 92 | #left coefficient aL 93 | aL = np.copy(DA_LeftFaces) 94 | 95 | #right coefficient aR 96 | aR = np.copy(DA_RightFaces) 97 | 98 | aL[0] = 0 99 | aR[-1] = 0 100 | 101 | #central coeff Ap 102 | aP = np.copy(aL) + np.copy(aR) - np.copy(Sp) 103 | 104 | print ('Assembling Matrices') 105 | print(lineSingle) 106 | 107 | # creat empty matrix A & empty vector B 108 | 109 | Amatrix = np.zeros([nCell, nCell]) 110 | BVector = np.zeros(nCell) 111 | 112 | for i in range(nCell): 113 | 114 | if i == 0: 115 | Amatrix[i,i] = aP[i] 116 | Amatrix[i,i+1] = -aR[i] 117 | 118 | elif i == nCell-1: 119 | Amatrix[i,i-1] = -aL[i] 120 | Amatrix[i,i] = aP[i] 121 | 122 | else: 123 | Amatrix[i,i-1] = -aL[i] 124 | Amatrix[i,i] = aP[i] 125 | Amatrix[i,i+1] = -aR[i] 126 | 127 | BVector[i] = Su[i] 128 | 129 | 130 | print ('Summary: Set Up') 131 | print(lineSingle) 132 | print ('Cell | aL | aR | ap | Sp | Su ') 133 | print(lineSingle) 134 | for i in range(nCell): 135 | print ('%4i %5.1f %5.1f %5.1f %5.1f %7.1f ' % ( 136 | i+1, aL[i], aR[i], aP[i], Sp[i], Su[i])) 137 | print(lineSingle) 138 | np.set_printoptions(linewidth=np.inf) 139 | print ('A matrix:') 140 | print(lineSingle) 141 | print(Amatrix) 142 | print ('B vector') 143 | print(lineSingle) 144 | print(BVector) 145 | print(lineSingle) 146 | 147 | print ('Solving ...') 148 | print(lineSingle) 149 | 150 | Tvector = np.linalg.solve(Amatrix, BVector) 151 | 152 | print ('Equations Solved') 153 | print(lineSingle) 154 | 155 | 156 | 157 | print('Solution: Temperature Vector') 158 | print(lineSingle) 159 | Tvector = np.around(Tvector, decimals = 2) 160 | print(Tvector) 161 | print(lineSingle) 162 | 163 | tempLeft = (Tvector[0] - (heatfluxLeftbc*area)/(2*np.copy(DA_LeftFaces[0]))) 164 | 165 | print('Left Boudnary Temperature:') 166 | print(lineSingle) 167 | print(tempLeft) 168 | 169 | temperatureStack = np.hstack([tempLeft, np.copy(Tvector), tempRight]) 170 | 171 | temperatureDifferenceLeft = temperatureStack[1:-1] - temperatureStack[0:-2] 172 | temperatureDifferenceRight = temperatureStack[2:] - temperatureStack[1:-1] 173 | 174 | normalLeft = -1*np.ones(nCell) 175 | normalRight = 1*np.ones(nCell) 176 | 177 | heatfluxLeft = -1*np.prod([normalLeft, temperatureDifferenceLeft, DA_LeftFaces],0) 178 | heatfluxRight = -1*np.prod([normalRight, temperatureDifferenceRight, DA_RightFaces],0) 179 | 180 | heatfluxLeft[0] *= 2.0 181 | heatfluxRight[-1] *= 2.0 182 | 183 | heatSource = heatSourcePerVol*cellVolume 184 | heatBalanceError = heatSource - heatfluxLeft - heatfluxRight 185 | 186 | 187 | print ('\nHeat Balance:') 188 | print(lineSingle) 189 | print ('Cell | QL | QR | SV | Error') 190 | print(lineSingle) 191 | for i in range(nCell): 192 | print('%4i %7.1f %7.1f %7.1f %7.1f' %(i+1, heatfluxLeft[i], heatfluxRight[i], 193 | heatSource[i], heatBalanceError[i])) 194 | print(lineSingle) 195 | 196 | 197 | 198 | print (' Plotting ...') 199 | print(lineSingle) 200 | 201 | xPlotting = np.hstack([xFace[0], np.copy(xCentroid), xFace[-1]]) 202 | 203 | xAnalytical = np.linspace(0, barLength, 100) 204 | temperatureAnalytical = ((heatSourcePerVol/(2.0*cond)) 205 | *(barLength*barLength*np.ones(len(xAnalytical)) 206 | - np.square(xAnalytical)) 207 | + (heatfluxLeftbc/cond)*(xAnalytical 208 | - barLength*np.ones(len(xAnalytical))) 209 | + tempRight) 210 | 211 | fontSize = 14 212 | fontSizeLegend = 14 213 | lineWidth = 2.0 214 | tickPad = 8 215 | tickPad2 = 16 216 | labelPadY = 1 217 | labelPadX = 2 218 | boxPad = 5 219 | darkBlue = (0.0,0.129,0.2784) 220 | darkRed = (0.7176, 0.0705, 0.207) 221 | 222 | 223 | plt.rc('font', family='serif') 224 | plt.rcParams["figure.figsize"] = (6.2,4.2) 225 | plt.rcParams['axes.linewidth'] = lineWidth 226 | 227 | fig1 = plt.figure() 228 | ax = fig1.add_subplot() 229 | fig1.tight_layout(pad=boxPad) 230 | ax.plot(xPlotting , temperatureStack, 'bo',linewidth = lineWidth, label='CFD', color=darkRed) 231 | ax.plot(xAnalytical, temperatureAnalytical, 'k--',linewidth = lineWidth, label = 'Analytical', color=darkBlue) 232 | plt.xlabel(r'$x$ [m]', fontsize=fontSize, labelpad = labelPadX) 233 | plt.ylabel(r'$T$ [$^{\circ}$ C]', fontsize=fontSize, labelpad = labelPadY) 234 | plt.title('Temperature Distribution Along the Bar') 235 | plt.yticks(fontsize = fontSize) 236 | plt.xticks(fontsize = fontSize) 237 | plt.xlim([xFace[0], xFace[-1]]) 238 | leg = plt.legend(fontsize = fontSizeLegend, loc='best', edgecolor = 'r') 239 | leg.get_frame().set_linewidth(lineWidth) 240 | ax.tick_params(which = 'both', direction='in', length=6,width=lineWidth, gridOn = False) 241 | ax.yaxis.set_ticks_position('both') 242 | ax.xaxis.set_ticks_position('both') 243 | ax.tick_params(pad=tickPad) 244 | plt.show() 245 | -------------------------------------------------------------------------------- /FVM_2D_Diffusion.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | import matplotlib.cm as cm 4 | 5 | print("\n") 6 | print("Finite Volume Method\n") 7 | print("Solving 2D Heat Diffusion Equation with Dirichlet Boundary Condition\n") 8 | print("Discretization for Diffusion Term: Central Difference Scheme\n") 9 | 10 | conductivity = 100 11 | print("Conductivity of the Material:",conductivity,'W/m-K') 12 | 13 | thickness = 0.1 14 | print("Thickness of the Plate:",thickness ,'m2') 15 | 16 | plateLength = 4 17 | print("Length of the Plate:",plateLength ,'m2') 18 | 19 | plateWidth = 4 20 | print("Width of the Plate:",plateWidth ,'m2') 21 | 22 | tempLeft = 100 23 | tempBottom = 150 24 | tempRight = 200 25 | tempTop = 250 26 | print("Temperature at the Left End of the Rod:",tempLeft,'C') 27 | print("Temperature at the Bottom End of the Rod:",tempBottom,'C') 28 | print("Temperature at the Right End of the Rod:",tempRight,'C') 29 | print("Temperature at the Top End of the Rod:",tempTop,'C') 30 | 31 | heatSourcePerVol = 1000 32 | print("Heat Source in the Rod:",heatSourcePerVol,'W/m3') 33 | print("\n") 34 | 35 | lineSingle = '------------------------------------------------' 36 | lineDouble = '================================================' 37 | 38 | nCellsLength = int(input('Enter the number of Cells along the length for Meshing the Plate: ')) 39 | nCellsWidth = int(input('Enter the number of Cells along the width for Meshing the Plate: ')) 40 | 41 | print(lineDouble) 42 | print('Creating Mesh') 43 | print(lineSingle) 44 | 45 | #Total No. of Cells & Cell Faces 46 | numCells = nCellsLength*nCellsWidth 47 | numFaces = (nCellsLength+1)*(nCellsWidth+1) 48 | 49 | #coordinate of faces(x,y) 50 | 51 | xFacesPattern = np.linspace(0, plateLength, nCellsLength+1) 52 | yFacesPattern = np.linspace(0, plateWidth, nCellsWidth+1) 53 | xFaces = np.tile(xFacesPattern, nCellsWidth+1) 54 | yFaces = np.repeat(yFacesPattern, nCellsLength+1) 55 | 56 | 57 | #coordinate of centroids(x,y) 58 | 59 | xCentroidPattern = 0.5*(xFacesPattern[1:] + xFacesPattern[0:-1]) 60 | yCentroidPattern = 0.5*(yFacesPattern[1:] + yFacesPattern[0:-1]) 61 | xCentroid = np.tile(xCentroidPattern,nCellsWidth+1) 62 | yCentroid = np.repeat(yCentroidPattern,nCellsLength+1) 63 | 64 | 65 | # Distance between the cell centroids and the boundaries 66 | 67 | dLeftBoundary = 2*(xCentroid[0] - xFacesPattern[0]) 68 | dRightBoundary = 2*(xFacesPattern[-1] - xCentroid[-1]) 69 | dTopBoundary = 2*(yCentroid[0] - yFacesPattern[0]) 70 | dBottomBoundary = 2*(yFacesPattern[-1] - yCentroid[-1]) 71 | 72 | 73 | # Assemble the distance vectors 74 | 75 | dLeftPattern = np.hstack([dLeftBoundary, xCentroidPattern[1:] - xCentroidPattern[0:-1]]) 76 | dRightPattern = np.hstack([xCentroidPattern[1:] - xCentroidPattern[0:-1], dRightBoundary]) 77 | dBottomPattern = np.hstack([yCentroidPattern[1:] - yCentroidPattern[0:-1], dBottomBoundary]) 78 | dTopPattern = np.hstack([dTopBoundary, yCentroidPattern[1:] - yCentroidPattern[0:-1]]) 79 | 80 | dLeft = np.tile(dLeftPattern, nCellsWidth) 81 | dRight = np.tile(dRightPattern, nCellsWidth) 82 | dBottom = np.repeat(dBottomPattern, nCellsLength) 83 | dTop = np.repeat(dTopPattern, nCellsLength) 84 | 85 | CellLength = plateLength/nCellsLength 86 | CellWidth = plateWidth/nCellsWidth 87 | CellVolume = CellLength*CellWidth*thickness #cellvolume 88 | 89 | areaX = CellWidth*thickness 90 | areaY = CellLength*thickness 91 | 92 | # Identify the cells which have boundary faces. Give them an ID of 1. 93 | 94 | topBoundaryID = np.hstack([np.ones(nCellsLength), np.tile(np.zeros(nCellsLength), nCellsWidth-1)]) 95 | bottomBoundaryID= np.hstack([np.tile(np.zeros(nCellsLength), nCellsWidth-1), np.ones(nCellsLength)]) 96 | leftBoundaryID = np.tile(np.hstack([1, np.zeros(nCellsLength-1)]), nCellsWidth) 97 | rightBoundaryID = np.tile(np.hstack([np.zeros(nCellsLength-1), 1]), nCellsWidth) 98 | 99 | print(' Calculating Matrix Coefficients') 100 | print(lineSingle) 101 | 102 | #diffusive flux per unit area 103 | DA_Left = np.divide(conductivity*areaX, dLeft) 104 | DA_Right = np.divide(conductivity*areaX, dRight) 105 | DA_Top = np.divide(conductivity*areaY, dTop) 106 | DA_Bottom = np.divide(conductivity*areaY, dBottom) 107 | 108 | Su = CellVolume*np.ones(numCells)*heatSourcePerVol 109 | 110 | # Add the contribution from each of the boundary faces 111 | Su += 2*tempLeft*np.multiply(leftBoundaryID, DA_Left) 112 | Su += 2*tempRight*np.multiply(rightBoundaryID, DA_Right) 113 | Su += 2*tempTop*np.multiply(topBoundaryID, DA_Top) 114 | Su += 2*tempBottom*np.multiply(bottomBoundaryID, DA_Bottom) 115 | 116 | # The source term is zero for interior cells 117 | Sp = np.zeros(numCells) 118 | 119 | # Add the contribution from each of the boundary faces 120 | 121 | Sp += -2*DA_Left*leftBoundaryID 122 | Sp += -2*DA_Right*rightBoundaryID 123 | Sp += -2*DA_Top*topBoundaryID 124 | Sp += -2*DA_Bottom*bottomBoundaryID 125 | 126 | # Only add contributions for interior cells 127 | 128 | aL = np.multiply(DA_Left, 1 - leftBoundaryID) 129 | aR = np.multiply(DA_Right,1 - rightBoundaryID) 130 | aT = np.multiply(DA_Top, 1 - topBoundaryID) 131 | aB = np.multiply(DA_Bottom, 1 - bottomBoundaryID) 132 | 133 | #central coeff Ap 134 | aP = aL + aR + aT + aB - Sp 135 | 136 | print(' Summary: Set Up') 137 | print(lineSingle) 138 | print('Cell | aL | aR | aB | aT | Sp | Su | aP ') 139 | print(lineSingle) 140 | for i in range(numCells): 141 | print('%4i %5.0f %5.0f %5.0f %5.0f %5.0f %7.0f %5.0f' %(i+1, aL[i], aR[i], aB[i], aT[i], Sp[i], Su[i], aP[i])) 142 | print(lineSingle) 143 | 144 | 145 | print(' Assembling Matrices') 146 | print(lineSingle) 147 | 148 | Amatrix = np.zeros([numCells, numCells]) 149 | Bvector = np.zeros(numCells) 150 | 151 | for i in range(numCells): 152 | 153 | Amatrix[i,i] = aP[i] 154 | Bvector[i] = Su[i] 155 | 156 | if leftBoundaryID[i] == 0: 157 | Amatrix[i,i-1] = -aL[i] 158 | 159 | if rightBoundaryID[i] == 0: 160 | Amatrix[i,i+1] = -aR[i] 161 | 162 | if bottomBoundaryID[i] == 0: 163 | Amatrix[i, i+nCellsLength] = -aB[i] 164 | 165 | if topBoundaryID[i] == 0: 166 | Amatrix[i, i-nCellsLength] = -aT[i] 167 | 168 | np.set_printoptions(linewidth=85) 169 | print(Amatrix) 170 | print(lineSingle) 171 | 172 | print('Solving ...') 173 | print(lineSingle) 174 | 175 | Tvector = np.linalg.solve(Amatrix, Bvector) 176 | Tvector = np.around(Tvector, decimals = 3) 177 | 178 | print('Equations Solved') 179 | print(lineSingle) 180 | 181 | Tgrid = Tvector.reshape(nCellsWidth, nCellsLength) 182 | 183 | print ('\nSolution: Temperature Field') 184 | print(lineSingle) 185 | print(Tgrid) 186 | print(lineSingle) 187 | 188 | #Heat Fluxes 189 | # Calculate the temperature differences 190 | # - To do this we need to stack on the boundary temperatures onto the grid 191 | 192 | Tleftrightshift = np.hstack([tempLeft*np.ones([nCellsWidth,1]), Tgrid, 193 | tempRight*np.ones([nCellsWidth,1])]) 194 | Ttopbottomshift = np.vstack([tempTop*np.ones([nCellsLength]), Tgrid, 195 | tempBottom*np.ones([nCellsLength])]) 196 | 197 | # Now we can calculate the temperature differences 198 | 199 | deltaTleft = Tleftrightshift[:,1:-1] - Tleftrightshift[:,0:-2] 200 | deltaTright = Tleftrightshift[:,2:] - Tleftrightshift[:,1:-1] 201 | deltaTtop = Ttopbottomshift[0:-2,:] - Ttopbottomshift[1:-1,:] 202 | deltaTbottom = Ttopbottomshift[1:-1,:] - Ttopbottomshift[2:,:] 203 | 204 | # We now need to calculate the diffusive heat flux (DA) on each face 205 | # - Start by reshaping the DA vectors into a grid of the correct size 206 | 207 | DA_left_grid = DA_Left.reshape(nCellsWidth, nCellsLength) 208 | DA_right_grid = DA_Right.reshape(nCellsWidth, nCellsLength) 209 | DA_top_grid = DA_Top.reshape(nCellsWidth, nCellsLength) 210 | DA_bottom_grid = DA_Bottom.reshape(nCellsWidth, nCellsLength) 211 | 212 | # Calculate the boundary face fluxes 213 | 214 | DA_left_boundary = (2*conductivity*areaX/dLeftBoundary)*np.ones([nCellsWidth,1]) 215 | DA_right_boundary = (2*conductivity*areaX/dRightBoundary)*np.ones([nCellsWidth,1]) 216 | DA_top_boundary = (2*conductivity*areaY/dTopBoundary)*np.ones([nCellsLength]) 217 | DA_bottom_boundary = (2*conductivity*areaY/dBottomBoundary)*np.ones([nCellsLength]) 218 | 219 | # Now stack on the boundary face fluxes to the grid 220 | 221 | DA_left_shift = np.hstack([DA_left_boundary, DA_left_grid[:,1:]]) 222 | DA_right_shift = np.hstack([DA_right_grid[:,:-1], DA_right_boundary]) 223 | DA_top_shift = np.vstack([DA_top_boundary, DA_top_grid[1:,:]]) 224 | DA_bottom_shift = np.vstack([DA_bottom_grid[0:-1,:],DA_bottom_boundary]) 225 | 226 | #unit normals 227 | 228 | normalsLeftGrid = -1*np.ones([nCellsWidth, nCellsLength]) 229 | normalsRightGrid = 1*np.ones([nCellsWidth, nCellsLength]) 230 | normalsBottomGrid = -1*np.ones([nCellsWidth, nCellsLength]) 231 | normalsTopGrid = 1*np.ones([nCellsWidth, nCellsLength]) 232 | 233 | #calculating heat flux across faces 234 | 235 | heatFluxLeft = -np.multiply(np.multiply(DA_left_shift,deltaTleft),normalsLeftGrid) 236 | heatFluxRight = -np.multiply(DA_right_shift,deltaTright,normalsRightGrid) 237 | heatFluxTop = -np.multiply(DA_top_shift,deltaTtop,normalsTopGrid) 238 | heatFluxBottom = -np.multiply(np.multiply(DA_bottom_shift,deltaTbottom),normalsBottomGrid) 239 | 240 | #calculating vol heat generation in each cell 241 | 242 | sourceVol = heatSourcePerVol*CellVolume*np.ones([nCellsWidth, nCellsLength]) 243 | 244 | # Calculate the error in the heat flux balance in each cell 245 | 246 | error = (sourceVol - heatFluxLeft - heatFluxRight - heatFluxTop - heatFluxBottom) 247 | 248 | heatFluxLeftVector = heatFluxLeft.flatten() 249 | heatFluxRightVector = heatFluxRight.flatten() 250 | heatFluxTopVector = heatFluxTop.flatten() 251 | heatFluxBottomVector = heatFluxBottom.flatten() 252 | sourceVolVector = sourceVol.flatten() 253 | errorVector = error.flatten() 254 | 255 | 256 | 257 | print('\nHeat Balance:') 258 | print(lineSingle) 259 | print('Cell | QL | QR | QT | QB | SV | Err') 260 | print(lineSingle) 261 | for i in range(numCells): 262 | print('%4i %7.1f %7.1f %7.1f %7.1f %7.1f %7.1f' % (i+1, heatFluxLeftVector[i], 263 | heatFluxRightVector[i], heatFluxTopVector[i], 264 | heatFluxBottomVector[i], sourceVolVector[i], errorVector[i])) 265 | print(lineSingle) 266 | 267 | #Sum the heat fluxes across the boundary faces to give the total heat flux 268 | #across each boundary 269 | 270 | heatFluxLeftBoundaryTotal = np.sum(np.multiply(leftBoundaryID, heatFluxLeftVector)) 271 | heatFluxRightBoundaryTotal = np.sum(np.multiply(rightBoundaryID, heatFluxRightVector)) 272 | heatFluxBottomBoundaryTotal = np.sum(np.multiply(bottomBoundaryID, heatFluxBottomVector)) 273 | heatFluxTopBoundaryTotal = np.sum(np.multiply(topBoundaryID, heatFluxTopVector)) 274 | 275 | heatFluxBoundaryTotal = (heatFluxLeftBoundaryTotal + heatFluxRightBoundaryTotal 276 | + heatFluxBottomBoundaryTotal + heatFluxTopBoundaryTotal) 277 | heatGenerationTotal = np.sum(sourceVolVector) 278 | 279 | print ('Boundary Heat Flux') 280 | print(lineSingle) 281 | print('Left : %5.1f [W]'%(heatFluxLeftBoundaryTotal)) 282 | print('Right : %6.1f [W]'% heatFluxRightBoundaryTotal) 283 | print('Bottom : %6.1f [W]'% heatFluxBottomBoundaryTotal) 284 | print('Top : %6.1f [W]'% heatFluxTopBoundaryTotal) 285 | print('Total : %7.1f [W]'% heatFluxBoundaryTotal) 286 | print(lineSingle) 287 | print('Generated : %7.1f [W]'% heatGenerationTotal) 288 | print(lineSingle) 289 | print('Error : %7.1f [W]'% (heatFluxBoundaryTotal - heatGenerationTotal)) 290 | print(lineSingle) 291 | 292 | # Interpolate the solution on the interior nodes from the CFD solution 293 | 294 | temperatureTopLeftCorner = 0.5*(tempTop + tempLeft) 295 | temperatureTopRightCorner = 0.5*(tempRight + tempTop) 296 | temperatureBottomLeftCorner = 0.5*(tempBottom + tempLeft) 297 | temperatureBottomRightCorner = 0.5*(tempRight + tempBottom) 298 | 299 | # Interpolate the solution on the interior nodes from the CFD solution 300 | 301 | Tleftrightnodes = 0.5*(Tgrid[:,1:]+Tgrid[:,:-1]) 302 | Tinternalnodes = 0.5*(Tleftrightnodes[1:,:] + Tleftrightnodes[:-1,:]) 303 | 304 | 305 | # Assemble the temperatures on all the boundary nodes 306 | 307 | temperatureTopVector = np.hstack([temperatureTopLeftCorner, 308 | tempTop*np.ones(nCellsLength-1),temperatureTopRightCorner]) 309 | 310 | temperatureBottomVector = np.hstack([temperatureBottomLeftCorner, 311 | tempBottom*np.ones(nCellsLength-1),temperatureBottomRightCorner]) 312 | 313 | temperatureLeftVector = tempLeft*np.ones([nCellsWidth-1,1]) 314 | temperatureRightVector = tempRight*np.ones([nCellsWidth-1,1]) 315 | 316 | 317 | Tnodes = np.vstack([temperatureTopVector, np.hstack([temperatureLeftVector, 318 | Tinternalnodes,temperatureRightVector]), temperatureBottomVector]) 319 | Tnodes = np.around(Tnodes, decimals = 2) 320 | 321 | print ('Solution: Temperature Field on nodes') 322 | print(lineSingle) 323 | print(Tnodes) 324 | print(lineSingle) 325 | 326 | xNodes = xFaces.reshape([nCellsWidth+1, nCellsLength+1]) 327 | yNodes = np.flipud(yFaces.reshape([nCellsWidth+1, nCellsLength+1])) 328 | 329 | #Plot the solution 330 | 331 | # Plot the data if desired 332 | 333 | print ('Plotting ...') 334 | print(lineSingle) 335 | 336 | tickPad = 8 337 | tickPad2 = 16 338 | labelPadY = 3 339 | labelPadX = 2 340 | boxPad = 2 341 | tickLength = 4 342 | markerSize = 4 343 | 344 | # Colours - Can use rgb or html 345 | lightBlue = '#bfc8d1' 346 | shadeBlue = '#8091a4' 347 | darkBlue = '#002147' 348 | 349 | # Use 'CMU sans-serif' font in the plots. 350 | plt.rc('font', family='serif') 351 | plt.rcParams['axes.linewidth'] = 1.5 352 | plt.rcParams["figure.figsize"] = (3.1,2.5) 353 | 354 | fig1 = plt.figure(1) 355 | ax = fig1.add_subplot(111) 356 | fig1.tight_layout(pad=boxPad) 357 | cmap_reversed = cm.get_cmap('autumn_r') 358 | CS = ax.contourf(xNodes, yNodes, Tnodes, cmap=cmap_reversed) 359 | CS2 = ax.contour(CS, colors='k', linewidth=1.5) 360 | ax.set_xlabel(r'$x$ [m]', fontsize=11, labelpad = labelPadX) 361 | ax.set_ylabel(r'$y$ [m]', fontsize=11, labelpad = labelPadY) 362 | ax.set_title('Temperature Contour') 363 | plt.yticks(np.arange(0,plateLength+1,1), fontsize = 11) 364 | plt.xticks(np.arange(0,plateWidth+1,1), fontsize = 11) 365 | cbar = fig1.colorbar(CS) 366 | cbar.ax.set_ylabel('Temperature [C]', fontsize=11, labelpad = labelPadX) 367 | cbar.ax.tick_params(size = 0, width = 1.5) 368 | cbar.add_lines(CS2) 369 | cbar.ax.tick_params(labelsize=11) 370 | ax.tick_params(which = 'both', direction='in', length=6,width=1.5, gridOn = False, pad=tickPad) 371 | ax.yaxis.set_ticks_position('both') 372 | ax.xaxis.set_ticks_position('both') 373 | plt.show() 374 | -------------------------------------------------------------------------------- /LBM_solver_flow_past_2Dcylinder.py: -------------------------------------------------------------------------------- 1 | #2D Flow around cylinder 2 | 3 | #Lattice Boltzmann BKG Method 4 | 5 | # 6 | # 7 | 8 | from numpy import * 9 | import matplotlib.pyplot as plt 10 | from matplotlib import cm 11 | 12 | lineSingle = '------------------------------------------------' 13 | lineDouble = '================================================' 14 | 15 | print("\n") 16 | print(lineDouble) 17 | print("Lattice Boltzmann Method\n") 18 | print("Solving 2D Heat flow around square/circular cylinder\n") 19 | print("BKG Model") 20 | print(lineSingle) 21 | 22 | #flow defination 23 | 24 | iterations = 150000 #total number of time iteration 25 | print("\nNumber of iterations: ",iterations) 26 | 27 | Re = 500 #flow reynolds number 28 | print("Flow Reynolds Number: ",Re,"\n") 29 | 30 | nx, ny = 420, 180 #number of lattice node 31 | ly = ny-1 #height of the domain 32 | 33 | #creating shape of the obstacle: cylinder 34 | 35 | cx, cy = nx//4, ny//2 #cylinder coordinates 36 | 37 | geometry = "" 38 | while not (geometry == 'SQUARE CYLINDER' or geometry == 'CIRCULAR CYLINDER'): 39 | 40 | geometry = input("Select the geometry: SQUARE CYLINDER or CIRCULAR CYLINDER: ").upper() 41 | 42 | def obstacle_cylinder(x,y): 43 | 44 | if geometry == "CIRCULAR CYLINDER": 45 | r = ny//9 #circle radius 46 | return (x-cx)**2 + (y-cy)**2