harishaseebat92 commited on
Commit
3184505
·
verified ·
1 Parent(s): 6c6dc22

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +150 -50
app.py CHANGED
@@ -1,26 +1,36 @@
1
- # app.py
2
  import numpy as np
 
 
 
3
  import gradio as gr
 
4
 
5
- # --- Simulation Core (No changes needed here) ---
6
- def solve_2d_heat_equation(Lx, Ly, t_max, Gamma, Nx, Ny, initial, bc):
 
 
 
 
 
 
 
7
  """
8
- Solves the 2D heat equation and returns the data and time step.
9
- (This function is the same as in your original code)
10
  """
11
  # Spatial grid
12
  x = np.linspace(0, Lx, Nx)
13
  y = np.linspace(0, Ly, Ny)
14
  dx, dy = x[1] - x[0], y[1] - y[0]
 
 
15
 
16
  # Time stepping for stability
17
- dt = 0.9 / (2 * Gamma * (1/dx**2 + 1/dy**2))
18
  Nt = int(np.ceil(t_max / dt)) + 1
19
  rx, ry = Gamma * dt / dx**2, Gamma * dt / dy**2
20
 
21
  # Initial condition
22
  X, Y = np.meshgrid(x, y, indexing='ij')
23
- u = np.zeros((Nx, Ny))
24
  if initial == "gaussian":
25
  u = np.exp(-(((X - Lx/2)**2 + (Y - Ly/2)**2) / (2*(Lx/10)**2)))
26
  elif initial == "random":
@@ -30,6 +40,8 @@ def solve_2d_heat_equation(Lx, Ly, t_max, Gamma, Nx, Ny, initial, bc):
30
  u = np.sin(kx * X) * np.sin(ky * Y)
31
  elif initial == "step":
32
  u = np.where((X < Lx/2) & (Y < Ly/2), 1.0, 0.0)
 
 
33
 
34
  # Storage for solution
35
  U = np.zeros((Nt, Nx, Ny))
@@ -38,12 +50,13 @@ def solve_2d_heat_equation(Lx, Ly, t_max, Gamma, Nx, Ny, initial, bc):
38
  # Time-stepping loop
39
  for n in range(1, Nt):
40
  un = u.copy()
 
41
  u[1:-1, 1:-1] = (
42
  un[1:-1, 1:-1]
43
  + rx * (un[2:, 1:-1] - 2 * un[1:-1, 1:-1] + un[:-2, 1:-1])
44
  + ry * (un[1:-1, 2:] - 2 * un[1:-1, 1:-1] + un[1:-1, :-2])
45
  )
46
- # Boundary conditions (simplified for brevity)
47
  if bc == "dirichlet":
48
  u[0, :] = u[-1, :] = u[:, 0] = u[:, -1] = 0.0
49
  elif bc == "neumann":
@@ -51,57 +64,144 @@ def solve_2d_heat_equation(Lx, Ly, t_max, Gamma, Nx, Ny, initial, bc):
51
  u[-1, :] = u[-2, :]
52
  u[:, 0] = u[:, 1]
53
  u[:, -1] = u[:, -2]
 
 
 
 
 
 
 
54
  U[n] = u.copy()
55
-
56
- # Return raw data - convert numpy arrays to lists for JSON compatibility
57
- return U.tolist(), dt
58
 
59
- # --- Gradio API Function ---
60
- def run_simulation_api(lx, ly, t_max, gamma, nx, ny, initial, bc):
 
 
61
  """
62
- API function that runs the simulation and returns data as a dictionary.
63
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  U, dt = solve_2d_heat_equation(
65
- Lx=lx, Ly=ly, t_max=t_max, Gamma=gamma, Nx=int(nx), Ny=int(ny),
66
  initial=initial, bc=bc
67
  )
68
-
69
- # Return data in a format that's easy to use in JavaScript
70
- return {
71
- "simulation_data": U,
72
- "time_step": dt,
73
- "domain": {"Lx": lx, "Ly": ly},
74
- "params": {"initial": initial, "bc": bc, "gamma": gamma}
75
- }
76
-
77
- # --- Gradio Interface (API only) ---
78
- with gr.Blocks(title="2D Heat Simulator API") as demo:
79
- # We define the inputs for the API
80
- lx_slider = gr.Slider(0.1, 5.0, 1.0, label="Lx")
81
- ly_slider = gr.Slider(0.1, 5.0, 1.0, label="Ly")
82
- nx_slider = gr.Slider(3, 200, 50, label="Nx")
83
- ny_slider = gr.Slider(3, 200, 50, label="Ny")
84
- t_slider = gr.Slider(0.01, 5.0, 0.5, label="t_max")
85
- gamma_slider = gr.Slider(0.001, 1.0, 0.1, label="Gamma")
86
- initial_dropdown = gr.Dropdown(["gaussian", "random", "sinusoidal", "step"], value="gaussian", label="Initial")
87
- bc_dropdown = gr.Dropdown(["dirichlet", "neumann"], value="dirichlet", label="Boundary")
88
-
89
- # We only need a JSON output component for the API
90
- output_json = gr.JSON(label="Simulation Output")
91
-
92
- # This is the crucial part: we create a hidden button to host our API endpoint
93
- api_btn = gr.Button("Run Simulation")
94
-
95
- api_btn.click(
96
- fn=run_simulation_api,
97
- inputs=[
98
- lx_slider, ly_slider, t_slider, gamma_slider,
99
- nx_slider, ny_slider, initial_dropdown, bc_dropdown
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  ],
101
- outputs=output_json,
102
- api_name="run_simulation" # This makes it available at /run/run_simulation
 
103
  )
104
 
105
  if __name__ == "__main__":
106
- # Launch the Gradio app
107
  demo.launch()
 
 
1
  import numpy as np
2
+ import matplotlib.pyplot as plt
3
+ from matplotlib.animation import FuncAnimation
4
+ import tempfile
5
  import gradio as gr
6
+ import plotly.graph_objects as go
7
 
8
+ # --- Simulation Core ---
9
+ def solve_2d_heat_equation(Lx: float,
10
+ Ly: float,
11
+ t_max: float,
12
+ Gamma: float = 0.1,
13
+ Nx: int = 50,
14
+ Ny: int = 50,
15
+ initial: str = "gaussian",
16
+ bc: str = "dirichlet"):
17
  """
18
+ Solve the 2D heat equation u_t = Gamma*(u_xx + u_yy) and return the solution array U and time step dt.
 
19
  """
20
  # Spatial grid
21
  x = np.linspace(0, Lx, Nx)
22
  y = np.linspace(0, Ly, Ny)
23
  dx, dy = x[1] - x[0], y[1] - y[0]
24
+ if dx == 0 or dy == 0:
25
+ raise ValueError("Nx and Ny must be > 1.")
26
 
27
  # Time stepping for stability
28
+ dt = 1.0 / (2 * Gamma * (1/dx**2 + 1/dy**2))
29
  Nt = int(np.ceil(t_max / dt)) + 1
30
  rx, ry = Gamma * dt / dx**2, Gamma * dt / dy**2
31
 
32
  # Initial condition
33
  X, Y = np.meshgrid(x, y, indexing='ij')
 
34
  if initial == "gaussian":
35
  u = np.exp(-(((X - Lx/2)**2 + (Y - Ly/2)**2) / (2*(Lx/10)**2)))
36
  elif initial == "random":
 
40
  u = np.sin(kx * X) * np.sin(ky * Y)
41
  elif initial == "step":
42
  u = np.where((X < Lx/2) & (Y < Ly/2), 1.0, 0.0)
43
+ else:
44
+ raise ValueError(f"Unknown initial condition: {initial}")
45
 
46
  # Storage for solution
47
  U = np.zeros((Nt, Nx, Ny))
 
50
  # Time-stepping loop
51
  for n in range(1, Nt):
52
  un = u.copy()
53
+ # Interior update
54
  u[1:-1, 1:-1] = (
55
  un[1:-1, 1:-1]
56
  + rx * (un[2:, 1:-1] - 2 * un[1:-1, 1:-1] + un[:-2, 1:-1])
57
  + ry * (un[1:-1, 2:] - 2 * un[1:-1, 1:-1] + un[1:-1, :-2])
58
  )
59
+ # Boundary conditions
60
  if bc == "dirichlet":
61
  u[0, :] = u[-1, :] = u[:, 0] = u[:, -1] = 0.0
62
  elif bc == "neumann":
 
64
  u[-1, :] = u[-2, :]
65
  u[:, 0] = u[:, 1]
66
  u[:, -1] = u[:, -2]
67
+ elif bc == "periodic":
68
+ u[0, :] = un[-2, :]
69
+ u[-1, :] = un[1, :]
70
+ u[:, 0] = un[:, -2]
71
+ u[:, -1] = un[:, 1]
72
+ else:
73
+ raise ValueError(f"Unknown bc: {bc}")
74
  U[n] = u.copy()
 
 
 
75
 
76
+ return U, dt
77
+
78
+ # --- Animation Generator ---
79
+ def create_animation_gif(U, Lx, Ly, initial, bc, Gamma, frame_skip, dt):
80
  """
81
+ Create and save a GIF animation from the solution array U.
82
  """
83
+ Nt, Nx, Ny = U.shape
84
+ fig, ax = plt.subplots()
85
+ x = np.linspace(0, Lx, Nx)
86
+ y = np.linspace(0, Ly, Ny)
87
+ im = ax.imshow(U[0].T, cmap='viridis', origin='lower', extent=[0, Lx, 0, Ly], vmin=U.min(), vmax=U.max())
88
+ ax.set_title(f"2D Heat Eq — init={initial}, bc={bc}, Gamma={Gamma:.2f}")
89
+ ax.set_xlabel("x")
90
+ ax.set_ylabel("y")
91
+ plt.colorbar(im, ax=ax, label="u")
92
+
93
+ def update(frame):
94
+ im.set_data(U[frame].T)
95
+ return [im]
96
+
97
+ idx = list(range(0, Nt, frame_skip))
98
+ if idx[-1] != Nt - 1:
99
+ idx.append(Nt - 1)
100
+
101
+ ani = FuncAnimation(fig, update, frames=idx, blit=True)
102
+
103
+ with tempfile.NamedTemporaryFile(suffix='.gif', delete=False) as tmpfile:
104
+ ani.save(tmpfile.name, writer='pillow', fps=30)
105
+ gif_path = tmpfile.name
106
+
107
+ plt.close(fig)
108
+ return gif_path
109
+
110
+ # --- Plotly Figure Generator ---
111
+ def create_plotly_figure(u, Lx, Ly, time_label):
112
+ """
113
+ Create an interactive Plotly heatmap for a given time slice u.
114
+ """
115
+ x = np.linspace(0, Lx, u.shape[0])
116
+ y = np.linspace(0, Ly, u.shape[1])
117
+ fig = go.Figure(data=go.Heatmap(
118
+ z=u.T,
119
+ x=x,
120
+ y=y,
121
+ colorscale='viridis'
122
+ ))
123
+ fig.update_layout(
124
+ title=f"Heat Distribution at t={time_label}",
125
+ xaxis_title='x',
126
+ yaxis_title='y'
127
+ )
128
+ return fig
129
+
130
+ # --- Gradio Interface Logic ---
131
+ def gradio_interface(lx, ly, t_max, gamma, nx, ny, initial, bc, frame_skip):
132
+ nx, ny, frame_skip = int(nx), int(ny), int(frame_skip)
133
  U, dt = solve_2d_heat_equation(
134
+ Lx=lx, Ly=ly, t_max=t_max, Gamma=gamma, Nx=nx, Ny=ny,
135
  initial=initial, bc=bc
136
  )
137
+ Nt = U.shape[0]
138
+ # Compute indices for t=0, t/4, 3t/4, t
139
+ idx0 = 0
140
+ idx1 = round((Nt - 1) / 4)
141
+ idx2 = round(3 * (Nt - 1) / 4)
142
+ idx3 = Nt - 1
143
+ # Extract slices
144
+ u0 = U[idx0]
145
+ u1 = U[idx1]
146
+ u2 = U[idx2]
147
+ u3 = U[idx3]
148
+ # Create Plotly figures
149
+ fig0 = create_plotly_figure(u0, lx, ly, "0")
150
+ fig1 = create_plotly_figure(u1, lx, ly, f"{idx1*dt:.2f}")
151
+ fig2 = create_plotly_figure(u2, lx, ly, f"{idx2*dt:.2f}")
152
+ fig3 = create_plotly_figure(u3, lx, ly, f"{idx3*dt:.2f}")
153
+ # Create GIF
154
+ gif_path = create_animation_gif(U, lx, ly, initial, bc, gamma, frame_skip, dt)
155
+ return gif_path, fig0, fig1, fig2, fig3
156
+
157
+ # --- Gradio UI Layout ---
158
+ with gr.Blocks(theme=gr.themes.Soft(), title="2D Heat Simulator") as demo:
159
+ gr.Markdown("# ♨️ 2D Heat Equation Simulator\nAdjust parameters and run the simulation.")
160
+ with gr.Row():
161
+ with gr.Column(scale=1):
162
+ gr.Markdown("## Domain & Grid")
163
+ lx_slider = gr.Slider(0.1, 5.0, 1.0, 0.1, label="Lx")
164
+ ly_slider = gr.Slider(0.1, 5.0, 1.0, 0.1, label="Ly")
165
+ nx_slider = gr.Slider(3, 200, 50, 1, label="Nx")
166
+ ny_slider = gr.Slider(3, 200, 50, 1, label="Ny")
167
+
168
+ gr.Markdown("## Simulation")
169
+ t_slider = gr.Slider(0.01, 5.0, 0.5, 0.01, label="t_max")
170
+ gamma_slider = gr.Slider(0.001, 1.0, 0.1, 0.001, label="Gamma")
171
+
172
+ gr.Markdown("## Conditions")
173
+ initial_dropdown = gr.Dropdown(
174
+ ["gaussian", "random", "sinusoidal", "step"], "gaussian", label="Initial"
175
+ )
176
+ bc_dropdown = gr.Dropdown(
177
+ ["dirichlet", "neumann", "periodic"], "dirichlet", label="Boundary"
178
+ )
179
+
180
+ gr.Markdown("## Animation")
181
+ frame_skip_slider = gr.Slider(1, 50, 5, 1, label="Frame Skip")
182
+ run_btn = gr.Button("Run Simulation", variant="primary")
183
+ with gr.Column(scale=3):
184
+ gif_output = gr.Image(label="Animation")
185
+ with gr.Row():
186
+ plot1 = gr.Plot(label="t=0")
187
+ plot2 = gr.Plot(label="t=t/4")
188
+ with gr.Row():
189
+ plot3 = gr.Plot(label="t=3t/4")
190
+ plot4 = gr.Plot(label="t=t")
191
+ inputs_list = [lx_slider, ly_slider, t_slider, gamma_slider,
192
+ nx_slider, ny_slider, initial_dropdown, bc_dropdown, frame_skip_slider]
193
+ outputs_list = [gif_output, plot1, plot2, plot3, plot4]
194
+ run_btn.click(fn=gradio_interface, inputs=inputs_list, outputs=outputs_list)
195
+ gr.Examples(
196
+ examples=[
197
+ [1.0, 1.0, 0.5, 0.1, 50, 50, "gaussian", "dirichlet", 5],
198
+ [2.0, 1.0, 1.0, 0.05, 60, 30, "sinusoidal", "periodic", 10],
199
+ [1.0, 1.0, 0.2, 0.2, 80, 80, "step", "neumann", 2],
200
  ],
201
+ inputs=inputs_list,
202
+ outputs=outputs_list,
203
+ fn=gradio_interface
204
  )
205
 
206
  if __name__ == "__main__":
 
207
  demo.launch()