harishaseebat92 commited on
Commit
8b2e675
·
1 Parent(s): 0b1fdba

Second update

Browse files
.gitattributes CHANGED
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ Placeholder_Images/*.stl filter=lfs diff=lfs merge=lfs -text
37
+ Placeholder_Images/*.gif filter=lfs diff=lfs merge=lfs -text
Placeholder_Images/gaussian.stl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e2d745eb9141c1a86e48dff2c4e08aa197bc60ff4103d41f9595b6da6c1b9ef2
3
+ size 3960184
Placeholder_Images/gaussian_3d.png ADDED
Placeholder_Images/gaussian_fluid.stl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d4d4eb92f2a9391b46704ec3094909ecd889d9429b596e772005e9eb267e5ad2
3
+ size 242884
Placeholder_Images/gaussian_initial.png ADDED
Placeholder_Images/gaussian_surface.stl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b5d4a636efb5ba15d4e0aee8b7a0b1321f1ae134ceadff70f4e586952a7ef507
3
+ size 242884
Placeholder_Images/qlbm_sinusoidal.gif ADDED

Git LFS Details

  • SHA256: e4deb315cf324320c10dd2a2bd5ae9dab6575f6d5b5997d256e9a2ecdcd473ad
  • Pointer size: 132 Bytes
  • Size of remote file: 3.03 MB
Placeholder_Images/sinusoidal.stl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:33fa8d72c4dc9b96372194663b81da3da4fe66236def23b6eb7a6de9ce986b31
3
+ size 3960184
Placeholder_Images/sinusoidal_3d.png ADDED
Placeholder_Images/sinusoidal_fluid.stl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8eacd3635c25b0e6127cd3b6f1bea965c7477ea05536c17281eda08b3ce78822
3
+ size 392084
Placeholder_Images/sinusoidal_initial.png ADDED
Placeholder_Images/sinusoidal_surface.stl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f81ac68f7b3755fc4a9a339e0c8a5d904ddd7fb940f7071f82bfa123204fe5c3
3
+ size 392084
__pycache__/fluid.cpython-310.pyc ADDED
Binary file (17.2 kB). View file
 
app.py CHANGED
@@ -27,41 +27,6 @@ def qlbm_gradio_interface(grid_size_input: int, time_steps_input: int, distribut
27
  return None, None # Modified return
28
  return plot_fig, plotly_json_frames # Modified return
29
 
30
- def qlbm_3D_gradio_interface(grid_size_input: int, time_steps_input: int, distribution_type_param: str, vx_param, vy_param, vz_param, boundary_condition_param: str):
31
- num_reg_qubits_val = int(math.log2(grid_size_input)) # Convert grid_size back to num_reg_qubits
32
- grid_size_val = grid_size_input
33
- time_steps_val = int(time_steps_input)
34
-
35
- vx_val = str(vx_param)
36
- vy_val = str(vy_param)
37
- vz_val = str(vz_param)
38
-
39
- x_sym, y_sym, z_sym = symbols('x y z')
40
- vx_sympified = sympify(vx_val)
41
- vy_sympified = sympify(vy_val)
42
- vz_sympified = sympify(vz_val)
43
-
44
- vx = lambdify((x_sym, y_sym, z_sym), vx_sympified, modules="numpy")
45
- vy = lambdify((x_sym, y_sym, z_sym), vy_sympified, modules="numpy")
46
- vz = lambdify((x_sym, y_sym, z_sym), vz_sympified, modules="numpy")
47
-
48
- print(f"Gradio Interface: Qubits/Direction={num_reg_qubits_val}, Grid Size={grid_size_val}, T={time_steps_val}, Distribution={distribution_type_param}, vx={vx_val}, vy={vy_val}, vz={vz_val}, Boundary={boundary_condition_param}")
49
-
50
- plot_fig, plotly_json_frames = simulate_qlbm_3D_and_animate( # Modified to unpack two return values
51
- num_reg_qubits=num_reg_qubits_val,
52
- T=time_steps_val,
53
- distribution_type=distribution_type_param,
54
- vx_input=vx,
55
- vy_input=vy,
56
- vz_input=vz,
57
- boundary_condition=boundary_condition_param
58
- )
59
-
60
- if plot_fig is None:
61
- gr.Warning("Simulation or plotting failed. Please check console for errors.")
62
- return None, None # Modified return
63
- return plot_fig, plotly_json_frames # Modified return
64
-
65
  # New functions for downloading Plotly objects
66
  def download_plot_data(plotly_json_frames):
67
  if not plotly_json_frames:
@@ -98,32 +63,13 @@ def update_qubit_info(grid_size):
98
 
99
  return fig, total_qubits_display, warning, recommended_display
100
 
101
- def update_qubit_3D_info(grid_size):
102
- num_reg_qubits = int(math.log2(grid_size))
103
- total_qubits = 3 * num_reg_qubits + 3
104
- grid_display = f"Grid Size: {grid_size} × {grid_size} × {grid_size}"
105
-
106
- x = np.array([16, 32, 64, 128, 256])
107
- y = np.log2(x).astype(int)
108
- fig = go.Figure()
109
- fig.add_trace(go.Scatter(x=x, y=y, mode='lines', name='Qubits/Direction'))
110
- fig.add_trace(go.Scatter(x=[grid_size], y=[num_reg_qubits], mode='markers', marker=dict(size=12, color='red'), name='Current Selection'))
111
- fig.update_layout(
112
- xaxis_title="Grid Size (Points/Direction)",
113
- yaxis_title="Qubits/Direction",
114
- width=400,
115
- height=300
116
- )
117
- warning = "⚠️ Warning: Grid sizes > 64 may exceed simulator/memory limits!" if grid_size > 64 else ""
118
- return fig, grid_display, warning
119
-
120
  # Modified example functions to set grid_size
121
  def set_sinusoidal_example():
122
  return (
123
  gr.update(value=256), # grid_size = 256 (corresponds to 8 qubits)
124
  gr.update(value=1600), # time_steps
125
  gr.update(value="Sinusoidal"), # distribution_type
126
- gr.update(value="User"), # velocity_field
127
  gr.update(value=0.2), # vx
128
  gr.update(value=0.15), # vy
129
  gr.update(value="Periodic"), # boundary_condition
@@ -134,247 +80,87 @@ def set_gaussian_example():
134
  gr.update(value=256), # grid_size = 256 (corresponds to 8 qubits)
135
  gr.update(value=1600), # time_steps
136
  gr.update(value="Gaussian"), # distribution_type
137
- gr.update(value="User"), # velocity_field
138
  gr.update(value=0.2), # vx
139
  gr.update(value=0.15), # vy
140
  gr.update(value="Periodic"), # boundary_condition
141
  )
142
 
143
- def set_sinusoidal_3d_example():
144
- return (
145
- gr.update(value=32), # grid_size = 32 (corresponds to 5 qubits)
146
- gr.update(value=100), # time_steps
147
- gr.update(value="Sinusoidal"), # distribution_type
148
- gr.update(value="0.2"), # vx
149
- gr.update(value="-0.15"), # vy
150
- gr.update(value="0.3"), # vz
151
- gr.update(value="Periodic"), # boundary_condition
152
- )
153
-
154
- def set_gaussian_3d_example():
155
- return (
156
- gr.update(value=32), # grid_size = 32 (corresponds to 5 qubits)
157
- gr.update(value=100), # time_steps
158
- gr.update(value="Gaussian"), # distribution_type
159
- gr.update(value="0.2"), # vx
160
- gr.update(value="-0.15"), # vy
161
- gr.update(value="0.3"), # vz
162
- gr.update(value="Periodic"), # boundary_condition
163
- )
164
-
165
- # Gradio interface with modified layout and slider
166
- with gr.Blocks(theme=gr.themes.Soft(), title="Quantum Simulation Demo") as demo:
167
- problem_type = gr.Radio(
168
- choices=["Fluid Dynamics", "EM", "Mechanical"],
169
- value="Fluid Dynamics",
170
- label="Select Problem Type"
171
- )
172
-
173
- with gr.Tabs() as tabs:
174
- with gr.TabItem("Fluid Dynamics - 2D", visible=True) as fluid_tab_2D:
175
- with gr.Row(): # Main row for top section
176
- with gr.Column(scale=1): # Column for left-side controls
177
- gr.Markdown("## Initial Distribution Examples")
178
- with gr.Row():
179
- with gr.Column(scale=1):
180
- example1 = LitModel3D("Placeholder_Images/sinusoidal.stl", label="Sinusoidal")
181
- sinusoidal_btn_2d = gr.Button("Sinusoidal")
182
- with gr.Column(scale=1):
183
- example2 = LitModel3D("Placeholder_Images/gaussian.stl", label="Gaussian")
184
- gaussian_btn_2d = gr.Button("Gaussian")
185
-
186
- gr.Markdown("## Simulation Parameters")
187
- num_reg_qubits_input_2d = gr.Slider(
188
- minimum=2**7, maximum=2**12, # Grid size values
189
- value=2**8, step=None, # step=None for arbitrary powers of 2 (handled by update function)
190
- label="Grid Size/Direction"
191
- )
192
- time_steps_slider_2d = gr.Slider(minimum=0, maximum=4000, value=1600, step=10, label="Time Steps")
193
- qubit_plot_2d = gr.Plot(label="Qubits vs. Grid Size")
194
- total_qubits_display_2d = gr.Markdown("Total Qubits: 19")
195
- warning_display_2d = gr.Markdown("")
196
- recommended_time_steps_display_2d = gr.Markdown("Recommended time steps: 1600")
197
-
198
- with gr.Column(scale=2): # Column for the main plot
199
- qlbm_interactive_plot_2d = gr.Plot(label="QLBM")
200
- download_button_2d = gr.DownloadButton(label="Download Plot Data (JSON)", visible=False) # New download button
201
- plotly_json_frames_state_2d = gr.State([]) # New state to store Plotly JSON frames
202
-
203
- with gr.Row(): # Row for bottom section
204
  with gr.Column(scale=1):
205
- gr.Markdown("## Initialization")
206
- with gr.Row():
207
- shear_btn_2d = gr.Button("Shear")
208
- tgv_btn_2d = gr.Button("TGV")
209
- with gr.Row():
210
- swirl_btn_2d = gr.Button("Swirl")
211
- user_btn_2d = gr.Button("User")
212
- selected_velocity_field_2d = gr.State("User")
213
- vx_slider_2d = gr.Slider(minimum=-0.3, maximum=0.3, value=0.2, step=0.01, label="V_x", visible=True)
214
- vy_slider_2d = gr.Slider(minimum=-0.3, maximum=0.3, value=0.15, step=0.01, label="V_y", visible=True)
215
- distribution_type_input_2d = gr.Radio(choices=["Gaussian", "Sinusoidal", "Random"], value="Sinusoidal", label="Initial Distribution Type")
216
-
217
  with gr.Column(scale=1):
218
- gr.Markdown("## Boundary Conditions")
219
- boundary_condition_input_2d = gr.Radio(choices=["Periodic", "Dirichlet", "Neumann"], value="Periodic", label="Boundary Condition")
220
-
221
- run_qlbm_btn_2d = gr.Button("Run Simulation", variant="primary") # Button below the sections
222
-
223
- qlbm_inputs_list_2d = [
224
- num_reg_qubits_input_2d, time_steps_slider_2d, distribution_type_input_2d,
225
- selected_velocity_field_2d, vx_slider_2d, vy_slider_2d, boundary_condition_input_2d
226
- ]
227
- run_qlbm_btn_2d.click(
228
- fn=qlbm_gradio_interface,
229
- inputs=qlbm_inputs_list_2d,
230
- outputs=[qlbm_interactive_plot_2d, plotly_json_frames_state_2d] # Modified output
231
- ).then(
232
- lambda: gr.update(visible=True), # Make download button visible after simulation
233
- outputs=[download_button_2d]
234
  )
235
- download_button_2d.click(
236
- fn=download_plot_data,
237
- inputs=[plotly_json_frames_state_2d],
238
- outputs=[download_button_2d]
239
- )
240
- num_reg_qubits_input_2d.change(
241
- fn=update_qubit_info,
242
- inputs=num_reg_qubits_input_2d,
243
- outputs=[qubit_plot_2d, total_qubits_display_2d, warning_display_2d, recommended_time_steps_display_2d]
244
- )
245
- sinusoidal_btn_2d.click(
246
- fn=set_sinusoidal_example,
247
- inputs=[],
248
- outputs=[num_reg_qubits_input_2d, time_steps_slider_2d, distribution_type_input_2d, selected_velocity_field_2d, vx_slider_2d, vy_slider_2d, boundary_condition_input_2d]
249
- )
250
- gaussian_btn_2d.click(
251
- fn=set_gaussian_example,
252
- inputs=[],
253
- outputs=[num_reg_qubits_input_2d, time_steps_slider_2d, distribution_type_input_2d, selected_velocity_field_2d, vx_slider_2d, vy_slider_2d, boundary_condition_input_2d]
254
- )
255
-
256
- def update_velocity_sliders_2d_from_button(velocity_type):
257
- return velocity_type, gr.update(visible=velocity_type == "User"), gr.update(visible=velocity_type == "User")
258
-
259
- shear_btn_2d.click(fn=lambda: update_velocity_sliders_2d_from_button("Shear"), outputs=[selected_velocity_field_2d, vx_slider_2d, vy_slider_2d])
260
- tgv_btn_2d.click(fn=lambda: update_velocity_sliders_2d_from_button("TGV"), outputs=[selected_velocity_field_2d, vx_slider_2d, vy_slider_2d])
261
- swirl_btn_2d.click(fn=lambda: update_velocity_sliders_2d_from_button("Swirl"), outputs=[selected_velocity_field_2d, vx_slider_2d, vy_slider_2d])
262
- user_btn_2d.click(fn=lambda: update_velocity_sliders_2d_from_button("User"), outputs=[selected_velocity_field_2d, vx_slider_2d, vy_slider_2d])
263
-
264
- with gr.TabItem("Fluid Dynamics - 3D", visible=True) as fluid_tab_3D:
265
- with gr.Row(): # Main row for top section
266
- with gr.Column(scale=1): # Column for left-side controls
267
- gr.Markdown("## Initial Distribution Examples")
268
- with gr.Row():
269
- with gr.Column(scale=1):
270
- example1 = LitModel3D("Placeholder_Images/sinusoidal_fluid.stl", label="Sinusoidal")
271
- sinusoidal_3d_btn = gr.Button("Sinusoidal")
272
- with gr.Column(scale=1):
273
- example2 = LitModel3D("Placeholder_Images/gaussian_fluid.stl", label="Gaussian")
274
- gaussian_3d_btn = gr.Button("Gaussian")
275
- gr.Markdown("## Simulation Parameters")
276
- num_reg_qubits_input_3d = gr.Slider(
277
- minimum=2**4, maximum=2**8, # Grid size values
278
- value=2**5, step=None, # step=None for arbitrary powers of 2
279
- label="Grid Size/Direction"
280
- )
281
- time_steps_slider_3d = gr.Slider(minimum=0, maximum=2000, value=100, step=10, label="Time Steps")
282
- # Removed num_slider_steps_slider_3d
283
- qubit_plot_3d = gr.Plot(label="Qubits vs. Grid Size")
284
- grid_display_3d = gr.Markdown("Grid Size: 32 × 32 × 32")
285
- warning_display_3d = gr.Markdown("")
286
-
287
- with gr.Column(scale=2): # Column for the main plot
288
- qlbm_interactive_plot_3d = gr.Plot(label="QLBM")
289
- download_button_3d = gr.DownloadButton(label="Download Plot Data (JSON)", visible=False) # New download button
290
- plotly_json_frames_state_3d = gr.State([]) # New state to store Plotly JSON frames
291
-
292
- with gr.Row(): # Row for bottom section
293
- with gr.Column(scale=1):
294
- gr.Markdown("## Initialization")
295
- with gr.Row():
296
- uniform_btn_3d = gr.Button("Uniform")
297
- swirl_btn_3d = gr.Button("Swirl")
298
- with gr.Row():
299
- shear_btn_3d = gr.Button("Shear")
300
- tgv_btn_3d = gr.Button("TGV")
301
- vx_text_input_3d = gr.Textbox(value="0.2", label="Velocity vx")
302
- vy_text_input_3d = gr.Textbox(value="-0.15", label="Velocity vy")
303
- vz_text_input_3d = gr.Textbox(value="0.3", label="Velocity vz")
304
- distribution_type_input_3d = gr.Radio(choices=["Gaussian", "Sinusoidal"], value="Sinusoidal", label="Initial Distribution Type")
305
-
306
- with gr.Column(scale=1):
307
- gr.Markdown("## Boundary Conditions")
308
- boundary_condition_input_3d = gr.Radio(choices=["Periodic", "Dirichlet", "Neumann"], value="Periodic", label="Boundary Condition")
309
-
310
- run_qlbm_btn_3d = gr.Button("Run Simulation", variant="primary") # Button below the sections
311
-
312
- qlbm_inputs_list_3d = [
313
- num_reg_qubits_input_3d, time_steps_slider_3d, distribution_type_input_3d,
314
- vx_text_input_3d, vy_text_input_3d, vz_text_input_3d, boundary_condition_input_3d
315
- # Removed num_slider_steps_slider_3d from inputs
316
- ]
317
- run_qlbm_btn_3d.click(
318
- fn=qlbm_3D_gradio_interface,
319
- inputs=qlbm_inputs_list_3d,
320
- outputs=[qlbm_interactive_plot_3d, plotly_json_frames_state_3d] # Modified output
321
- ).then(
322
- lambda: gr.update(visible=True), # Make download button visible after simulation
323
- outputs=[download_button_3d]
324
- )
325
- download_button_3d.click(
326
- fn=download_plot_data,
327
- inputs=[plotly_json_frames_state_3d],
328
- outputs=[download_button_3d]
329
- )
330
- num_reg_qubits_input_3d.change(
331
- fn=update_qubit_3D_info,
332
- inputs=num_reg_qubits_input_3d,
333
- outputs=[qubit_plot_3d, grid_display_3d, warning_display_3d]
334
- )
335
-
336
- sinusoidal_3d_btn.click(
337
- fn=set_sinusoidal_3d_example,
338
- inputs=[],
339
- outputs=[num_reg_qubits_input_3d, time_steps_slider_3d, distribution_type_input_3d, vx_text_input_3d, vy_text_input_3d, vz_text_input_3d, boundary_condition_input_3d]
340
- )
341
- gaussian_3d_btn.click(
342
- fn=set_gaussian_3d_example,
343
- inputs=[],
344
- outputs=[num_reg_qubits_input_3d, time_steps_slider_3d, distribution_type_input_3d, vx_text_input_3d, vy_text_input_3d, vz_text_input_3d, boundary_condition_input_3d]
345
- )
346
-
347
- def update_velocity_entries_3d(val):
348
- fieldname_to_index = {"Uniform": 0, "Swirl": 1, "Shear": 2, "TGV": 3}
349
- selection = fieldname_to_index[val]
350
- return (
351
- gr.update(value=(["0.2", "0.3*sin(-2*pi*z)", "abs(z-0.5)*1.2-0.3", "0.15*cos(2*pi*x)*sin(2*pi*y)*sin(2*pi*z)"])[selection]),
352
- gr.update(value=(["-0.15", "0.2", "0", "-0.3*sin(2*pi*x)*cos(2*pi*y)*sin(2*pi*z)"])[selection]),
353
- gr.update(value=(["0.3", "0.3*sin(2*pi*x)", "0", "0.15*sin(2*pi*x)*sin(2*pi*y)*cos(2*pi*z)"])[selection])
354
- )
355
-
356
- uniform_btn_3d.click(fn=lambda: update_velocity_entries_3d("Uniform"), outputs=[vx_text_input_3d, vy_text_input_3d, vz_text_input_3d])
357
- swirl_btn_3d.click(fn=lambda: update_velocity_entries_3d("Swirl"), outputs=[vx_text_input_3d, vy_text_input_3d, vz_text_input_3d])
358
- shear_btn_3d.click(fn=lambda: update_velocity_entries_3d("Shear"), outputs=[vx_text_input_3d, vy_text_input_3d, vz_text_input_3d])
359
- tgv_btn_3d.click(fn=lambda: update_velocity_entries_3d("TGV"), outputs=[vx_text_input_3d, vy_text_input_3d, vz_text_input_3d])
360
-
361
- with gr.TabItem("EM", visible=False) as em_tab:
362
- gr.Markdown("## Coming Soon")
363
- with gr.TabItem("Mechanical", visible=False) as mech_tab:
364
- gr.Markdown("## Coming Soon")
365
-
366
- def update_tabs(selection):
367
- return (
368
- gr.update(visible=selection == "Fluid Dynamics"),
369
- gr.update(visible=selection == "Fluid Dynamics"),
370
- gr.update(visible=selection == "EM"),
371
- gr.update(visible=selection == "Mechanical")
372
- )
373
-
374
- problem_type.change(
375
- fn=update_tabs,
376
- inputs=problem_type,
377
- outputs=[fluid_tab_2D, fluid_tab_3D, em_tab, mech_tab]
378
  )
379
 
380
  if __name__ == "__main__":
 
27
  return None, None # Modified return
28
  return plot_fig, plotly_json_frames # Modified return
29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  # New functions for downloading Plotly objects
31
  def download_plot_data(plotly_json_frames):
32
  if not plotly_json_frames:
 
63
 
64
  return fig, total_qubits_display, warning, recommended_display
65
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  # Modified example functions to set grid_size
67
  def set_sinusoidal_example():
68
  return (
69
  gr.update(value=256), # grid_size = 256 (corresponds to 8 qubits)
70
  gr.update(value=1600), # time_steps
71
  gr.update(value="Sinusoidal"), # distribution_type
72
+ gr.update(value="Uniform"), # velocity_field
73
  gr.update(value=0.2), # vx
74
  gr.update(value=0.15), # vy
75
  gr.update(value="Periodic"), # boundary_condition
 
80
  gr.update(value=256), # grid_size = 256 (corresponds to 8 qubits)
81
  gr.update(value=1600), # time_steps
82
  gr.update(value="Gaussian"), # distribution_type
83
+ gr.update(value="Uniform"), # velocity_field
84
  gr.update(value=0.2), # vx
85
  gr.update(value=0.15), # vy
86
  gr.update(value="Periodic"), # boundary_condition
87
  )
88
 
89
+ # Gradio interface for Fluid Dynamics - 2D only
90
+ with gr.Blocks(theme=gr.themes.Soft(), title="QLBM Fluid Simulation (2D)") as demo:
91
+ with gr.Row(): # Main row for top section
92
+ with gr.Column(scale=1): # Column for left-side controls
93
+ gr.Markdown("## Initial Distribution Examples")
94
+ with gr.Row():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  with gr.Column(scale=1):
96
+ example1 = LitModel3D("Placeholder_Images/sinusoidal.stl", label="Sinusoidal")
97
+ sinusoidal_btn_2d = gr.Button("Sinusoidal")
 
 
 
 
 
 
 
 
 
 
98
  with gr.Column(scale=1):
99
+ example2 = LitModel3D("Placeholder_Images/gaussian.stl", label="Gaussian")
100
+ gaussian_btn_2d = gr.Button("Gaussian")
101
+
102
+ gr.Markdown("## Simulation Parameters")
103
+ num_reg_qubits_input_2d = gr.Slider(
104
+ minimum=2**7, maximum=2**12, # Grid size values
105
+ value=2**8, step=None, # step=None for arbitrary powers of 2 (handled by update function)
106
+ label="Grid Size/Direction"
 
 
 
 
 
 
 
 
107
  )
108
+ time_steps_slider_2d = gr.Slider(minimum=0, maximum=4000, value=1600, step=10, label="Time Steps")
109
+ qubit_plot_2d = gr.Plot(label="Qubits vs. Grid Size")
110
+ total_qubits_display_2d = gr.Markdown("Total Qubits: 19")
111
+ warning_display_2d = gr.Markdown("")
112
+ recommended_time_steps_display_2d = gr.Markdown("Recommended time steps: 1600")
113
+
114
+ with gr.Column(scale=2): # Column for the main plot
115
+ qlbm_interactive_plot_2d = gr.Plot(label="QLBM")
116
+ download_button_2d = gr.DownloadButton(label="Download Plot Data (JSON)", visible=False) # New download button
117
+ plotly_json_frames_state_2d = gr.State([]) # New state to store Plotly JSON frames
118
+
119
+ with gr.Row(): # Row for bottom section
120
+ with gr.Column(scale=1):
121
+ gr.Markdown("## Initialization (Uniform)")
122
+ selected_velocity_field_2d = gr.State("Uniform")
123
+ vx_slider_2d = gr.Slider(minimum=-0.3, maximum=0.3, value=0.2, step=0.01, label="V_x", visible=True)
124
+ vy_slider_2d = gr.Slider(minimum=-0.3, maximum=0.3, value=0.15, step=0.01, label="V_y", visible=True)
125
+ distribution_type_input_2d = gr.Radio(choices=["Gaussian", "Sinusoidal"], value="Sinusoidal", label="Initial Distribution Type")
126
+
127
+ with gr.Column(scale=1):
128
+ gr.Markdown("## Boundary Conditions")
129
+ boundary_condition_input_2d = gr.Radio(choices=["Periodic"], value="Periodic", label="Boundary Condition")
130
+
131
+ run_qlbm_btn_2d = gr.Button("Run Simulation", variant="primary") # Button below the sections
132
+
133
+ qlbm_inputs_list_2d = [
134
+ num_reg_qubits_input_2d, time_steps_slider_2d, distribution_type_input_2d,
135
+ selected_velocity_field_2d, vx_slider_2d, vy_slider_2d, boundary_condition_input_2d
136
+ ]
137
+ run_qlbm_btn_2d.click(
138
+ fn=qlbm_gradio_interface,
139
+ inputs=qlbm_inputs_list_2d,
140
+ outputs=[qlbm_interactive_plot_2d, plotly_json_frames_state_2d] # Modified output
141
+ ).then(
142
+ lambda: gr.update(visible=True), # Make download button visible after simulation
143
+ outputs=[download_button_2d]
144
+ )
145
+ download_button_2d.click(
146
+ fn=download_plot_data,
147
+ inputs=[plotly_json_frames_state_2d],
148
+ outputs=[download_button_2d]
149
+ )
150
+ num_reg_qubits_input_2d.change(
151
+ fn=update_qubit_info,
152
+ inputs=num_reg_qubits_input_2d,
153
+ outputs=[qubit_plot_2d, total_qubits_display_2d, warning_display_2d, recommended_time_steps_display_2d]
154
+ )
155
+ sinusoidal_btn_2d.click(
156
+ fn=set_sinusoidal_example,
157
+ inputs=[],
158
+ outputs=[num_reg_qubits_input_2d, time_steps_slider_2d, distribution_type_input_2d, selected_velocity_field_2d, vx_slider_2d, vy_slider_2d, boundary_condition_input_2d]
159
+ )
160
+ gaussian_btn_2d.click(
161
+ fn=set_gaussian_example,
162
+ inputs=[],
163
+ outputs=[num_reg_qubits_input_2d, time_steps_slider_2d, distribution_type_input_2d, selected_velocity_field_2d, vx_slider_2d, vy_slider_2d, boundary_condition_input_2d]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
  )
165
 
166
  if __name__ == "__main__":
fluid.py CHANGED
@@ -149,10 +149,6 @@ def simulate_qlbm_and_animate(num_reg_qubits: int, T: int, distribution_type: st
149
  selected_initial_state_function_raw = lambda x, y, N_val_func: \
150
  np.exp(-((x - N_val_func / 2)**2 / (2 * (N_val_func / 5)**2) +
151
  (y - N_val_func / 2)**2 / (2 * (N_val_func / 5)**2))) * 1.8 + 0.2
152
- elif distribution_type == "Random":
153
- selected_initial_state_function_raw = lambda x, y, N_val_func: \
154
- np.random.rand(N_val_func, N_val_func) * 1.5 + 0.2 if isinstance(x, int) else \
155
- np.random.rand(x.shape[0], x.shape[1]) * 1.5 + 0.2
156
  else:
157
  print(f"Warning: Unknown distribution type '{distribution_type}'. Defaulting to Sinusoidal.")
158
  selected_initial_state_function_raw = lambda x, y, N_val_func: \
@@ -163,16 +159,8 @@ def simulate_qlbm_and_animate(num_reg_qubits: int, T: int, distribution_type: st
163
  selected_initial_state_function_raw(x_coords, y_coords, current_N) * \
164
  (y_coords < current_N).astype(int)
165
 
166
- if velocity_field == "User":
167
  pass
168
- elif velocity_field == "Shear":
169
- vx_input = vx_input * (current_N / 2)
170
- elif velocity_field == "TGV":
171
- vx_input = vx_input * np.sin(np.pi * current_N / 10)
172
- vy_input = vy_input * np.cos(np.pi * current_N / 10)
173
- elif velocity_field == "Swirl":
174
- vx_input = vx_input * np.cos(np.pi * current_N / 5)
175
- vy_input = vy_input * np.sin(np.pi * current_N / 5)
176
 
177
  with tempfile.TemporaryDirectory() as tmp_npy_dir:
178
  intermediate_folder_path = Path(tmp_npy_dir)
@@ -359,10 +347,6 @@ def simulate_qlbm_and_animate(num_reg_qubits: int, T: int, distribution_type: st
359
 
360
  if boundary_condition == "Periodic":
361
  pass
362
- elif boundary_condition == "Dirichlet":
363
- pass
364
- elif boundary_condition == "Neumann":
365
- pass
366
 
367
  downsampling_factor = 2**5
368
  if current_N == 0:
@@ -378,10 +362,7 @@ def simulate_qlbm_and_animate(num_reg_qubits: int, T: int, distribution_type: st
378
  yv_init = np.arange(current_N)
379
  initial_grid_2d_X, initial_grid_2d_Y = np.meshgrid(xv_init, yv_init)
380
 
381
- if distribution_type == "Random":
382
- initial_grid_2d = selected_initial_state_function_raw(current_N, current_N, current_N)
383
- else:
384
- initial_grid_2d = initial_state_func_eval(initial_grid_2d_X, initial_grid_2d_Y)
385
 
386
  sub_sv_init_flat = initial_grid_2d.flatten().astype(np.complex128)
387
  norm = np.linalg.norm(sub_sv_init_flat)
@@ -456,10 +437,10 @@ def simulate_qlbm_and_animate(num_reg_qubits: int, T: int, distribution_type: st
456
  for i, Z in enumerate(data_frames):
457
  frame_trace = go.Surface(
458
  z=Z, x=x_coords_plot, y=y_coords_plot,
459
- colorscale='Viridis',
460
  cmin=z_min, cmax=z_max,
461
  name=f'Time: {actual_timesteps[i]}',
462
- showscale=True
463
  )
464
  fig.add_trace(frame_trace)
465
 
@@ -494,537 +475,32 @@ def simulate_qlbm_and_animate(num_reg_qubits: int, T: int, distribution_type: st
494
 
495
  sliders = [dict(active=0, currentvalue={"prefix": "Time: "}, pad={"t": 50}, steps=steps)]
496
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
497
  fig.update_layout(
498
  title='', # Removed graph title
499
  scene=dict(
500
  xaxis_title='X',
501
  yaxis_title='Y',
502
  zaxis_title='Density',
503
- xaxis=dict(range=[x_coords_plot[0], x_coords_plot[-1]]),
504
- yaxis=dict(range=[y_coords_plot[0], y_coords_plot[-1]]),
505
- zaxis=dict(range=[z_min, z_max]),
506
  ),
507
  sliders=sliders,
508
  width=800,
509
  height=700
510
  )
511
-
512
- return fig, plotly_json_frames # Modified return
513
-
514
- def simulate_qlbm_3D_and_animate(num_reg_qubits: int, T: int, distribution_type: str, vx_input, vy_input, vz_input, boundary_condition: str):
515
- num_anc = 3
516
- num_qubits_total = 3 * num_reg_qubits + num_anc
517
- current_N = 2**num_reg_qubits
518
- N_tot_state_vector = 2**num_qubits_total
519
- num_ranks = 1
520
- rank = 0
521
- N_sub_per_rank = int(N_tot_state_vector // num_ranks)
522
-
523
- # Simplified time steps for 3D since slider steps are removed
524
- NUM_ANIMATION_FRAMES_3D = 10 # Default number of frames if no specific slider steps
525
-
526
- if T == 0:
527
- time_steps = [0]
528
- else:
529
- num_points = min(T + 1, NUM_ANIMATION_FRAMES_3D)
530
- time_steps = np.linspace(start=0, stop=T, num=num_points, dtype=int)
531
- time_steps = sorted(list(set(time_steps)))
532
-
533
-
534
- if distribution_type == "Sinusoidal":
535
- selected_initial_state_function_raw = lambda x, y, z, N_val_func: \
536
- np.sin(x * 2 * np.pi / N_val_func) * \
537
- np.sin(y * 2 * np.pi / N_val_func) * \
538
- np.sin(z * 2 * np.pi / N_val_func) + 1
539
- elif distribution_type == "Gaussian":
540
- selected_initial_state_function_raw = lambda x, y, z, N_val_func: \
541
- np.exp(-((x - N_val_func / 2)**2 / (2 * (N_val_func / 5)**2) + (y - N_val_func / 2)**2 / (2 * (N_val_func / 5)**2) +
542
- (z - N_val_func / 2)**2 / (2 * (N_val_func / 5)**2))) * 1.8 + 0.2
543
- else:
544
- print(f"Warning: Unknown distribution type '{distribution_type}'. Defaulting to Sinusoidal.")
545
- selected_initial_state_function_raw = lambda x, y, z, N_val_func: \
546
- np.sin(x * 2 * np.pi / N_val_func) * \
547
- np.sin(y * 2 * np.pi / N_val_func) * \
548
- np.sin(z * 2 * np.pi / N_val_func) + 1
549
-
550
- initial_state_func_eval = lambda i:\
551
- selected_initial_state_function_raw(i%current_N,(i//current_N)%current_N,i//(current_N**2),current_N)*(i<(current_N**3)).astype(int)
552
-
553
- with tempfile.TemporaryDirectory() as tmp_npy_dir:
554
- intermediate_folder_path = Path(tmp_npy_dir)
555
-
556
- cudaq.set_target('nvidia', option='fp64')
557
-
558
- @cudaq.kernel
559
- def alloc_kernel(num_qubits_alloc: int):
560
- qubits = cudaq.qvector(num_qubits_alloc)
561
-
562
- from cupy.cuda.memory import MemoryPointer, UnownedMemory
563
-
564
- def to_cupy_array(state):
565
- tensor = state.getTensor()
566
- pDevice = tensor.data()
567
- sizeByte = tensor.get_num_elements() * tensor.get_element_size()
568
- mem = UnownedMemory(pDevice, sizeByte, owner=state)
569
- memptr_obj = MemoryPointer(mem, 0)
570
- cupy_array_val = cp.ndarray(tensor.get_num_elements(),
571
- dtype=cp.complex128,
572
- memptr=memptr_obj)
573
- return cupy_array_val
574
-
575
- class QLBMAdvecDiffD3Q7_new:
576
- def __init__(self,vx,vy,vz) -> None:
577
- self.dim = 3
578
- self.ndir = 7
579
- self.nq_dir = math.ceil(np.log2(self.ndir))
580
- self.dirs=[]
581
- for dir_int in range(self.ndir):
582
- if dir_int==4:
583
- dir_bin="111"
584
- else:
585
- dir_bin = f"{dir_int:b}".zfill(self.nq_dir)
586
- self.dirs.append(dir_bin)
587
- self.cs = 1/np.sqrt(3)
588
- self.ux = lambda x,y,z: vx(x,y,z)/self.cs**2
589
- self.uy = lambda x,y,z: vy(x,y,z)/self.cs**2
590
- self.uz = lambda x,y,z: vz(x,y,z)/self.cs**2
591
- self.create_circuit()
592
-
593
- def create_circuit(self):
594
- print("Creating circuit")
595
- x_coeffs,x_coeff_var_indices=get_circuit_inputs(lambda x,y,z: ((1+self.ux(x/current_N,y/current_N,z/current_N))/2)**0.5,num_reg_qubits,min(current_N,32))
596
- y_coeffs,y_coeff_var_indices=get_circuit_inputs(lambda x,y,z: ((1+self.uy(x/current_N,y/current_N,z/current_N))/2)**0.5,num_reg_qubits,min(current_N,32))
597
- z_coeffs,z_coeff_var_indices=get_circuit_inputs(lambda x,y,z: ((1+self.uz(x/current_N,y/current_N,z/current_N))/2)**0.5,num_reg_qubits,min(current_N,32))
598
- x_coeffs_,x_coeff_var_indices_=get_circuit_inputs(lambda x,y,z: 0 if (1+self.ux((x-1)/current_N,y/current_N,z/current_N))==0 else \
599
- ((1+self.ux((x-1)/current_N,y/current_N,z/current_N))/(2+self.ux((x-1)/current_N,y/current_N,z/current_N)-self.ux((x+1)/current_N,y/current_N,z/current_N)))**0.5,num_reg_qubits,min(current_N,32))
600
- y_coeffs_,y_coeff_var_indices_=get_circuit_inputs(lambda x,y,z: 0 if (1+self.uy(x/current_N,(y-1)/current_N,z/current_N))==0 else \
601
- ((1+self.uy(x/current_N,(y-1)/current_N,z/current_N))/(2+self.uy(x/current_N,(y-1)/current_N,z/current_N)-self.uy(x/current_N,(y+1)/current_N,z/current_N)))**0.5,num_reg_qubits,min(current_N,32))
602
- z_coeffs_,z_coeff_var_indices_=get_circuit_inputs(lambda x,y,z: 0 if (1+self.uz(x/current_N,y/current_N,(z-1)/current_N))==0 else \
603
- ((1+self.uz(x/current_N,y/current_N,(z-1)/current_N))/(2+self.uz(x/current_N,y/current_N,(z-1)/current_N)-self.uz(x/current_N,y/current_N,(z+1)/current_N)))**0.5,num_reg_qubits,min(current_N,32))
604
- unprep1_coeffs,unprep1_coeff_var_indices=get_circuit_inputs(lambda x,y,z:\
605
- (1/3**0.5)*(1+(self.ux((x-1)/current_N,y/current_N,z/current_N)-self.ux((x+1)/current_N,y/current_N,z/current_N))/2)**0.5,num_reg_qubits,min(current_N,32))
606
- unprep2_coeffs, unprep2_coeff_var_indices = get_circuit_inputs(lambda x, y, z: ((1 + (self.uy(x/current_N, (y-1)/current_N, z/current_N) - self.uy(x/current_N, (y+1)/current_N, z/current_N))/2) /(2 - (self.ux((x-1)/current_N, y/current_N, z/current_N) - self.ux((x+1)/current_N, y/current_N, z/current_N))/2))**0.5, num_reg_qubits, min(current_N, 32))
607
- print("Generated angles")
608
- v=np.pad([1/4, 1/4, 0, 1/4, 0, 1/4, 0],(0,2**num_anc - self.ndir))
609
- v=v**0.5
610
- v[0]+=1
611
- v=v/np.linalg.norm(v)
612
- U_prep=2*np.outer(v,v)-np.eye(len(v))
613
- cudaq.register_operation("prep_op", U_prep)
614
- def collisionOp(dirs):
615
- dirs_i_list=[]
616
- for dir_ in dirs:
617
- dirs_i=[(int(c)) for c in dir_]
618
- dirs_i_list+=dirs_i[::-1]
619
- return dirs_i_list
620
- self.dirs_i_list=collisionOp(self.dirs)
621
- print("Generated dirs_i_list")
622
- @cudaq.kernel
623
- def rshift(q: cudaq.qview, n: int):
624
- for i in range(n):
625
- if i == n-1:
626
- x(q[n-1-i])
627
- elif i == n-2:
628
- x.ctrl(q[n-1-(i+1)], q[n-1-i])
629
- else:
630
- x.ctrl(q[0:n-1-i], q[n-1-i])
631
- @cudaq.kernel
632
- def lshift(q: cudaq.qview, n: int):
633
- for i in range(n):
634
- if i == 0:
635
- x(q[0])
636
- elif i == 1:
637
- x.ctrl(q[0], q[1])
638
- else:
639
- x.ctrl(q[0:i], q[i])
640
- @cudaq.kernel
641
- def d2q5_tstep(q: cudaq.qview, nqx: int, nqy: int, nqz: int, nq_dir: int, dirs_i: list[int]):
642
- qx=q[0:nqx]
643
- qy=q[nqx:nqx+nqy]
644
- qz=q[nqx+nqy:nqx+nqy+nqz]
645
- qdir=q[nqx+nqy+nqz:nqx+nqy+nqz+nq_dir]
646
- i=2
647
- b_list=dirs_i[i*nq_dir:(i+1)*nq_dir]
648
- for j in range(nq_dir):
649
- b=b_list[j]
650
- if b==0:
651
- x(qdir[j])
652
- cudaq.control(lshift,qdir,qx,nqx)
653
- for j in range(nq_dir):
654
- b=b_list[j]
655
- if b==0:
656
- x(qdir[j])
657
- i=1
658
- b_list=dirs_i[i*nq_dir:(i+1)*nq_dir]
659
- for j in range(nq_dir):
660
- b=b_list[j]
661
- if b==0:
662
- x(qdir[j])
663
- cudaq.control(rshift,qdir,qx,nqx)
664
- for j in range(nq_dir):
665
- b=b_list[j]
666
- if b==0:
667
- x(qdir[j])
668
- i=4
669
- b_list=dirs_i[i*nq_dir:(i+1)*nq_dir]
670
- for j in range(nq_dir):
671
- b=b_list[j]
672
- if b==0:
673
- x(qdir[j])
674
- cudaq.control(lshift,qdir,qy,nqy)
675
- for j in range(nq_dir):
676
- b=b_list[j]
677
- if b==0:
678
- x(qdir[j])
679
- i=3
680
- b_list=dirs_i[i*nq_dir:(i+1)*nq_dir]
681
- for j in range(nq_dir):
682
- b=b_list[j]
683
- if b==0:
684
- x(qdir[j])
685
- cudaq.control(rshift,qdir,qy,nqy)
686
- for j in range(nq_dir):
687
- b=b_list[j]
688
- if b==0:
689
- x(qdir[j])
690
- i=6
691
- b_list=dirs_i[i*nq_dir:(i+1)*nq_dir]
692
- for j in range(nq_dir):
693
- b=b_list[j]
694
- if b==0:
695
- x(qdir[j])
696
- cudaq.control(lshift,qdir,qz,nqz)
697
- for j in range(nq_dir):
698
- b=b_list[j]
699
- if b==0:
700
- x(qdir[j])
701
- i=5
702
- b_list=dirs_i[i*nq_dir:(i+1)*nq_dir]
703
- for j in range(nq_dir):
704
- b=b_list[j]
705
- if b==0:
706
- x(qdir[j])
707
- cudaq.control(rshift,qdir,qz,nqz)
708
- for j in range(nq_dir):
709
- b=b_list[j]
710
- if b==0:
711
- x(qdir[j])
712
- @cudaq.kernel
713
- def d2q5_tstep_wrapper(state: cudaq.State,nqx:int,nqy:int,nqz:int,nq_dir:int,dirs_i:list[int],\
714
- x_coeff_var_indices:list[int],x_coeffs:list[float],\
715
- y_coeff_var_indices:list[int],y_coeffs:list[float],\
716
- z_coeff_var_indices:list[int],z_coeffs:list[float],\
717
- x_coeff_var_indices_:list[int],x_coeffs_:list[float],\
718
- y_coeff_var_indices_:list[int],y_coeffs_:list[float],\
719
- z_coeff_var_indices_:list[int],z_coeffs_:list[float],\
720
- unprep1_coeff_var_indices:list[int],unprep1_coeffs:list[float],\
721
- unprep2_coeff_var_indices:list[int],unprep2_coeffs:list[float]):
722
- q=cudaq.qvector(state)
723
- qdir=q[nqx+nqy+nqz:nqx+nqy+nqz+nq_dir]
724
- prep_op(qdir[2],qdir[1],qdir[0])
725
- x.ctrl(qdir[0],qdir[1])
726
- ind=0
727
- coeff_ind=0
728
- x(qdir[2])
729
- while ind<len(x_coeff_var_indices):
730
- tuple_length=x_coeff_var_indices[ind]
731
- for sub_ind in range(ind+1, ind+1+tuple_length):
732
- x.ctrl(q[nqx+nqy+nqz-1-x_coeff_var_indices[sub_ind]],qdir[0])
733
- ry.ctrl(-x_coeffs[coeff_ind],[qdir[2],qdir[1]],qdir[0])
734
- coeff_ind+=1
735
- ind+=(1+tuple_length)
736
- x(qdir[2])
737
- ind=0
738
- coeff_ind=0
739
- while ind<len(z_coeff_var_indices):
740
- tuple_length=z_coeff_var_indices[ind]
741
- for sub_ind in range(ind+1,ind+1+tuple_length):
742
- x.ctrl(q[nqx+nqy+nqz-1-z_coeff_var_indices[sub_ind]],qdir[0])
743
- ry.ctrl(-z_coeffs[coeff_ind],[qdir[2],qdir[1]],qdir[0])
744
- coeff_ind+=1
745
- ind+=(1+tuple_length)
746
- x.ctrl(qdir[0],qdir[1])
747
- ind=0
748
- coeff_ind=0
749
- while ind<len(y_coeff_var_indices):
750
- tuple_length=y_coeff_var_indices[ind]
751
- for sub_ind in range(ind+1,ind+1+tuple_length):
752
- x.ctrl(q[nqx+nqy+nqz-1-y_coeff_var_indices[sub_ind]],qdir[2])
753
- ry.ctrl(y_coeffs[coeff_ind],[qdir[0],qdir[1]],qdir[2])
754
- coeff_ind+=1
755
- ind+=(1+tuple_length)
756
- d2q5_tstep(q,nqx,nqy,nqz,nq_dir,dirs_i)
757
- ind=0
758
- coeff_ind=0
759
- while ind<len(y_coeff_var_indices_):
760
- tuple_length=y_coeff_var_indices_[ind]
761
- for sub_ind in range(ind+1,ind+1+tuple_length):
762
- x.ctrl(q[nqx+nqy+nqz-1-y_coeff_var_indices_[sub_ind]],qdir[2])
763
- ry.ctrl(-y_coeffs_[coeff_ind],[qdir[0],qdir[1]],qdir[2])
764
- coeff_ind+=1
765
- ind+=(1+tuple_length)
766
- x.ctrl(qdir[0],qdir[1])
767
- ind=0
768
- coeff_ind=0
769
- x(qdir[2])
770
- while ind<len(x_coeff_var_indices_):
771
- tuple_length=x_coeff_var_indices_[ind]
772
- for sub_ind in range(ind+1,ind+1+tuple_length):
773
- x.ctrl(q[nqx+nqy+nqz-1-x_coeff_var_indices_[sub_ind]],qdir[0])
774
- ry.ctrl(x_coeffs_[coeff_ind],[qdir[1],qdir[2]],qdir[0])
775
- coeff_ind+=1
776
- ind+=(1+tuple_length)
777
- x(qdir[2])
778
- ind=0
779
- coeff_ind=0
780
- while ind<len(z_coeff_var_indices_):
781
- tuple_length=z_coeff_var_indices_[ind]
782
- for sub_ind in range(ind+1,ind+1+tuple_length):
783
- x.ctrl(q[nqx+nqy+nqz-1-z_coeff_var_indices_[sub_ind]],qdir[0])
784
- ry.ctrl(z_coeffs_[coeff_ind],[qdir[1],qdir[2]],qdir[0])
785
- coeff_ind+=1
786
- ind+=(1+tuple_length)
787
- x.ctrl(qdir[0],qdir[1])
788
- ind=0
789
- coeff_ind=0
790
- x.ctrl(qdir[1],qdir[2])
791
- while ind<len(unprep2_coeff_var_indices):
792
- tuple_length=unprep2_coeff_var_indices[ind]
793
- for sub_ind in range(ind+1,ind+1+tuple_length):
794
- x.ctrl(q[nqx+nqy+nqz-1-unprep2_coeff_var_indices[sub_ind]],qdir[1])
795
- ry.ctrl(unprep2_coeffs[coeff_ind],qdir[2],qdir[1])
796
- coeff_ind+=1
797
- ind+=(1+tuple_length)
798
- x.ctrl(qdir[1],qdir[2])
799
- ind=0
800
- coeff_ind=0
801
- while ind<len(unprep1_coeff_var_indices):
802
- tuple_length=unprep1_coeff_var_indices[ind]
803
- for sub_ind in range(ind+1,ind+1+tuple_length):
804
- x.ctrl(q[nqx+nqy+nqz-1-unprep1_coeff_var_indices[sub_ind]],qdir[1])
805
- ry.ctrl(-unprep1_coeffs[coeff_ind],qdir[0],qdir[1])
806
- coeff_ind+=1
807
- ind+=(1+tuple_length)
808
- ry(-2*np.pi/3,qdir[0])
809
- print("Kernels defined")
810
- def run_timestep_func(vec_arg, hadamard=False):
811
- result=cudaq.get_state(d2q5_tstep_wrapper,vec_arg,num_reg_qubits,num_reg_qubits,num_reg_qubits,self.nq_dir,self.dirs_i_list,\
812
- x_coeff_var_indices,x_coeffs,\
813
- y_coeff_var_indices,y_coeffs,\
814
- z_coeff_var_indices,z_coeffs,\
815
- x_coeff_var_indices_,x_coeffs_,\
816
- y_coeff_var_indices_,y_coeffs_,\
817
- z_coeff_var_indices_,z_coeffs_,\
818
- unprep1_coeff_var_indices,unprep1_coeffs,\
819
- unprep2_coeff_var_indices,unprep2_coeffs)
820
- num_nonzero_ranks = num_ranks / (2**num_anc)
821
- rank_slice_cupy = to_cupy_array(result)
822
- if rank >= num_nonzero_ranks and num_nonzero_ranks > 0:
823
- sub_sv_zeros = np.zeros(N_sub_per_rank, dtype=np.complex128)
824
- cp.cuda.runtime.memcpy(rank_slice_cupy.data.ptr, sub_sv_zeros.ctypes.data, sub_sv_zeros.nbytes, cp.cuda.runtime.memcpyHostToDevice)
825
- if rank == 0 and num_nonzero_ranks < 1 and N_sub_per_rank > 0:
826
- limit_idx = int(N_tot_state_vector / (2**num_anc))
827
- if limit_idx < rank_slice_cupy.size:
828
- rank_slice_cupy[limit_idx:] = 0
829
- return result
830
- self.run_timestep = run_timestep_func
831
- print("Circuit created")
832
- def write_state(self, state_to_write, t_step_str_val):
833
- rank_slice_cupy = to_cupy_array(state_to_write)
834
- num_nonzero_ranks = num_ranks / (2**num_anc)
835
- if rank < num_nonzero_ranks or (rank == 0 and num_nonzero_ranks <= 0):
836
- save_path = intermediate_folder_path / f"{t_step_str_val}_{rank}.npy"
837
- with open(save_path, 'wb') as f:
838
- arr_to_save = None
839
- data_limit = N_sub_per_rank
840
- if num_nonzero_ranks < 1 and rank == 0:
841
- data_limit = int(N_tot_state_vector / (2**num_anc))
842
- if data_limit > 0:
843
- relevant_part_cupy = cp.real(rank_slice_cupy[:data_limit])
844
- else:
845
- relevant_part_cupy = cp.array([], dtype=cp.float64)
846
- if relevant_part_cupy.size >= current_N * current_N * current_N:
847
- arr_flat = relevant_part_cupy[:current_N * current_N * current_N]
848
- if downsampling_factor > 1 and current_N > 0:
849
- arr_reshaped = arr_flat.reshape((current_N, current_N, current_N))
850
- arr_downsampled = arr_reshaped[::downsampling_factor, ::downsampling_factor, ::downsampling_factor]
851
- arr_to_save = arr_downsampled.flatten()
852
- else:
853
- arr_to_save = arr_flat
854
- elif relevant_part_cupy.size > 0:
855
- if downsampling_factor > 1:
856
- arr_to_save = relevant_part_cupy[::downsampling_factor]
857
- else:
858
- arr_to_save = relevant_part_cupy
859
- if arr_to_save is not None and arr_to_save.size > 0:
860
- np.save(f, arr_to_save.get() if isinstance(arr_to_save, cp.ndarray) else arr_to_save)
861
- print("Write state defined")
862
- def run_evolution(self, initial_state_arg, total_timesteps, time_steps_to_save, observable=False):
863
- current_state_val = initial_state_arg
864
- save_times = set(time_steps_to_save)
865
- if 0 in save_times:
866
- print("Writing first state")
867
- self.write_state(current_state_val, '0')
868
- for t_iter in range(total_timesteps):
869
- print("Running timestep")
870
- next_state_val = self.run_timestep(current_state_val)
871
- if (t_iter + 1) in save_times:
872
- print("Writing next state")
873
- self.write_state(next_state_val, str(t_iter + 1))
874
- cp.get_default_memory_pool().free_all_blocks()
875
- current_state_val = next_state_val
876
- if rank == 0:
877
- print(f"Timestep: {total_timesteps}/{total_timesteps} (Evolution complete)")
878
- cp.get_default_memory_pool().free_all_blocks()
879
- self.final_state = current_state_val
880
-
881
- if boundary_condition == "Periodic":
882
- pass
883
- elif boundary_condition == "Dirichlet":
884
- pass
885
- elif boundary_condition == "Neumann":
886
- pass
887
-
888
- downsampling_factor = 1
889
- if current_N == 0:
890
- print("Error: current_N is zero. num_reg_qubits likely too small.")
891
- return None, None # Modified return
892
- if current_N < downsampling_factor:
893
- downsampling_factor = current_N if current_N > 0 else 1
894
-
895
- qlbm_obj = QLBMAdvecDiffD3Q7_new(vx=vx_input, vy=vy_input, vz=vz_input)
896
- initial_state_val = cudaq.get_state(alloc_kernel, num_qubits_total)
897
-
898
- sub_sv_init_flat = initial_state_func_eval(np.arange(N_sub_per_rank)).astype(np.complex128)
899
-
900
- norm = np.linalg.norm(sub_sv_init_flat)
901
- if norm > 0:
902
- sub_sv_init_flat /= norm
903
- else:
904
- print("Error: Initial state norm is zero.")
905
- return None, None # Modified return
906
- full_initial_sv_host = np.zeros(N_sub_per_rank, dtype=np.complex128)
907
- num_computational_states = current_N ** 3
908
- if len(sub_sv_init_flat) == num_computational_states:
909
- if num_computational_states <= N_sub_per_rank:
910
- full_initial_sv_host[:num_computational_states] = sub_sv_init_flat
911
- else:
912
- print(f"Error: Grid data {num_computational_states} > N_sub_per_rank {N_sub_per_rank}")
913
- return None, None # Modified return
914
- else:
915
- print(f"Warning: Initial state size {len(sub_sv_init_flat)} != expected {num_computational_states}")
916
- fill_len = min(len(sub_sv_init_flat), num_computational_states, N_sub_per_rank)
917
- full_initial_sv_host[:fill_len] = sub_sv_init_flat[:fill_len]
918
-
919
- rank_slice_init = to_cupy_array(initial_state_val)
920
- print(f'Rank {rank}: Initializing state with {distribution_type} (vx={vx_input}, vy={vy_input})...')
921
- cp.cuda.runtime.memcpy(rank_slice_init.data.ptr, full_initial_sv_host.ctypes.data, full_initial_sv_host.nbytes, cp.cuda.runtime.memcpyHostToDevice)
922
- print(f'Rank {rank}: Initial state copied. Size: {len(sub_sv_init_flat)}. N_sub_per_rank: {N_sub_per_rank}')
923
-
924
- print("Starting QLBM evolution...")
925
- qlbm_obj.run_evolution(initial_state_val, T, time_steps)
926
- print("QLBM evolution complete.")
927
-
928
- print("Generating interactive plot with Plotly...")
929
- downsampled_N = current_N // downsampling_factor
930
- if downsampled_N == 0 and current_N > 0:
931
- downsampled_N = 1
932
- elif current_N == 0:
933
- print("Error: current_N is zero before Plotly stage.")
934
- return None, None # Modified return
935
-
936
- data_frames = []
937
- actual_timesteps = []
938
- for t in time_steps:
939
- file_path = intermediate_folder_path / f"{t}_{rank}.npy"
940
- if file_path.exists():
941
- sol_loaded = np.load(file_path)
942
- if sol_loaded.size == downsampled_N * downsampled_N* downsampled_N:
943
- data = np.reshape(sol_loaded, (downsampled_N, downsampled_N, downsampled_N))
944
- data_frames.append(data)
945
- actual_timesteps.append(t)
946
- print(f"Time {t}: Min={np.min(data)}, Max={np.max(data)}, Mean={np.mean(data)}")
947
- else:
948
- print(f"Warning: File {file_path} size {sol_loaded.size} != expected {downsampled_N*downsampled_N*downsampled_N}. Skipping.")
949
- else:
950
- print(f"Warning: File {file_path} not found. Skipping.")
951
-
952
- if not data_frames:
953
- print("Error: No data frames loaded for plotting.")
954
- return None, None # Modified return
955
-
956
- x_coords_plot = np.linspace(0, 1, downsampled_N)
957
- y_coords_plot = np.linspace(0, 1, downsampled_N)
958
- z_coords_plot = np.linspace(0, 1, downsampled_N)
959
- Z_grid_mesh, Y_grid_mesh, X_grid_mesh = np.meshgrid(x_coords_plot, y_coords_plot, z_coords_plot, indexing='ij')
960
-
961
- data_min = min([np.min(data) for data in data_frames])
962
- data_max = max([np.max(data) for data in data_frames])
963
- if data_max == data_min:
964
- data_max += 1e-9
965
-
966
- fig = go.Figure()
967
-
968
- # Store individual frames for download
969
- plotly_json_frames = []
970
-
971
- for i, output_data in enumerate(data_frames):
972
- frame_trace = go.Isosurface(
973
- x=X_grid_mesh.flatten(),
974
- y=Y_grid_mesh.flatten(),
975
- z=Z_grid_mesh.flatten(),
976
- value=output_data.flatten(),
977
- isomin=data_min,
978
- isomax=data_max,
979
- opacity=0.4, # needs to be small to see through all surfaces
980
- surface_count=7, # needs to be a large number for good volume rendering,
981
- caps=dict(x_show=False, y_show=False, z_show=False)
982
- )
983
- fig.add_trace(frame_trace)
984
-
985
- # Create a figure for the individual frame and convert to JSON
986
- single_frame_fig = go.Figure(data=[frame_trace], layout=fig.layout)
987
- single_frame_fig.update_layout(
988
- title=f"Time: {actual_timesteps[i]}",
989
- scene=dict(
990
- xaxis_title='X',
991
- yaxis_title='Y',
992
- zaxis_title='Z',
993
- xaxis=dict(range=[x_coords_plot[0], x_coords_plot[-1]]),
994
- yaxis=dict(range=[y_coords_plot[0], y_coords_plot[-1]]),
995
- zaxis=dict(range=[z_coords_plot[0], z_coords_plot[-1]]),
996
- )
997
- )
998
- plotly_json_frames.append(single_frame_fig.to_json())
999
-
1000
- for trace in fig.data[1:]:
1001
- trace.visible = False
1002
-
1003
- steps = []
1004
- for i in range(len(data_frames)):
1005
- step = dict(
1006
- method="update",
1007
- args=[{"visible": [False] * len(data_frames)}],
1008
- label=f"Time: {actual_timesteps[i]}"
1009
- )
1010
- step["args"][0]["visible"][i] = True
1011
- steps.append(step)
1012
-
1013
- sliders = [dict(active=0, currentvalue={"prefix": "Time: "}, pad={"t": 50}, steps=steps)]
1014
-
1015
- fig.update_layout(
1016
- title='', # Removed graph title
1017
- scene=dict(
1018
- xaxis_title='X',
1019
- yaxis_title='Y',
1020
- zaxis_title='Z',
1021
- xaxis=dict(range=[x_coords_plot[0], x_coords_plot[-1]]),
1022
- yaxis=dict(range=[y_coords_plot[0], y_coords_plot[-1]]),
1023
- zaxis=dict(range=[z_coords_plot[0], z_coords_plot[-1]]),
1024
- ),
1025
- sliders=sliders,
1026
- width=800,
1027
- height=700
1028
- )
1029
-
1030
  return fig, plotly_json_frames # Modified return
 
149
  selected_initial_state_function_raw = lambda x, y, N_val_func: \
150
  np.exp(-((x - N_val_func / 2)**2 / (2 * (N_val_func / 5)**2) +
151
  (y - N_val_func / 2)**2 / (2 * (N_val_func / 5)**2))) * 1.8 + 0.2
 
 
 
 
152
  else:
153
  print(f"Warning: Unknown distribution type '{distribution_type}'. Defaulting to Sinusoidal.")
154
  selected_initial_state_function_raw = lambda x, y, N_val_func: \
 
159
  selected_initial_state_function_raw(x_coords, y_coords, current_N) * \
160
  (y_coords < current_N).astype(int)
161
 
162
+ if velocity_field == "Uniform":
163
  pass
 
 
 
 
 
 
 
 
164
 
165
  with tempfile.TemporaryDirectory() as tmp_npy_dir:
166
  intermediate_folder_path = Path(tmp_npy_dir)
 
347
 
348
  if boundary_condition == "Periodic":
349
  pass
 
 
 
 
350
 
351
  downsampling_factor = 2**5
352
  if current_N == 0:
 
362
  yv_init = np.arange(current_N)
363
  initial_grid_2d_X, initial_grid_2d_Y = np.meshgrid(xv_init, yv_init)
364
 
365
+ initial_grid_2d = initial_state_func_eval(initial_grid_2d_X, initial_grid_2d_Y)
 
 
 
366
 
367
  sub_sv_init_flat = initial_grid_2d.flatten().astype(np.complex128)
368
  norm = np.linalg.norm(sub_sv_init_flat)
 
437
  for i, Z in enumerate(data_frames):
438
  frame_trace = go.Surface(
439
  z=Z, x=x_coords_plot, y=y_coords_plot,
440
+ colorscale='Blues',
441
  cmin=z_min, cmax=z_max,
442
  name=f'Time: {actual_timesteps[i]}',
443
+ showscale=False
444
  )
445
  fig.add_trace(frame_trace)
446
 
 
475
 
476
  sliders = [dict(active=0, currentvalue={"prefix": "Time: "}, pad={"t": 50}, steps=steps)]
477
 
478
+ # fig.update_layout(
479
+ # title='', # Removed graph title
480
+ # scene=dict(
481
+ # xaxis_title='X',
482
+ # yaxis_title='Y',
483
+ # zaxis_title='Density',
484
+ # xaxis=dict(range=[x_coords_plot[0], x_coords_plot[-1]]),
485
+ # yaxis=dict(range=[y_coords_plot[0], y_coords_plot[-1]]),
486
+ # zaxis=dict(range=[z_min, z_max]),
487
+ # ),
488
+ # sliders=sliders,
489
+ # width=800,
490
+ # height=700
491
+ # )
492
  fig.update_layout(
493
  title='', # Removed graph title
494
  scene=dict(
495
  xaxis_title='X',
496
  yaxis_title='Y',
497
  zaxis_title='Density',
498
+ xaxis=dict(visible=False),
499
+ yaxis=dict(visible=False),
500
+ zaxis=dict(visible=False),
501
  ),
502
  sliders=sliders,
503
  width=800,
504
  height=700
505
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
506
  return fig, plotly_json_frames # Modified return