harishaseebat92 commited on
Commit
13251a2
·
1 Parent(s): 50d95a5

IonQ QPU branch is now implemented

Browse files
Files changed (1) hide show
  1. em/simulation.py +189 -14
em/simulation.py CHANGED
@@ -792,21 +792,196 @@ async def _run_simulation_async():
792
  await _flush_async()
793
  return
794
 
795
- # IonQ QPU placeholder branch (not yet implemented)
796
- if state.backend_type == "QPU" and state.selected_qpu == "IonQ QPU":
797
- state.error_message = "IonQ QPU backend is not yet available in this build. Please select IBM QPU or the Statevector Estimator."
798
- state.status_message = "IonQ QPU backend unavailable."
799
- state.status_type = "warning"
800
- state.show_progress = False
801
- state.is_running = False
802
- state.run_button_text = "RUN!"
803
- state.stop_button_disabled = True
804
- log_to_console("IonQ QPU backend not connected. Use IBM QPU or Statevector Estimator instead.")
805
- await _flush_async()
806
  try:
807
- ctrl.view_update()
808
- except Exception:
809
- pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
810
  return
811
 
812
  # Simulator path - run blocking simulation in executor
 
792
  await _flush_async()
793
  return
794
 
795
+ # IonQ QPU branch
796
+ ionq_qpu_selected = state.backend_type == "QPU" and state.selected_qpu == "IonQ QPU"
797
+ if ionq_qpu_selected:
 
 
 
 
 
 
 
 
798
  try:
799
+ log_to_console("Running IonQ QPU simulation...")
800
+ state.status_message = "Running IonQ QPU simulation..."
801
+ state.simulation_progress = 5
802
+ await _flush_async()
803
+
804
+ # Import IonQ QPU backend (same module as IBM, different platform param)
805
+ try:
806
+ from quantum.utils.EBU_Quantum.no_body.base_functions import get_field_values as ionq_get_field_values, create_time_frames as ionq_create_time_frames
807
+ except ModuleNotFoundError:
808
+ from utils.EBU_Quantum.no_body.base_functions import get_field_values as ionq_get_field_values, create_time_frames as ionq_create_time_frames
809
+
810
+ # Inputs for IonQ QPU (single field, single position only!)
811
+ snapshot_dt = float(state.dt_user)
812
+ ix_imp, iy_imp = nearest_node_index(float(state.impulse_x), float(state.impulse_y), nx)
813
+ impulse_pos = (ix_imp, iy_imp)
814
+
815
+ # Get field and single position from UI
816
+ field_type = (state.qpu_field_components or "Ez").strip()
817
+ if field_type == "All":
818
+ field_type = "Ez"
819
+ log_to_console("Warning: IonQ QPU only supports single field. Defaulting to Ez.")
820
+
821
+ # Parse single monitor position
822
+ pts_str = str(state.qpu_monitor_gridpoints or "").strip()
823
+ raw_pts = [tuple(map(int, m)) for m in re.findall(r"\((\d+)\s*,\s*(\d+)\)", pts_str)]
824
+ if not raw_pts:
825
+ monitor_x, monitor_y = impulse_pos
826
+ log_to_console(f"No monitor position specified. Using impulse position ({monitor_x}, {monitor_y}).")
827
+ else:
828
+ monitor_x, monitor_y = raw_pts[0]
829
+ if len(raw_pts) > 1:
830
+ log_to_console(f"Warning: IonQ QPU only supports single position. Using first: ({monitor_x}, {monitor_y})")
831
+
832
+ state.status_message = "Step 1: Generating circuit..."
833
+ state.simulation_progress = 0
834
+ await _flush_async()
835
+
836
+ def _ionq_progress_callback(pct, message=None):
837
+ """Progress callback for IonQ QPU."""
838
+ state.simulation_progress = int(pct)
839
+ if message:
840
+ state.status_message = message
841
+ elif pct < 10:
842
+ state.status_message = f"Step 1: Generating circuit ({int(pct)}%)"
843
+ elif pct < 60:
844
+ state.status_message = f"Step 2: Optimising circuit ({int(pct)}%)"
845
+ elif pct < 90:
846
+ state.status_message = f"Step 3: Job execution ({int(pct)}%)"
847
+ else:
848
+ state.status_message = f"Step 4: Creating plots ({int(pct)}%)"
849
+ _flush_state_threadsafe()
850
+
851
+ # Call the IonQ QPU get_field_values function in executor
852
+ def _run_ionq_qpu():
853
+ return ionq_get_field_values(
854
+ field=field_type,
855
+ x=monitor_x,
856
+ y=monitor_y,
857
+ T=float(T),
858
+ snapshot_time=snapshot_dt,
859
+ nx=nx,
860
+ impulse_pos=impulse_pos,
861
+ shots=10000,
862
+ pm_optimization_level=1, # IonQ recommended
863
+ simulation="False",
864
+ optimization="True",
865
+ platform="IONQ", # <-- Key difference from IBM
866
+ progress_callback=_ionq_progress_callback,
867
+ print_callback=log_to_console,
868
+ )
869
+
870
+ field_values = await loop.run_in_executor(executor, _run_ionq_qpu)
871
+
872
+ # Build time frames to match the output
873
+ times = ionq_create_time_frames(float(T), snapshot_dt)
874
+
875
+ # Build Plotly figure for the single time series
876
+ import plotly.graph_objects as go
877
+ fig = go.Figure()
878
+
879
+ # Determine grid dimensions for label
880
+ if field_type == 'Ez':
881
+ gw, gh = nx, nx
882
+ elif field_type == 'Hx':
883
+ gw, gh = nx, nx - 1
884
+ else:
885
+ gw, gh = nx - 1, nx
886
+
887
+ from .utils import normalized_position_label
888
+ label = normalized_position_label(monitor_x, monitor_y, gw, gh)
889
+
890
+ # Color based on field type
891
+ if field_type == 'Ez':
892
+ color = "#d32f2f"
893
+ elif field_type == 'Hx':
894
+ color = "#388e3c"
895
+ else:
896
+ color = "#1976d2"
897
+
898
+ fig.add_trace(
899
+ go.Scatter(
900
+ x=list(times),
901
+ y=[float(v) for v in field_values],
902
+ mode='lines+markers',
903
+ name=f"{field_type} @ {label}",
904
+ line=dict(color=color, width=2.5),
905
+ marker=dict(size=7, symbol="circle", color=color),
906
+ hovertemplate=f"{field_type} | t=%{{x:.3f}}s<br>Value=%{{y:.6g}}<extra>{label}</extra>",
907
+ )
908
+ )
909
+
910
+ max_abs = max((abs(float(v)) for v in field_values), default=1.0)
911
+ pad = 0.12 * max_abs if max_abs > 0 else 0.1
912
+
913
+ fig.update_layout(
914
+ title=f"IonQ QPU Time Series - {field_type} @ {label}",
915
+ height=660, width=900,
916
+ margin=dict(l=50, r=30, t=50, b=50),
917
+ hovermode="x unified",
918
+ legend=dict(orientation='h', yanchor='bottom', y=1.02, xanchor='right', x=1, title_text=""),
919
+ paper_bgcolor="#FFFFFF",
920
+ plot_bgcolor="#FFFFFF",
921
+ )
922
+ fig.update_xaxes(title_text="Time (s)", title_font=dict(size=22), tickfont=dict(size=16), showgrid=True, gridcolor="rgba(0,0,0,.06)")
923
+ fig.update_yaxes(title_text="Field Value", title_font=dict(size=22), tickfont=dict(size=16), showgrid=True, gridcolor="rgba(0,0,0,.06)")
924
+ fig.update_yaxes(range=[-max_abs - pad, max_abs + pad])
925
+
926
+ # Cache the figure for export
927
+ qpu_ts_cache["fig"] = fig
928
+ qpu_ts_cache["times"] = list(times)
929
+ qpu_ts_cache["series_map"] = {(field_type, monitor_x, monitor_y): list(field_values)}
930
+ qpu_ts_cache["field"] = field_type
931
+ qpu_ts_cache["unique_fields"] = [field_type]
932
+
933
+ try:
934
+ ctrl.qpu_ts_update(fig)
935
+ except Exception:
936
+ pass
937
+
938
+ state.simulation_has_run = True
939
+ state.run_button_text = "Successful!"
940
+ state.simulation_progress = 100
941
+ state.status_message = "IonQ QPU simulation completed successfully!"
942
+ log_to_console("IonQ QPU run completed")
943
+ state.status_type = "success"
944
+ state.show_progress = False
945
+ _auto_hide_status_window(3.0)
946
+ await _flush_async()
947
+
948
+ ready = bool(field_values) and len(field_values) > 0
949
+ state.qpu_ts_ready = ready
950
+ state.qpu_plot_style = (
951
+ "width: 900px; height: 660px; margin: 0 auto;"
952
+ if ready else "display: none; width: 900px; height: 660px; margin: 0 auto;"
953
+ )
954
+ state.qpu_ts_other_ready = False
955
+ state.qpu_other_plot_style = "display: none; width: 900px; height: 660px; margin: 0 auto;"
956
+
957
+ # Set filter options for single result
958
+ state.qpu_plot_field_options = ["All", field_type]
959
+ state.qpu_plot_filter = "All"
960
+ state.qpu_plot_position_options = ["All positions", label]
961
+ state.qpu_plot_position_filter = "All positions"
962
+
963
+ if not ready:
964
+ state.error_message = "No IonQ QPU time series generated. Check Δt, T, nx, and monitor position."
965
+ state.status_message = "Warning: No IonQ QPU time series generated."
966
+ state.status_type = "warning"
967
+ log_to_console("IonQ QPU complete.")
968
+
969
+ except Exception as e:
970
+ import traceback
971
+ state.error_message = f"IonQ QPU run failed: {e}"
972
+ state.status_message = f"IonQ QPU Error: {e}"
973
+ state.status_type = "error"
974
+ state.show_progress = False
975
+ state.run_button_text = "RUN!"
976
+ state.qpu_ts_ready = False
977
+ log_to_console(f"IonQ QPU error: {e}")
978
+ log_to_console(traceback.format_exc())
979
+ finally:
980
+ state.is_running = False
981
+ state.stop_button_disabled = True
982
+ _stop_progress_heartbeat()
983
+ executor.shutdown(wait=False)
984
+ await _flush_async()
985
  return
986
 
987
  # Simulator path - run blocking simulation in executor