Spaces:
Runtime error
Runtime error
Commit
·
c27d6ee
1
Parent(s):
2dbe6b1
pp now boots safely on Spaces without tripping the LLVM SmallVector assertion
Browse files
README.md
CHANGED
|
@@ -32,3 +32,19 @@ reverse proxy. Set the following environment variables (the Dockerfile already d
|
|
| 32 |
|
| 33 |
The bundled `docker/nginx.conf` proxies incoming traffic on `${PORT:-7860}` to the
|
| 34 |
individual services so the browser never tries to contact `127.0.0.1` directly.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
|
| 33 |
The bundled `docker/nginx.conf` proxies incoming traffic on `${PORT:-7860}` to the
|
| 34 |
individual services so the browser never tries to contact `127.0.0.1` directly.
|
| 35 |
+
|
| 36 |
+
## CUDA-Q backend on CPU-only hosts
|
| 37 |
+
|
| 38 |
+
The 3D lattice Boltzmann solver relies on CUDA-Q, which expects a CUDA-capable GPU.
|
| 39 |
+
CPU-only runtimes such as Hugging Face Spaces will now automatically skip loading the
|
| 40 |
+
quantum backend so the UI can still boot. Use the following environment variables to
|
| 41 |
+
override the default:
|
| 42 |
+
|
| 43 |
+
| Variable | Effect |
|
| 44 |
+
| --- | --- |
|
| 45 |
+
| `DISABLE_CUDAQ=1` | Force-disable the CUDA-Q backend regardless of GPU availability. |
|
| 46 |
+
| `FORCE_ENABLE_CUDAQ=1` | Attempt to load the CUDA-Q backend even if the platform was auto-detected as CPU-only. |
|
| 47 |
+
|
| 48 |
+
When the backend is disabled the "Run Simulation" button is greyed out and a warning
|
| 49 |
+
appears in the UI explaining why. Run the app locally on a CUDA-enabled machine and
|
| 50 |
+
set `FORCE_ENABLE_CUDAQ=1` if you still want to attempt a run on a constrained host.
|
qlbm.py
CHANGED
|
@@ -1,18 +1,9 @@
|
|
| 1 |
import os
|
| 2 |
os.environ["OMP_NUM_THREADS"] = "1"
|
| 3 |
|
| 4 |
-
# Defer cudaq import to avoid LLVM crash on CPU-only environments
|
| 5 |
-
_cudaq_available = False
|
| 6 |
-
try:
|
| 7 |
-
import cudaq
|
| 8 |
-
_cudaq_available = True
|
| 9 |
-
except ImportError:
|
| 10 |
-
pass
|
| 11 |
-
|
| 12 |
import numpy as np
|
| 13 |
import math
|
| 14 |
import time
|
| 15 |
-
import shutil
|
| 16 |
import plotly.graph_objects as go
|
| 17 |
import pyvista as pv
|
| 18 |
from trame.app import get_server
|
|
@@ -22,46 +13,61 @@ from trame.widgets import html # <--- IMPORT ADDED HERE
|
|
| 22 |
from trame_plotly.widgets import plotly as plotly_widgets
|
| 23 |
from pyvista.trame.ui import plotter_ui
|
| 24 |
|
| 25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
simulate_qlbm_3D_and_animate = None
|
|
|
|
| 27 |
|
| 28 |
-
|
| 29 |
-
"""Check if NVIDIA GPU is available."""
|
| 30 |
-
nvidia_devices = os.environ.get("NVIDIA_VISIBLE_DEVICES")
|
| 31 |
-
cuda_devices = os.environ.get("CUDA_VISIBLE_DEVICES")
|
| 32 |
-
|
| 33 |
-
def _has_devices(val):
|
| 34 |
-
if not val:
|
| 35 |
-
return False
|
| 36 |
-
return val.strip().lower() not in ("", "none", "nodevfiles", "-1")
|
| 37 |
-
|
| 38 |
-
has_env = _has_devices(nvidia_devices) or _has_devices(cuda_devices)
|
| 39 |
-
has_proc = os.path.exists("/proc/driver/nvidia/version")
|
| 40 |
-
has_smi = shutil.which("nvidia-smi") is not None
|
| 41 |
-
return has_env or has_proc or has_smi
|
| 42 |
-
|
| 43 |
-
def _lazy_import_simulation():
|
| 44 |
-
"""Lazily import simulation module only when GPU is available."""
|
| 45 |
-
global simulate_qlbm_3D_and_animate
|
| 46 |
-
if simulate_qlbm_3D_and_animate is not None:
|
| 47 |
-
return simulate_qlbm_3D_and_animate
|
| 48 |
-
|
| 49 |
-
if not _detect_gpu_available():
|
| 50 |
-
print("Warning: No GPU detected, simulation module not loaded.")
|
| 51 |
-
return None
|
| 52 |
-
|
| 53 |
try:
|
| 54 |
-
from fluid3d_pyvista import simulate_qlbm_3D_and_animate
|
| 55 |
-
simulate_qlbm_3D_and_animate = sim_func
|
| 56 |
-
return sim_func
|
| 57 |
except ImportError:
|
| 58 |
try:
|
| 59 |
-
from quantum.fluid3d_pyvista import simulate_qlbm_3D_and_animate
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
print("Warning:
|
| 64 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
|
| 66 |
# --- Server Setup ---
|
| 67 |
server = get_server()
|
|
@@ -115,6 +121,8 @@ state.update({
|
|
| 115 |
"simulation_has_run": False,
|
| 116 |
"time_val": 0,
|
| 117 |
"max_time_step": 0,
|
|
|
|
|
|
|
| 118 |
# Workflow guidance styles
|
| 119 |
"workflow_step": 0,
|
| 120 |
"overview_card_style": _WORKFLOW_BASE_STYLE,
|
|
@@ -508,13 +516,8 @@ def update_geometry_view():
|
|
| 508 |
def run_simulation():
|
| 509 |
global simulation_data_frames, simulation_times, current_grid_object
|
| 510 |
|
| 511 |
-
|
| 512 |
-
|
| 513 |
-
if sim_func is None:
|
| 514 |
-
if not _detect_gpu_available():
|
| 515 |
-
state.run_error = "Simulation requires NVIDIA GPU which is not available in this environment."
|
| 516 |
-
else:
|
| 517 |
-
state.run_error = "Simulation module not found."
|
| 518 |
return
|
| 519 |
|
| 520 |
state.is_running = True
|
|
@@ -537,7 +540,7 @@ def run_simulation():
|
|
| 537 |
# 2. Run Simulation
|
| 538 |
# Note: simulate_qlbm_3D_and_animate updates the passed plotter with the first frame
|
| 539 |
plotter.clear()
|
| 540 |
-
_, frames, times, grid_obj =
|
| 541 |
num_reg_qubits=num_reg_qubits,
|
| 542 |
T=T,
|
| 543 |
distribution_type=distribution_type,
|
|
@@ -1004,10 +1007,18 @@ with SinglePageLayout(server) as layout:
|
|
| 1004 |
text="Run Simulation",
|
| 1005 |
color="primary",
|
| 1006 |
block=True,
|
| 1007 |
-
disabled=("is_running", False),
|
| 1008 |
click=run_simulation,
|
| 1009 |
style=("is_running ? '' : 'background-color:#87CEFA;'", ""),
|
| 1010 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1011 |
with vuetify3.VRow(dense=True, classes="mt-2"):
|
| 1012 |
with vuetify3.VCol(cols=6):
|
| 1013 |
vuetify3.VBtn(
|
|
|
|
| 1 |
import os
|
| 2 |
os.environ["OMP_NUM_THREADS"] = "1"
|
| 3 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
import numpy as np
|
| 5 |
import math
|
| 6 |
import time
|
|
|
|
| 7 |
import plotly.graph_objects as go
|
| 8 |
import pyvista as pv
|
| 9 |
from trame.app import get_server
|
|
|
|
| 13 |
from trame_plotly.widgets import plotly as plotly_widgets
|
| 14 |
from pyvista.trame.ui import plotter_ui
|
| 15 |
|
| 16 |
+
|
| 17 |
+
def _env_flag(name: str) -> bool:
|
| 18 |
+
value = os.environ.get(name)
|
| 19 |
+
return str(value).lower() in {"1", "true", "yes", "on"} if value is not None else False
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def _should_disable_quantum_backend():
|
| 23 |
+
if _env_flag("FORCE_ENABLE_CUDAQ"):
|
| 24 |
+
return False, ""
|
| 25 |
+
|
| 26 |
+
reasons = []
|
| 27 |
+
if _env_flag("DISABLE_CUDAQ"):
|
| 28 |
+
reasons.append("disabled via DISABLE_CUDAQ=1")
|
| 29 |
+
|
| 30 |
+
hf_space = os.environ.get("SPACE_ID") or os.environ.get("HF_SPACE_ID")
|
| 31 |
+
if hf_space:
|
| 32 |
+
reasons.append("running inside Hugging Face Spaces (CPU runtime)")
|
| 33 |
+
|
| 34 |
+
cuda_visible = os.environ.get("CUDA_VISIBLE_DEVICES")
|
| 35 |
+
if cuda_visible is not None and cuda_visible.strip() in {"", "-1"}:
|
| 36 |
+
reasons.append("no CUDA device exposed (CUDA_VISIBLE_DEVICES is empty)")
|
| 37 |
+
|
| 38 |
+
nvidia_visible = os.environ.get("NVIDIA_VISIBLE_DEVICES")
|
| 39 |
+
if nvidia_visible is not None and nvidia_visible.strip() in {"", "void"}:
|
| 40 |
+
reasons.append("no NVIDIA device exposed (NVIDIA_VISIBLE_DEVICES is empty)")
|
| 41 |
+
|
| 42 |
+
if reasons:
|
| 43 |
+
msg = "; ".join(reasons)
|
| 44 |
+
return True, f"Quantum backend disabled because {msg}. Set FORCE_ENABLE_CUDAQ=1 to override."
|
| 45 |
+
|
| 46 |
+
return False, ""
|
| 47 |
+
|
| 48 |
+
|
| 49 |
simulate_qlbm_3D_and_animate = None
|
| 50 |
+
_SIMULATION_BACKEND_DISABLED, _SIMULATION_DISABLED_REASON = _should_disable_quantum_backend()
|
| 51 |
|
| 52 |
+
if not _SIMULATION_BACKEND_DISABLED:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 53 |
try:
|
| 54 |
+
from fluid3d_pyvista import simulate_qlbm_3D_and_animate # type: ignore
|
|
|
|
|
|
|
| 55 |
except ImportError:
|
| 56 |
try:
|
| 57 |
+
from quantum.fluid3d_pyvista import simulate_qlbm_3D_and_animate # type: ignore
|
| 58 |
+
except ImportError as exc:
|
| 59 |
+
_SIMULATION_DISABLED_REASON = "Simulation module not found."
|
| 60 |
+
simulate_qlbm_3D_and_animate = None
|
| 61 |
+
print(f"Warning: {exc}")
|
| 62 |
+
except Exception as exc: # pragma: no cover - defensive guard for HF runtime
|
| 63 |
+
_SIMULATION_DISABLED_REASON = f"Failed to load CUDA-Q backend: {exc}"
|
| 64 |
+
simulate_qlbm_3D_and_animate = None
|
| 65 |
+
else:
|
| 66 |
+
_SIMULATION_DISABLED_REASON = _SIMULATION_DISABLED_REASON or "Quantum backend disabled by environment settings."
|
| 67 |
+
|
| 68 |
+
_SIMULATION_BACKEND_READY = simulate_qlbm_3D_and_animate is not None
|
| 69 |
+
if not _SIMULATION_BACKEND_READY and _SIMULATION_DISABLED_REASON:
|
| 70 |
+
print(f"Warning: {_SIMULATION_DISABLED_REASON}")
|
| 71 |
|
| 72 |
# --- Server Setup ---
|
| 73 |
server = get_server()
|
|
|
|
| 121 |
"simulation_has_run": False,
|
| 122 |
"time_val": 0,
|
| 123 |
"max_time_step": 0,
|
| 124 |
+
"simulation_backend_ready": _SIMULATION_BACKEND_READY,
|
| 125 |
+
"simulation_disabled_reason": _SIMULATION_DISABLED_REASON,
|
| 126 |
# Workflow guidance styles
|
| 127 |
"workflow_step": 0,
|
| 128 |
"overview_card_style": _WORKFLOW_BASE_STYLE,
|
|
|
|
| 516 |
def run_simulation():
|
| 517 |
global simulation_data_frames, simulation_times, current_grid_object
|
| 518 |
|
| 519 |
+
if simulate_qlbm_3D_and_animate is None:
|
| 520 |
+
state.run_error = _SIMULATION_DISABLED_REASON or "Simulation module is not available on this platform."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 521 |
return
|
| 522 |
|
| 523 |
state.is_running = True
|
|
|
|
| 540 |
# 2. Run Simulation
|
| 541 |
# Note: simulate_qlbm_3D_and_animate updates the passed plotter with the first frame
|
| 542 |
plotter.clear()
|
| 543 |
+
_, frames, times, grid_obj = simulate_qlbm_3D_and_animate(
|
| 544 |
num_reg_qubits=num_reg_qubits,
|
| 545 |
T=T,
|
| 546 |
distribution_type=distribution_type,
|
|
|
|
| 1007 |
text="Run Simulation",
|
| 1008 |
color="primary",
|
| 1009 |
block=True,
|
| 1010 |
+
disabled=("is_running || !simulation_backend_ready", False),
|
| 1011 |
click=run_simulation,
|
| 1012 |
style=("is_running ? '' : 'background-color:#87CEFA;'", ""),
|
| 1013 |
)
|
| 1014 |
+
vuetify3.VAlert(
|
| 1015 |
+
v_if="simulation_disabled_reason",
|
| 1016 |
+
type="warning",
|
| 1017 |
+
variant="tonal",
|
| 1018 |
+
density="compact",
|
| 1019 |
+
children=["{{ simulation_disabled_reason }}"],
|
| 1020 |
+
classes="mt-2",
|
| 1021 |
+
)
|
| 1022 |
with vuetify3.VRow(dense=True, classes="mt-2"):
|
| 1023 |
with vuetify3.VCol(cols=6):
|
| 1024 |
vuetify3.VBtn(
|