harishaseebat92/Fluid_Simulation_Classical
0
1import numpy as np
2import matplotlib.pyplot as plt
3from matplotlib.animation import FuncAnimation
4import tempfile
5import gradio as gr
6
7def solve_and_animate_2d(Lx: float,
8 Ly: float,
9 t_max: float,
10 Gamma: float = 0.1,
11 Nx: int = 50,
12 Ny: int = 50,
13 initial: str = "gaussian",
14 bc: str = "dirichlet",
15 frame_skip: int = 1):
16 """
17 Solve the 2D heat equation u_t = Gamma*(u_xx + u_yy) and return a GIF animation.
18 Initial conditions: {"gaussian", "random", "sinusoidal", "step"}
19 Boundary conditions: {"dirichlet", "neumann", "periodic"}
20 """
21 # Spatial grid
22 x = np.linspace(0, Lx, Nx)
23 y = np.linspace(0, Ly, Ny)
24 dx, dy = x[1] - x[0], y[1] - y[0]
25 if dx == 0 or dy == 0:
26 raise ValueError("Nx and Ny must be > 1.")
27
28 # Time stepping for stability
29 dt = 1.0 / (2 * Gamma * (1/dx**2 + 1/dy**2))
30 Nt = int(np.ceil(t_max / dt)) + 1
31 rx, ry = Gamma * dt / dx**2, Gamma * dt / dy**2
32
33 # Initial condition
34 X, Y = np.meshgrid(x, y, indexing='ij')
35 if initial == "gaussian":
36 u = np.exp(-(((X - Lx/2)**2 + (Y - Ly/2)**2) / (2*(Lx/10)**2)))
37 elif initial == "random":
38 u = np.random.rand(Nx, Ny)
39 elif initial == "sinusoidal":
40 kx, ky = 2 * np.pi / Lx, 2 * np.pi / Ly
41 u = np.sin(kx * X) * np.sin(ky * Y)
42 elif initial == "step":
43 u = np.where((X < Lx/2) & (Y < Ly/2), 1.0, 0.0)
44 else:
45 raise ValueError(f"Unknown initial condition: {initial}")
46
47 # Storage for solution
48 U = np.zeros((Nt, Nx, Ny))
49 U[0] = u.copy()
50
51 # Time-stepping loop
52 for n in range(1, Nt):
53 un = u.copy()
54 # Interior update
55 u[1:-1, 1:-1] = (
56 un[1:-1, 1:-1]
57 + rx * (un[2:, 1:-1] - 2 * un[1:-1, 1:-1] + un[:-2, 1:-1])
58 + ry * (un[1:-1, 2:] - 2 * un[1:-1, 1:-1] + un[1:-1, :-2])
59 )
60 # Boundary conditions
61 if bc == "dirichlet":
62 u[0, :] = u[-1, :] = u[:, 0] = u[:, -1] = 0.0
63 elif bc == "neumann":
64 u[0, :] = u[1, :]
65 u[-1, :] = u[-2, :]
66 u[:, 0] = u[:, 1]
67 u[:, -1] = u[:, -2]
68 elif bc == "periodic":
69 u[0, :] = un[-2, :]
70 u[-1, :] = un[1, :]
71 u[:, 0] = un[:, -2]
72 u[:, -1] = un[:, 1]
73 else:
74 raise ValueError(f"Unknown bc: {bc}")
75 U[n] = u.copy()
76
77 # Create animation with Matplotlib
78 fig, ax = plt.subplots()
79 im = ax.imshow(U[0].T, cmap='viridis', origin='lower', extent=[0, Lx, 0, Ly], vmin=U.min(), vmax=U.max())
80 ax.set_title(f"2D Heat Eq — init={initial}, bc={bc}, Gamma={Gamma:.2f}")
81 ax.set_xlabel("x")
82 ax.set_ylabel("y")
83 plt.colorbar(im, ax=ax, label="u")
84
85 # Animation update function
86 def update(frame):
87 im.set_data(U[frame].T)
88 return [im]
89
90 # Subsample frames
91 idx = list(range(0, Nt, frame_skip))
92 if idx[-1] != Nt - 1:
93 idx.append(Nt - 1)
94
95 # Generate animation
96 ani = FuncAnimation(fig, update, frames=idx, blit=True)
97
98 # Save as GIF
99 with tempfile.NamedTemporaryFile(suffix='.gif', delete=False) as tmpfile:
100 ani.save(tmpfile.name, writer='pillow', fps=30)
101 gif_path = tmpfile.name
102
103 plt.close(fig)
104 return gif_path
105
106def gradio_interface(lx, ly, t_max, gamma, nx, ny, initial, bc, frame_skip):
107 nx, ny, frame_skip = int(nx), int(ny), int(frame_skip)
108 return solve_and_animate_2d(
109 Lx=lx, Ly=ly, t_max=t_max, Gamma=gamma, Nx=nx, Ny=ny,
110 initial=initial, bc=bc, frame_skip=frame_skip
111 )
112
113with gr.Blocks(theme=gr.themes.Soft(), title="2D Heat Simulator") as demo:
114 gr.Markdown("# ♨️ 2D Heat Equation Simulator\nAdjust parameters and run the simulation.")
115 with gr.Row():
116 with gr.Column(scale=1):
117 gr.Markdown("## Domain & Grid")
118 lx_slider = gr.Slider(0.1, 5.0, 1.0, 0.1, label="Lx")
119 ly_slider = gr.Slider(0.1, 5.0, 1.0, 0.1, label="Ly")
120 nx_slider = gr.Slider(3, 200, 50, 1, label="Nx")
121 ny_slider = gr.Slider(3, 200, 50, 1, label="Ny")
122
123 gr.Markdown("## Simulation")
124 t_slider = gr.Slider(0.01, 5.0, 0.5, 0.01, label="t_max")
125 gamma_slider = gr.Slider(0.001, 1.0, 0.1, 0.001, label="Gamma")
126
127 gr.Markdown("## Conditions")
128 initial_dropdown = gr.Dropdown(
129 ["gaussian", "random", "sinusoidal", "step"], "gaussian", label="Initial"
130 )
131 bc_dropdown = gr.Dropdown(
132 ["dirichlet", "neumann", "periodic"], "dirichlet", label="Boundary"
133 )
134
135 gr.Markdown("## Animation")
136 frame_skip_slider = gr.Slider(1, 50, 5, 1, label="Frame Skip")
137 run_btn = gr.Button("Run Simulation", variant="primary")
138 with gr.Column(scale=3):
139 plot_output = gr.Image(label="Heatmap Animation")
140 inputs_list = [lx_slider, ly_slider, t_slider, gamma_slider,
141 nx_slider, ny_slider, initial_dropdown, bc_dropdown, frame_skip_slider]
142 run_btn.click(fn=gradio_interface, inputs=inputs_list, outputs=plot_output)
143 gr.Examples(
144 examples=[
145 [1.0, 1.0, 0.5, 0.1, 50, 50, "gaussian", "dirichlet", 5],
146 [2.0, 1.0, 1.0, 0.05, 60, 30, "sinusoidal", "periodic", 10],
147 [1.0, 1.0, 0.2, 0.2, 80, 80, "step", "neumann", 2],
148 ],
149 inputs=inputs_list,
150 outputs=[plot_output],
151 fn=gradio_interface
152 )
153
154if __name__ == "__main__":
155 demo.launch()