harishaseebat92 commited on
Commit
6ca7a4a
·
1 Parent(s): b112afa

EM : IBM/ION Job Retrieve Upload Window

Browse files
Files changed (4) hide show
  1. em/simulation.py +133 -105
  2. em/state.py +1 -2
  3. em/ui.py +102 -75
  4. qlbm/qlbm_sample_app.py +1 -1
em/simulation.py CHANGED
@@ -1445,30 +1445,33 @@ def update_value_display(point):
1445
 
1446
  def process_uploaded_em_job_result():
1447
  """
1448
- Process an uploaded IBM/IonQ EM job result JSON file and generate a time-series plot.
1449
 
1450
  This function:
1451
- 1. Decodes the uploaded file (base64 -> JSON)
1452
- 2. Parses the job result to extract field values (expectation values or counts)
 
1453
  3. Builds time frames based on user-specified T and dt
1454
  4. Generates a Plotly time-series figure
1455
 
1456
- Required JSON structure (example):
1457
- - IBM: List of expectation values or PrimitiveResult
1458
- - IonQ: Dict with "field_values" or list of values
1459
- - Simple format: {"field_values": [0.1, 0.2, ...], "times": [0.0, 0.1, ...]}
1460
  """
1461
- import base64
1462
- import json
1463
  import plotly.graph_objects as go
1464
 
1465
  if not state.bound:
1466
  return
1467
 
1468
- # Validate file upload
1469
- uploaded = state.em_job_upload
1470
- if not uploaded:
1471
- state.em_job_upload_error = "No file uploaded. Please select a JSON file."
 
 
 
 
1472
  return
1473
 
1474
  # Reset messages
@@ -1482,28 +1485,9 @@ def process_uploaded_em_job_result():
1482
  def log_to_console(msg):
1483
  print(msg)
1484
 
1485
- log_to_console("Processing uploaded EM job result...")
1486
 
1487
  try:
1488
- # Handle list or single file
1489
- file_data = uploaded[0] if isinstance(uploaded, list) else uploaded
1490
-
1491
- # Get filename for display
1492
- filename = file_data.get("name", "unknown.json") if isinstance(file_data, dict) else "unknown.json"
1493
- state.em_job_upload_filename = filename
1494
- log_to_console(f"Processing file: {filename}")
1495
-
1496
- # Decode content
1497
- content = file_data.get("content", "") if isinstance(file_data, dict) else ""
1498
-
1499
- if isinstance(content, bytes):
1500
- json_str = content.decode("utf-8")
1501
- else:
1502
- if content.startswith("data:"):
1503
- content = content.split(",", 1)[1]
1504
- raw_bytes = base64.b64decode(content)
1505
- json_str = raw_bytes.decode("utf-8")
1506
-
1507
  # Parse parameters from UI
1508
  field_type = str(state.em_job_field_type or "Ez").strip()
1509
 
@@ -1524,77 +1508,125 @@ def process_uploaded_em_job_result():
1524
  platform = str(state.em_job_platform or "IBM")
1525
 
1526
  log_to_console(f"Parameters: field={field_type}, pos=({monitor_x},{monitor_y}), T={total_time}, dt={snapshot_dt}, nx={nx}, platform={platform}")
1527
-
1528
- # Parse JSON
1529
- result = json.loads(json_str)
1530
-
1531
- # Extract field values based on result structure
1532
  field_values = []
1533
  times = []
1534
-
1535
- # Try different result formats
1536
- if isinstance(result, dict):
1537
- # Format 1: {"field_values": [...], "times": [...]}
1538
- if "field_values" in result:
1539
- field_values = result["field_values"]
1540
- times = result.get("times", None)
1541
- log_to_console(f"Found 'field_values' key with {len(field_values)} values")
1542
-
1543
- # Format 2: {"results": {...}} with key -> value mapping
1544
- elif "results" in result:
1545
- results_dict = result["results"]
1546
- # Sort by key (time index) and extract values
1547
- sorted_keys = sorted(results_dict.keys(), key=lambda x: float(x) if x.replace('.','').isdigit() else 0)
1548
- field_values = [results_dict[k] for k in sorted_keys]
1549
- log_to_console(f"Found 'results' dict with {len(field_values)} entries")
1550
-
1551
- # Format 3: {"expectation_values": [...]}
1552
- elif "expectation_values" in result:
1553
- exp_vals = result["expectation_values"]
1554
- # Convert expectation values to field values: sqrt((1 - z_exp) / 2)
1555
- field_values = [np.sqrt((1 - float(z)) / 2) for z in exp_vals]
1556
- log_to_console(f"Found 'expectation_values' with {len(field_values)} values, converted to field values")
1557
-
1558
- # Format 4: IBM RuntimeEncoder result with nested structure
1559
- elif "pub_results" in result or "results" in result:
1560
- pub_results = result.get("pub_results", result.get("results", []))
1561
- for pr in pub_results:
1562
- if isinstance(pr, dict) and "data" in pr:
1563
- data = pr["data"]
1564
- if "evs" in data:
1565
- z_exp = float(data["evs"])
1566
- field_values.append(np.sqrt((1 - z_exp) / 2))
1567
- log_to_console(f"Parsed {len(field_values)} values from pub_results")
1568
-
1569
- else:
1570
- # Try to use the dict values directly if they look numeric
1571
- if all(isinstance(v, (int, float)) for v in result.values()):
1572
- sorted_keys = sorted(result.keys())
1573
- field_values = [result[k] for k in sorted_keys]
1574
- log_to_console(f"Using dict values directly: {len(field_values)} values")
1575
-
1576
- elif isinstance(result, list):
1577
- # Format 5: Simple list of values
1578
- if all(isinstance(v, (int, float)) for v in result):
1579
- field_values = result
1580
- log_to_console(f"Simple list with {len(field_values)} values")
1581
-
1582
- # Format 6: List of dicts (e.g., IBM PrimitiveResult-like)
1583
- elif all(isinstance(v, dict) for v in result):
1584
- for item in result:
1585
- if "evs" in item:
1586
- z_exp = float(item["evs"])
1587
- field_values.append(np.sqrt((1 - z_exp) / 2))
1588
- elif "value" in item:
1589
- field_values.append(float(item["value"]))
1590
- elif "data" in item and isinstance(item["data"], dict):
1591
- if "evs" in item["data"]:
1592
- z_exp = float(item["data"]["evs"])
1593
- field_values.append(np.sqrt((1 - z_exp) / 2))
1594
- log_to_console(f"Parsed {len(field_values)} values from list of dicts")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1595
 
1596
  if not field_values:
1597
- state.em_job_upload_error = "Could not extract field values from JSON. Check file format."
1598
  state.em_job_is_processing = False
1599
  return
1600
 
@@ -1688,12 +1720,8 @@ def process_uploaded_em_job_result():
1688
  state.qpu_plot_position_options = ["All positions", label]
1689
  state.qpu_plot_position_filter = "All positions"
1690
 
1691
- state.em_job_upload_success = f"✓ Successfully processed {len(field_values)} time step(s) from {filename}"
1692
  log_to_console(f"Upload processing complete: {len(field_values)} points plotted")
1693
-
1694
- except json.JSONDecodeError as e:
1695
- state.em_job_upload_error = f"Invalid JSON file: {e}"
1696
- log_to_console(f"JSON decode error: {e}")
1697
  except Exception as e:
1698
  state.em_job_upload_error = f"Error processing job result: {e}"
1699
  log_to_console(f"Processing error: {e}")
 
1445
 
1446
  def process_uploaded_em_job_result():
1447
  """
1448
+ Process an IBM/IonQ EM job by retrieving it directly using the Job ID and generate a time-series plot.
1449
 
1450
  This function:
1451
+ 1. Takes the Job ID from user input
1452
+ 2. Connects to IBM/IonQ based on platform selection and retrieves the job
1453
+ 3. Extracts expectation values (evs) from Estimator results and converts them to field magnitudes
1454
  3. Builds time frames based on user-specified T and dt
1455
  4. Generates a Plotly time-series figure
1456
 
1457
+ Note:
1458
+ - This pathway expects the job was submitted by this EM workflow (Estimator-based).
1459
+ - The job is assumed to contain one expectation value per time frame.
 
1460
  """
1461
+ import os
 
1462
  import plotly.graph_objects as go
1463
 
1464
  if not state.bound:
1465
  return
1466
 
1467
+ # Validate Job ID
1468
+ job_id = None
1469
+ if getattr(state, "em_job_id", None) and str(state.em_job_id).strip():
1470
+ job_id = str(state.em_job_id).strip()
1471
+ if job_id.endswith(".json"):
1472
+ job_id = job_id[:-5]
1473
+ if not job_id:
1474
+ state.em_job_upload_error = "No Job ID provided. Please enter a Job ID."
1475
  return
1476
 
1477
  # Reset messages
 
1485
  def log_to_console(msg):
1486
  print(msg)
1487
 
1488
+ log_to_console(f"Processing EM job result for Job ID: {job_id}")
1489
 
1490
  try:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1491
  # Parse parameters from UI
1492
  field_type = str(state.em_job_field_type or "Ez").strip()
1493
 
 
1508
  platform = str(state.em_job_platform or "IBM")
1509
 
1510
  log_to_console(f"Parameters: field={field_type}, pos=({monitor_x},{monitor_y}), T={total_time}, dt={snapshot_dt}, nx={nx}, platform={platform}")
1511
+
1512
+ # Retrieve job results from provider
 
 
 
1513
  field_values = []
1514
  times = []
1515
+
1516
+ if platform.upper() == "IBM":
1517
+ try:
1518
+ from qiskit_ibm_runtime import QiskitRuntimeService
1519
+ except Exception:
1520
+ state.em_job_upload_error = "qiskit_ibm_runtime package not available. Please install it."
1521
+ state.em_job_is_processing = False
1522
+ return
1523
+
1524
+ try:
1525
+ ibm_token = os.environ.get("API_KEY_IBM_EM")
1526
+ if not ibm_token or not str(ibm_token).strip():
1527
+ state.em_job_upload_error = "IBM API token not found. Set API_KEY_IBM_EM environment variable."
1528
+ state.em_job_is_processing = False
1529
+ return
1530
+ service = QiskitRuntimeService(
1531
+ channel="ibm_cloud",
1532
+ token=ibm_token,
1533
+ instance="crn:v1:bluemix:public:quantum-computing:us-east:a/15157e4350c04a9dab51b8b8a4a93c86:e29afd91-64bf-4a82-8dbf-731e6c213595::",
1534
+ )
1535
+ except Exception as e:
1536
+ state.em_job_upload_error = f"Failed to connect to IBM Quantum: {e}"
1537
+ state.em_job_is_processing = False
1538
+ return
1539
+
1540
+ try:
1541
+ job = service.job(job_id)
1542
+ except Exception as e:
1543
+ state.em_job_upload_error = f"Failed to retrieve IBM job: {e}"
1544
+ state.em_job_is_processing = False
1545
+ return
1546
+
1547
+ try:
1548
+ status = job.status()
1549
+ status_name = status.name if hasattr(status, "name") else str(status)
1550
+ if status_name not in ("DONE", "COMPLETED"):
1551
+ state.em_job_upload_error = f"Job is not complete. Current status: {status_name}"
1552
+ state.em_job_is_processing = False
1553
+ return
1554
+ except Exception:
1555
+ pass
1556
+
1557
+ try:
1558
+ # Support both shapes:
1559
+ # - PrimitiveResult: iterable of pubs -> pub.data.evs
1560
+ # - list-like result where each entry has .data.evs
1561
+ res = job.result()
1562
+ if hasattr(res, "__iter__"):
1563
+ for pub in res:
1564
+ data = getattr(pub, "data", None)
1565
+ evs = getattr(data, "evs", None) if data is not None else None
1566
+ if evs is not None:
1567
+ z_exp = float(np.array(evs).reshape(-1)[0])
1568
+ field_values.append(float(np.sqrt((1 - z_exp) / 2)))
1569
+ elif hasattr(res, "data") and hasattr(res.data, "evs"):
1570
+ z_exp = float(np.array(res.data.evs).reshape(-1)[0])
1571
+ field_values.append(float(np.sqrt((1 - z_exp) / 2)))
1572
+ except Exception as e:
1573
+ state.em_job_upload_error = f"Failed to get job results: {e}"
1574
+ state.em_job_is_processing = False
1575
+ return
1576
+
1577
+ else:
1578
+ # IonQ pathway (Estimator-based in this app)
1579
+ try:
1580
+ from qiskit_ionq import IonQProvider
1581
+ except Exception:
1582
+ state.em_job_upload_error = "qiskit_ionq package not available. Please install it."
1583
+ state.em_job_is_processing = False
1584
+ return
1585
+
1586
+ ionq_token = os.environ.get("API_KEY_IONQ_EM")
1587
+ if not ionq_token or not str(ionq_token).strip():
1588
+ state.em_job_upload_error = "IonQ API token not found. Set API_KEY_IONQ_EM environment variable."
1589
+ state.em_job_is_processing = False
1590
+ return
1591
+ os.environ.setdefault("IONQ_API_TOKEN", ionq_token)
1592
+
1593
+ try:
1594
+ provider = IonQProvider()
1595
+ job = provider.retrieve_job(job_id)
1596
+ except Exception as e:
1597
+ state.em_job_upload_error = f"Failed to retrieve IonQ job: {e}"
1598
+ state.em_job_is_processing = False
1599
+ return
1600
+
1601
+ try:
1602
+ status = job.status()
1603
+ status_name = status.name if hasattr(status, "name") else str(status)
1604
+ if status_name not in ("DONE", "COMPLETED"):
1605
+ state.em_job_upload_error = f"Job is not complete. Current status: {status_name}"
1606
+ state.em_job_is_processing = False
1607
+ return
1608
+ except Exception:
1609
+ pass
1610
+
1611
+ try:
1612
+ res = job.result()
1613
+ if hasattr(res, "__iter__"):
1614
+ for pub in res:
1615
+ data = getattr(pub, "data", None)
1616
+ evs = getattr(data, "evs", None) if data is not None else None
1617
+ if evs is not None:
1618
+ z_exp = float(np.array(evs).reshape(-1)[0])
1619
+ field_values.append(float(np.sqrt((1 - z_exp) / 2)))
1620
+ elif hasattr(res, "data") and hasattr(res.data, "evs"):
1621
+ z_exp = float(np.array(res.data.evs).reshape(-1)[0])
1622
+ field_values.append(float(np.sqrt((1 - z_exp) / 2)))
1623
+ except Exception as e:
1624
+ state.em_job_upload_error = f"Failed to get job results: {e}"
1625
+ state.em_job_is_processing = False
1626
+ return
1627
 
1628
  if not field_values:
1629
+ state.em_job_upload_error = "No field values extracted from job. Ensure the job was submitted by the EM Estimator workflow."
1630
  state.em_job_is_processing = False
1631
  return
1632
 
 
1720
  state.qpu_plot_position_options = ["All positions", label]
1721
  state.qpu_plot_position_filter = "All positions"
1722
 
1723
+ state.em_job_upload_success = f"✓ Successfully processed {len(field_values)} time step(s) from {platform} job {job_id}"
1724
  log_to_console(f"Upload processing complete: {len(field_values)} points plotted")
 
 
 
 
1725
  except Exception as e:
1726
  state.em_job_upload_error = f"Error processing job result: {e}"
1727
  log_to_console(f"Processing error: {e}")
em/state.py CHANGED
@@ -298,12 +298,11 @@ def _init_state_defaults():
298
  "show_progress": False,
299
  "console_logs": "Console initialized...\n",
300
  # --- EM Job Upload State ---
301
- "em_job_upload": None,
302
- "em_job_upload_filename": "",
303
  "em_job_upload_error": "",
304
  "em_job_upload_success": "",
305
  "em_job_is_processing": False,
306
  "em_job_platform": "IBM",
 
307
  "em_job_field_type": "Ez",
308
  "em_job_monitor_point": "(0, 0)",
309
  "em_job_total_time": 1.0,
 
298
  "show_progress": False,
299
  "console_logs": "Console initialized...\n",
300
  # --- EM Job Upload State ---
 
 
301
  "em_job_upload_error": "",
302
  "em_job_upload_success": "",
303
  "em_job_is_processing": False,
304
  "em_job_platform": "IBM",
305
+ "em_job_id": "",
306
  "em_job_field_type": "Ez",
307
  "em_job_monitor_point": "(0, 0)",
308
  "em_job_total_time": 1.0,
em/ui.py CHANGED
@@ -494,100 +494,127 @@ def _build_output_preferences_card():
494
  def _build_job_upload_card():
495
  """Build the Job Result Upload card for loading previously saved QPU results."""
496
  with vuetify3.VCard(classes="mb-1", style="font-size: 0.8rem;"):
497
- with vuetify3.VCardTitle("Upload Job Results", classes="text-subtitle-1 text-primary", style="font-size: 0.9rem; padding: 6px 10px;"):
498
  pass
499
  with vuetify3.VCardText(classes="py-1 px-2"):
500
- trame_html.Div("Load previously saved IBM/IonQ QPU job results (JSON format)",
501
- classes="text-caption text-medium-emphasis mb-2")
502
-
503
- # Platform and Field Type row
504
- with vuetify3.VRow(dense=True, classes="mb-2"):
505
- with vuetify3.VCol(cols=6):
 
 
506
  vuetify3.VSelect(
 
507
  label="Platform",
508
  v_model=("em_job_platform", "IBM"),
509
  items=("['IBM', 'IonQ']",),
510
  density="compact",
511
  hide_details=True,
512
  color="primary",
 
 
513
  )
514
- with vuetify3.VCol(cols=6):
515
- vuetify3.VSelect(
516
- label="Field Type",
517
- v_model=("em_job_field_type", "Ez"),
518
- items=("['Ez', 'Hx', 'Hy']",),
519
- density="compact",
520
- hide_details=True,
521
- color="primary",
522
- )
523
-
524
- # Monitor position row
525
- with vuetify3.VRow(dense=True, classes="mb-2"):
526
- with vuetify3.VCol(cols=12):
527
  vuetify3.VTextField(
528
- label="Monitor Point (x, y)",
529
- v_model=("em_job_monitor_point", "(0, 0)"),
 
530
  density="compact",
531
  hide_details=True,
532
  color="primary",
533
- placeholder="(x, y)",
 
 
534
  )
535
-
536
- # Time and grid parameters row
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
537
  with vuetify3.VRow(dense=True, classes="mb-2"):
538
  with vuetify3.VCol(cols=4):
539
- vuetify3.VTextField(
540
- label="Total Time (T)",
541
- v_model=("em_job_total_time", 1.0),
542
- type="number",
543
- density="compact",
544
- hide_details=True,
545
- color="primary",
546
- )
547
- with vuetify3.VCol(cols=4):
548
- vuetify3.VTextField(
549
- label="Snapshot Δt",
550
- v_model=("em_job_snapshot_dt", 0.1),
551
- type="number",
552
- density="compact",
553
- hide_details=True,
554
- color="primary",
555
- )
556
  with vuetify3.VCol(cols=4):
557
- vuetify3.VTextField(
558
- label="No. of Points per Direction",
559
- v_model=("em_job_nx", 4),
560
- type="number",
561
- density="compact",
562
- hide_details=True,
563
- color="primary",
564
- )
565
-
566
- # File upload and Generate button
567
- with vuetify3.VRow(dense=True, classes="align-center mt-2"):
568
- with vuetify3.VCol(cols=8):
569
- vuetify3.VFileInput(
570
- label="Upload Job Result (JSON)",
571
- v_model=("em_job_upload", None),
572
- accept=".json",
573
- prepend_icon="mdi-file-upload",
574
- density="compact",
575
- hide_details=True,
576
- color="primary",
577
- show_size=True,
578
- clearable=True,
579
- )
580
  with vuetify3.VCol(cols=4):
581
- vuetify3.VBtn(
582
- text="Generate",
583
- color="secondary",
584
- variant="tonal",
585
- block=True,
586
- disabled=("!em_job_upload || em_job_is_processing", True),
587
- loading=("em_job_is_processing", False),
588
- click=process_uploaded_em_job_result,
589
- prepend_icon="mdi-chart-box-outline",
590
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
591
 
592
  # Success message
593
  vuetify3.VAlert(
 
494
  def _build_job_upload_card():
495
  """Build the Job Result Upload card for loading previously saved QPU results."""
496
  with vuetify3.VCard(classes="mb-1", style="font-size: 0.8rem;"):
497
+ with vuetify3.VCardTitle("Upload Results", classes="text-subtitle-1 text-primary", style="font-size: 0.9rem; padding: 6px 10px;"):
498
  pass
499
  with vuetify3.VCardText(classes="py-1 px-2"):
500
+ trame_html.Div(
501
+ "Retrieve completed job results from IBM or IonQ using the Job ID",
502
+ classes="text-caption text-medium-emphasis mb-2",
503
+ )
504
+
505
+ # Platform selector
506
+ with vuetify3.VTooltip(location="top"):
507
+ with vuetify3.Template(v_slot_activator="{ props }"):
508
  vuetify3.VSelect(
509
+ v_bind="props",
510
  label="Platform",
511
  v_model=("em_job_platform", "IBM"),
512
  items=("['IBM', 'IonQ']",),
513
  density="compact",
514
  hide_details=True,
515
  color="primary",
516
+ classes="mb-2",
517
+ prepend_icon="mdi-chip",
518
  )
519
+ trame_html.Span("Select the quantum hardware provider (IBM or IonQ)")
520
+
521
+ # Job ID input
522
+ with vuetify3.VTooltip(location="top"):
523
+ with vuetify3.Template(v_slot_activator="{ props }"):
 
 
 
 
 
 
 
 
524
  vuetify3.VTextField(
525
+ v_bind="props",
526
+ label="Job ID",
527
+ v_model=("em_job_id", ""),
528
  density="compact",
529
  hide_details=True,
530
  color="primary",
531
+ classes="mb-2",
532
+ placeholder="e.g., 019b368e-6e22-7525-8512-fd16e0503673",
533
+ prepend_icon="mdi-identifier",
534
  )
535
+ trame_html.Span("Enter the Job ID (UUID format from IBM or IonQ)")
536
+
537
+ # Field / monitor / time parameters
538
+ with vuetify3.VRow(dense=True, classes="mb-2"):
539
+ with vuetify3.VCol(cols=6):
540
+ with vuetify3.VTooltip(location="top"):
541
+ with vuetify3.Template(v_slot_activator="{ props }"):
542
+ vuetify3.VSelect(
543
+ v_bind="props",
544
+ label="Field Type",
545
+ v_model=("em_job_field_type", "Ez"),
546
+ items=("['Ez', 'Hx', 'Hy']",),
547
+ density="compact",
548
+ hide_details=True,
549
+ color="primary",
550
+ )
551
+ trame_html.Span("Select which field component to plot (Ez, Hx, Hy)")
552
+ with vuetify3.VCol(cols=6):
553
+ with vuetify3.VTooltip(location="top"):
554
+ with vuetify3.Template(v_slot_activator="{ props }"):
555
+ vuetify3.VTextField(
556
+ v_bind="props",
557
+ label="Monitor Point (x, y)",
558
+ v_model=("em_job_monitor_point", "(0, 0)"),
559
+ density="compact",
560
+ hide_details=True,
561
+ color="primary",
562
+ placeholder="(x, y)",
563
+ )
564
+ trame_html.Span("Integer grid indices of the monitor point")
565
+
566
  with vuetify3.VRow(dense=True, classes="mb-2"):
567
  with vuetify3.VCol(cols=4):
568
+ with vuetify3.VTooltip(location="top"):
569
+ with vuetify3.Template(v_slot_activator="{ props }"):
570
+ vuetify3.VTextField(
571
+ v_bind="props",
572
+ label="Total Time (T)",
573
+ v_model=("em_job_total_time", 1.0),
574
+ type="number",
575
+ density="compact",
576
+ hide_details=True,
577
+ color="primary",
578
+ )
579
+ trame_html.Span("Total simulation time")
 
 
 
 
 
580
  with vuetify3.VCol(cols=4):
581
+ with vuetify3.VTooltip(location="top"):
582
+ with vuetify3.Template(v_slot_activator="{ props }"):
583
+ vuetify3.VTextField(
584
+ v_bind="props",
585
+ label="Snapshot Δt",
586
+ v_model=("em_job_snapshot_dt", 0.1),
587
+ type="number",
588
+ density="compact",
589
+ hide_details=True,
590
+ color="primary",
591
+ )
592
+ trame_html.Span("Time between snapshots")
 
 
 
 
 
 
 
 
 
 
 
593
  with vuetify3.VCol(cols=4):
594
+ with vuetify3.VTooltip(location="top"):
595
+ with vuetify3.Template(v_slot_activator="{ props }"):
596
+ vuetify3.VTextField(
597
+ v_bind="props",
598
+ label="No. of Points per Direction",
599
+ v_model=("em_job_nx", 4),
600
+ type="number",
601
+ density="compact",
602
+ hide_details=True,
603
+ color="primary",
604
+ )
605
+ trame_html.Span("Grid dimension nx (grid is nx × nx)")
606
+
607
+ vuetify3.VBtn(
608
+ text="Retrieve & Generate Plot",
609
+ color="secondary",
610
+ variant="tonal",
611
+ block=True,
612
+ disabled=("!em_job_id || em_job_is_processing", True),
613
+ loading=("em_job_is_processing", False),
614
+ click=process_uploaded_em_job_result,
615
+ prepend_icon="mdi-chart-box-outline",
616
+ classes="mb-2",
617
+ )
618
 
619
  # Success message
620
  vuetify3.VAlert(
qlbm/qlbm_sample_app.py CHANGED
@@ -820,7 +820,7 @@ def run_sampling_hw_ionq(
820
  # IonQ job status polling
821
  last_status = None
822
  poll_count = 0
823
- max_polls = 600 # ~10 minutes with 1s interval
824
 
825
  while poll_count < max_polls:
826
  try:
 
820
  # IonQ job status polling
821
  last_status = None
822
  poll_count = 0
823
+ max_polls = 60000 # ~10 minutes with 1s interval
824
 
825
  while poll_count < max_polls:
826
  try: