harishaseebat92's picture
Rename app.py to app_o.py
75f0e0a verified
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import tempfile
import gradio as gr
def solve_and_animate_2d(Lx: float,
Ly: float,
t_max: float,
Gamma: float = 0.1,
Nx: int = 50,
Ny: int = 50,
initial: str = "gaussian",
bc: str = "dirichlet",
frame_skip: int = 1):
"""
Solve the 2D heat equation u_t = Gamma*(u_xx + u_yy) and return a GIF animation.
Initial conditions: {"gaussian", "random", "sinusoidal", "step"}
Boundary conditions: {"dirichlet", "neumann", "periodic"}
"""
# Spatial grid
x = np.linspace(0, Lx, Nx)
y = np.linspace(0, Ly, Ny)
dx, dy = x[1] - x[0], y[1] - y[0]
if dx == 0 or dy == 0:
raise ValueError("Nx and Ny must be > 1.")
# Time stepping for stability
dt = 1.0 / (2 * Gamma * (1/dx**2 + 1/dy**2))
Nt = int(np.ceil(t_max / dt)) + 1
rx, ry = Gamma * dt / dx**2, Gamma * dt / dy**2
# Initial condition
X, Y = np.meshgrid(x, y, indexing='ij')
if initial == "gaussian":
u = np.exp(-(((X - Lx/2)**2 + (Y - Ly/2)**2) / (2*(Lx/10)**2)))
elif initial == "random":
u = np.random.rand(Nx, Ny)
elif initial == "sinusoidal":
kx, ky = 2 * np.pi / Lx, 2 * np.pi / Ly
u = np.sin(kx * X) * np.sin(ky * Y)
elif initial == "step":
u = np.where((X < Lx/2) & (Y < Ly/2), 1.0, 0.0)
else:
raise ValueError(f"Unknown initial condition: {initial}")
# Storage for solution
U = np.zeros((Nt, Nx, Ny))
U[0] = u.copy()
# Time-stepping loop
for n in range(1, Nt):
un = u.copy()
# Interior update
u[1:-1, 1:-1] = (
un[1:-1, 1:-1]
+ rx * (un[2:, 1:-1] - 2 * un[1:-1, 1:-1] + un[:-2, 1:-1])
+ ry * (un[1:-1, 2:] - 2 * un[1:-1, 1:-1] + un[1:-1, :-2])
)
# Boundary conditions
if bc == "dirichlet":
u[0, :] = u[-1, :] = u[:, 0] = u[:, -1] = 0.0
elif bc == "neumann":
u[0, :] = u[1, :]
u[-1, :] = u[-2, :]
u[:, 0] = u[:, 1]
u[:, -1] = u[:, -2]
elif bc == "periodic":
u[0, :] = un[-2, :]
u[-1, :] = un[1, :]
u[:, 0] = un[:, -2]
u[:, -1] = un[:, 1]
else:
raise ValueError(f"Unknown bc: {bc}")
U[n] = u.copy()
# Create animation with Matplotlib
fig, ax = plt.subplots()
im = ax.imshow(U[0].T, cmap='viridis', origin='lower', extent=[0, Lx, 0, Ly], vmin=U.min(), vmax=U.max())
ax.set_title(f"2D Heat Eq — init={initial}, bc={bc}, Gamma={Gamma:.2f}")
ax.set_xlabel("x")
ax.set_ylabel("y")
plt.colorbar(im, ax=ax, label="u")
# Animation update function
def update(frame):
im.set_data(U[frame].T)
return [im]
# Subsample frames
idx = list(range(0, Nt, frame_skip))
if idx[-1] != Nt - 1:
idx.append(Nt - 1)
# Generate animation
ani = FuncAnimation(fig, update, frames=idx, blit=True)
# Save as GIF
with tempfile.NamedTemporaryFile(suffix='.gif', delete=False) as tmpfile:
ani.save(tmpfile.name, writer='pillow', fps=30)
gif_path = tmpfile.name
plt.close(fig)
return gif_path
def gradio_interface(lx, ly, t_max, gamma, nx, ny, initial, bc, frame_skip):
nx, ny, frame_skip = int(nx), int(ny), int(frame_skip)
return solve_and_animate_2d(
Lx=lx, Ly=ly, t_max=t_max, Gamma=gamma, Nx=nx, Ny=ny,
initial=initial, bc=bc, frame_skip=frame_skip
)
with gr.Blocks(theme=gr.themes.Soft(), title="2D Heat Simulator") as demo:
gr.Markdown("# ♨️ 2D Heat Equation Simulator\nAdjust parameters and run the simulation.")
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("## Domain & Grid")
lx_slider = gr.Slider(0.1, 5.0, 1.0, 0.1, label="Lx")
ly_slider = gr.Slider(0.1, 5.0, 1.0, 0.1, label="Ly")
nx_slider = gr.Slider(3, 200, 50, 1, label="Nx")
ny_slider = gr.Slider(3, 200, 50, 1, label="Ny")
gr.Markdown("## Simulation")
t_slider = gr.Slider(0.01, 5.0, 0.5, 0.01, label="t_max")
gamma_slider = gr.Slider(0.001, 1.0, 0.1, 0.001, label="Gamma")
gr.Markdown("## Conditions")
initial_dropdown = gr.Dropdown(
["gaussian", "random", "sinusoidal", "step"], "gaussian", label="Initial"
)
bc_dropdown = gr.Dropdown(
["dirichlet", "neumann", "periodic"], "dirichlet", label="Boundary"
)
gr.Markdown("## Animation")
frame_skip_slider = gr.Slider(1, 50, 5, 1, label="Frame Skip")
run_btn = gr.Button("Run Simulation", variant="primary")
with gr.Column(scale=3):
plot_output = gr.Image(label="Heatmap Animation")
inputs_list = [lx_slider, ly_slider, t_slider, gamma_slider,
nx_slider, ny_slider, initial_dropdown, bc_dropdown, frame_skip_slider]
run_btn.click(fn=gradio_interface, inputs=inputs_list, outputs=plot_output)
gr.Examples(
examples=[
[1.0, 1.0, 0.5, 0.1, 50, 50, "gaussian", "dirichlet", 5],
[2.0, 1.0, 1.0, 0.05, 60, 30, "sinusoidal", "periodic", 10],
[1.0, 1.0, 0.2, 0.2, 80, 80, "step", "neumann", 2],
],
inputs=inputs_list,
outputs=[plot_output],
fn=gradio_interface
)
if __name__ == "__main__":
demo.launch()