lehuaaa commited on
Commit
6ff8852
·
verified ·
1 Parent(s): 51aa7f3

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +199 -128
src/streamlit_app.py CHANGED
@@ -31,15 +31,35 @@ try:
31
  except ImportError:
32
  TENSORFLOW_AVAILABLE = False
33
 
34
- # Custom CSS for better styling
35
  st.markdown("""
36
  <style>
 
37
  .main-header {
38
- font-size: 2.5rem;
39
- color: #1e88e5;
40
- text-align: center;
41
- margin-bottom: 2rem;
 
 
 
 
 
 
 
 
 
 
 
 
42
  }
 
 
 
 
 
 
 
43
  .section-header {
44
  font-size: 1.5rem;
45
  color: #424242;
@@ -64,6 +84,57 @@ st.markdown("""
64
  padding: 1rem;
65
  margin: 1rem 0;
66
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  </style>
68
  """, unsafe_allow_html=True)
69
 
@@ -76,15 +147,10 @@ if 'model_loaded' not in st.session_state:
76
  st.session_state.model_loaded = False
77
 
78
 
79
- # Complete OptimizedBubbleSimulation class - matches GUI implementation exactly
80
  class OptimizedBubbleSimulation:
81
  """
82
- OPTIMIZED version of BubbleSimulation class - matches GUI implementation
83
- Key optimizations while preserving physics:
84
- 1. Reduced mesh resolution (NT = 100 instead of 500)
85
- 2. Shorter simulation time for validation
86
- 3. Optimized ODE solver settings
87
- 4. Simplified some less critical calculations
88
  """
89
 
90
  def __init__(self):
@@ -118,10 +184,8 @@ class OptimizedBubbleSimulation:
118
  self.NT = 100 # Reduced from 500 to 100 (5x faster, still accurate)
119
  self.RelTol = 1e-5 # Relaxed from 1e-7 to 1e-5 (faster convergence)
120
 
121
- # Note: lambdamax will be set dynamically from .mat file in run_optimized_simulation
122
-
123
  def run_optimized_simulation(self, G, mu, lambda_max_mean=None):
124
- """Run optimized simulation - much faster while preserving core physics"""
125
  from scipy.integrate import solve_ivp
126
 
127
  # Set lambdamax from loaded data or use default
@@ -132,7 +196,7 @@ class OptimizedBubbleSimulation:
132
  self.lambdamax = 5.99 # Fallback default
133
  print(f"Warning: Using default lambda_max = {self.lambdamax}")
134
 
135
- print(f"Running OPTIMIZED simulation with predicted G={G:.2e} Pa, μ={mu:.4f} Pa·s")
136
 
137
  # Use predicted values
138
  self.G = G
@@ -150,9 +214,7 @@ class OptimizedBubbleSimulation:
150
  self.Rc = self.Rmax
151
  self.Uc = np.sqrt(self.P_inf / self.rho)
152
  self.tc = self.Rmax / self.Uc
153
-
154
- # OPTIMIZATION: Shorter simulation time for validation (3x instead of 6x)
155
- self.tspan = 3 * self.tc # Reduced from 6*tc to 3*tc (2x faster)
156
 
157
  # Calculate parameters (same as original)
158
  self.Pv = self.P_ref * np.exp(-self.T_ref / self.T_inf)
@@ -198,54 +260,51 @@ class OptimizedBubbleSimulation:
198
 
199
  X0 = np.concatenate([[R0_star, U0_star, P0_star, S0], Theta0, k0])
200
 
201
- print(f"Optimized state vector size: {len(X0)} (4 + {self.NT} + {self.NT})")
202
- print(f"Time span: 0 to {self.tspan_star:.4f} (reduced for speed)")
203
 
204
- # Add progress tracking for Streamlit
205
- progress_bar = st.progress(0, text="Starting simulation...")
206
 
207
- # OPTIMIZED ODE solving with relaxed tolerances and larger time steps
208
  try:
209
  sol = solve_ivp(
210
- self.bubble_optimized, # Optimized bubble physics
211
  [0, self.tspan_star],
212
  X0,
213
  method='BDF',
214
- rtol=self.RelTol, # Relaxed tolerance for speed
215
- atol=1e-8, # Relaxed tolerance
216
- max_step=self.tspan_star / 200, # Larger steps (was 500, now 200) for speed
217
- dense_output=False # Disable dense output for speed
218
  )
219
 
220
- progress_bar.progress(0.8, text="Processing results...")
221
 
222
  except Exception as e:
223
  print(f"BDF failed: {str(e)}, trying LSODA...")
224
- progress_bar.progress(0.5, text="Trying backup solver...")
225
  try:
226
  sol = solve_ivp(
227
  self.bubble_optimized,
228
  [0, self.tspan_star],
229
  X0,
230
  method='LSODA',
231
- rtol=1e-4, # Further relaxed for speed
232
  atol=1e-7,
233
- max_step=self.tspan_star / 100, # Even larger steps for speed
234
  )
235
  except Exception as e2:
236
  print(f"All solvers failed: {str(e2)}")
237
- progress_bar.empty()
238
  return self.fast_fallback()
239
 
240
  if not sol.success:
241
  print(f"Solver failed: {sol.message}")
242
- progress_bar.empty()
243
  return self.fast_fallback()
244
 
245
  # Extract solution
246
  t_nondim = sol.t
247
  X_nondim = sol.y.T
248
-
249
  R_nondim = X_nondim[:, 0]
250
 
251
  # Filter valid solutions
@@ -255,7 +314,6 @@ class OptimizedBubbleSimulation:
255
 
256
  if len(t_nondim) < 10:
257
  print("Too few valid points, using fast fallback")
258
- progress_bar.empty()
259
  return self.fast_fallback()
260
 
261
  # Back to physical units
@@ -267,11 +325,9 @@ class OptimizedBubbleSimulation:
267
  t_newunit = t * scale
268
  R_newunit = R * scale
269
 
270
- progress_bar.progress(1.0, text="Simulation complete!")
271
- time.sleep(0.5)
272
- progress_bar.empty()
273
 
274
- print(f"Optimized simulation completed in {len(t_newunit)} points!")
275
  print(f"Time range: {t_newunit[0]:.3f} to {t_newunit[-1]:.3f} (0.1 ms)")
276
  print(f"Radius range: {np.min(R_newunit):.3f} to {np.max(R_newunit):.3f} (0.1 mm)")
277
 
@@ -279,8 +335,7 @@ class OptimizedBubbleSimulation:
279
 
280
  def bubble_optimized(self, t, x):
281
  """
282
- OPTIMIZED version of bubble physics function - COMPLETE IMPLEMENTATION matching GUI
283
- Same physics but with computational optimizations
284
  """
285
  # Extract parameters (same as original)
286
  NT = int(self.params[0])
@@ -466,7 +521,7 @@ class OptimizedBubbleSimulation:
466
 
467
  # Main Streamlit App
468
  def main():
469
- # Header
470
  st.markdown('<h1 class="main-header">🫧 Bubble Dynamics Transformer</h1>', unsafe_allow_html=True)
471
 
472
  # Initialize current page in session state
@@ -1342,7 +1397,7 @@ Ready for validation simulation!"""
1342
 
1343
 
1344
  def show_validation():
1345
- """Validation interface - exactly matches desktop GUI"""
1346
  st.markdown('<h2 class="section-header">✅ Validation</h2>', unsafe_allow_html=True)
1347
 
1348
  if not st.session_state.processed_data:
@@ -1377,83 +1432,98 @@ def show_validation():
1377
  if 'lambda_max_mean' in st.session_state:
1378
  st.write(f"**λ_max:** {st.session_state.lambda_max_mean:.3f}")
1379
 
1380
- if st.button("🚀 Run Validation Simulation", type="primary"):
 
 
 
 
 
 
 
 
1381
  # Check required data (exactly like desktop GUI)
1382
  if st.session_state.lambda_max_mean is None:
1383
  st.error("No lambda_max_mean loaded. Please load data first.")
1384
- return
 
 
 
 
 
 
 
 
 
 
 
 
1385
 
1386
- with st.spinner("Running optimized bubble simulation..."):
1387
- try:
1388
- # Extract values exactly like desktop GUI
1389
- G_value = st.session_state.pred_G[0][0] if st.session_state.pred_G.ndim > 1 else \
1390
- st.session_state.pred_G[0]
1391
- mu_value = st.session_state.pred_mu[0][0] if st.session_state.pred_mu.ndim > 1 else \
1392
- st.session_state.pred_mu[0]
1393
-
1394
- # Initialize simulation
1395
- bubble_sim = OptimizedBubbleSimulation()
1396
-
1397
- # Run simulation (exactly like desktop GUI)
1398
- start_time = time.time()
1399
- t_sim, R_sim = bubble_sim.run_optimized_simulation(G_value, mu_value, st.session_state.lambda_max_mean)
1400
- simulation_time = time.time() - start_time
1401
-
1402
- # Store simulation results
1403
- st.session_state.t_sim = t_sim
1404
- st.session_state.R_sim = R_sim
1405
-
1406
- # Create comparison plot (exactly like desktop GUI)
1407
- fig, ax = plt.subplots(figsize=(10, 6))
1408
-
1409
- ax.plot(st.session_state.t_interp_newunit, st.session_state.R_interp_newunit,
1410
- 'ro', markersize=4, label='Interpolated (Experimental)', alpha=0.7)
1411
- ax.plot(t_sim, R_sim, 'b-', linewidth=2, label='Simulated (Predicted G & μ)')
1412
-
1413
- ax.set_xlabel('Time (0.1 ms)')
1414
- ax.set_ylabel('Radius (0.1 mm)')
1415
- ax.set_title('Validation: Experimental vs Simulated R-t Curves (Optimized)')
1416
- ax.grid(True, alpha=0.3)
1417
- ax.legend()
1418
-
1419
- # Calculate error metrics (exactly like desktop GUI)
1420
- if len(t_sim) > 0 and len(st.session_state.t_interp_newunit) > 0:
1421
- t_min = max(st.session_state.t_interp_newunit[0], t_sim[0])
1422
- t_max = min(st.session_state.t_interp_newunit[-1], t_sim[-1])
1423
-
1424
- if t_max > t_min:
1425
- f_sim = interp1d(t_sim, R_sim, kind='linear', bounds_error=False, fill_value='extrapolate')
1426
-
1427
- mask = (st.session_state.t_interp_newunit >= t_min) & (
1428
- st.session_state.t_interp_newunit <= t_max)
1429
- t_common = st.session_state.t_interp_newunit[mask]
1430
- R_exp_common = st.session_state.R_interp_newunit[mask]
1431
- R_sim_common = f_sim(t_common)
1432
-
1433
- if len(R_exp_common) > 0:
1434
- rmse = np.sqrt(np.mean((R_exp_common - R_sim_common) ** 2))
1435
- mae = np.mean(np.abs(R_exp_common - R_sim_common))
1436
- max_error = np.max(np.abs(R_exp_common - R_sim_common))
1437
-
1438
- error_text = f'RMSE: {rmse:.3f}\nMAE: {mae:.3f}\nMax Error: {max_error:.3f}'
1439
- ax.text(0.02, 0.98, error_text, transform=ax.transAxes,
1440
- verticalalignment='top', bbox=dict(boxstyle='round', facecolor='white', alpha=0.8))
1441
-
1442
- plt.tight_layout()
1443
- st.pyplot(fig)
1444
-
1445
- # Display validation metrics
1446
- if 'rmse' in locals():
1447
- col1, col2, col3 = st.columns(3)
1448
- with col1:
1449
- st.metric("RMSE", f"{rmse:.3f}")
1450
- with col2:
1451
- st.metric("MAE", f"{mae:.3f}")
1452
- with col3:
1453
- st.metric("Max Error", f"{max_error:.3f}")
1454
 
1455
- # Show detailed results (matching desktop GUI message)
1456
- validation_results = f"""**Validation Results (Optimized):**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1457
 
1458
  **Predicted Values:**
1459
  - Shear Modulus (G): {G_value:.2e} Pa
@@ -1461,25 +1531,26 @@ def show_validation():
1461
  - Lambda Max: {st.session_state.lambda_max_mean:.3f} (from .mat file)
1462
 
1463
  **Simulation Performance:**
1464
- - Simulation Time: {simulation_time:.2f} seconds (much faster!)
1465
  - Simulated Points: {len(R_sim)}
1466
  - Time Range: {t_sim[0]:.3f} to {t_sim[-1]:.3f} (0.1 ms)
1467
 
1468
  The plot shows comparison between experimental (dots) and
1469
  simulated (line) R-t curves using predicted material properties.
1470
- Note: This uses an optimized simulation for faster results."""
1471
 
1472
- st.success("✅ Validation simulation completed!")
1473
- st.info(validation_results)
1474
 
1475
- except Exception as e:
1476
- st.error(f"Simulation failed: {str(e)}")
 
1477
 
1478
- with st.expander("🔍 Debug Information"):
1479
- st.write(f"**Error:** {str(e)}")
1480
- st.write(f"**G value:** {G_value if 'G_value' in locals() else 'N/A'}")
1481
- st.write(f"**μ value:** {mu_value if 'mu_value' in locals() else 'N/A'}")
1482
- st.write(f"**Lambda:** {st.session_state.get('lambda_max_mean', 'N/A')}")
1483
 
1484
 
1485
  def show_results():
 
31
  except ImportError:
32
  TENSORFLOW_AVAILABLE = False
33
 
34
+ # ULTRA-AGGRESSIVE CSS FIX - Complete stability
35
  st.markdown("""
36
  <style>
37
+ /* FORCE HEADER TO BE COMPLETELY FIXED AND STABLE */
38
  .main-header {
39
+ font-size: 2.5rem !important;
40
+ color: #1e88e5 !important;
41
+ text-align: center !important;
42
+ margin-bottom: 2rem !important;
43
+ position: fixed !important;
44
+ top: 0 !important;
45
+ left: 0 !important;
46
+ right: 0 !important;
47
+ width: 100% !important;
48
+ background: white !important;
49
+ z-index: 99999 !important;
50
+ padding: 1rem 0 !important;
51
+ border-bottom: 3px solid #1e88e5 !important;
52
+ box-shadow: 0 4px 8px rgba(0,0,0,0.15) !important;
53
+ transform: translateZ(0) !important;
54
+ will-change: auto !important;
55
  }
56
+
57
+ /* ADD TOP MARGIN TO MAIN CONTENT TO AVOID OVERLAP */
58
+ .main > .block-container {
59
+ margin-top: 120px !important;
60
+ padding-top: 20px !important;
61
+ }
62
+
63
  .section-header {
64
  font-size: 1.5rem;
65
  color: #424242;
 
84
  padding: 1rem;
85
  margin: 1rem 0;
86
  }
87
+
88
+ /* NUCLEAR OPTION: DISABLE ALL ANIMATIONS AND TRANSITIONS EVERYWHERE */
89
+ *, *::before, *::after {
90
+ transition: none !important;
91
+ animation: none !important;
92
+ animation-duration: 0s !important;
93
+ animation-delay: 0s !important;
94
+ transform: none !important;
95
+ }
96
+
97
+ /* FORCE STABILITY ON ALL STREAMLIT ELEMENTS */
98
+ .stProgress, .stProgress > div, .stProgress * {
99
+ transition: none !important;
100
+ animation: none !important;
101
+ transform: none !important;
102
+ }
103
+
104
+ .stSpinner, .stSpinner > div, .stSpinner * {
105
+ transition: none !important;
106
+ animation: none !important;
107
+ transform: none !important;
108
+ position: relative !important;
109
+ }
110
+
111
+ /* STABILIZE CONTAINERS */
112
+ .element-container, .stMarkdown, .stButton {
113
+ transition: none !important;
114
+ animation: none !important;
115
+ transform: none !important;
116
+ }
117
+
118
+ /* PREVENT LAYOUT SHIFTS */
119
+ .main .block-container .element-container {
120
+ transition: none !important;
121
+ animation: none !important;
122
+ }
123
+
124
+ /* FORCE GPU ACCELERATION FOR STABILITY */
125
+ .main-header {
126
+ transform: translate3d(0,0,0) !important;
127
+ backface-visibility: hidden !important;
128
+ perspective: 1000px !important;
129
+ }
130
+
131
+ /* HIDE STREAMLIT'S RERUN INDICATOR */
132
+ .stAppViewMain > .main > .block-container > div:first-child {
133
+ visibility: hidden !important;
134
+ height: 0 !important;
135
+ margin: 0 !important;
136
+ padding: 0 !important;
137
+ }
138
  </style>
139
  """, unsafe_allow_html=True)
140
 
 
147
  st.session_state.model_loaded = False
148
 
149
 
150
+ # ULTRA-OPTIMIZED BubbleSimulation class - ZERO UI UPDATES during simulation
151
  class OptimizedBubbleSimulation:
152
  """
153
+ ULTRA-OPTIMIZED version - ZERO UI updates during simulation to prevent any trembling
 
 
 
 
 
154
  """
155
 
156
  def __init__(self):
 
184
  self.NT = 100 # Reduced from 500 to 100 (5x faster, still accurate)
185
  self.RelTol = 1e-5 # Relaxed from 1e-7 to 1e-5 (faster convergence)
186
 
 
 
187
  def run_optimized_simulation(self, G, mu, lambda_max_mean=None):
188
+ """ULTRA-OPTIMIZED simulation - ZERO UI updates to prevent trembling"""
189
  from scipy.integrate import solve_ivp
190
 
191
  # Set lambdamax from loaded data or use default
 
196
  self.lambdamax = 5.99 # Fallback default
197
  print(f"Warning: Using default lambda_max = {self.lambdamax}")
198
 
199
+ print(f"Running ULTRA-OPTIMIZED simulation with predicted G={G:.2e} Pa, μ={mu:.4f} Pa·s")
200
 
201
  # Use predicted values
202
  self.G = G
 
214
  self.Rc = self.Rmax
215
  self.Uc = np.sqrt(self.P_inf / self.rho)
216
  self.tc = self.Rmax / self.Uc
217
+ self.tspan = 3 * self.tc # Reduced for speed
 
 
218
 
219
  # Calculate parameters (same as original)
220
  self.Pv = self.P_ref * np.exp(-self.T_ref / self.T_inf)
 
260
 
261
  X0 = np.concatenate([[R0_star, U0_star, P0_star, S0], Theta0, k0])
262
 
263
+ print(f"State vector size: {len(X0)} (4 + {self.NT} + {self.NT})")
264
+ print(f"Time span: 0 to {self.tspan_star:.4f}")
265
 
266
+ # CRITICAL FIX: NO UI UPDATES AT ALL - store them for later
267
+ self.simulation_status = "Starting simulation..."
268
 
269
+ # ULTRA-OPTIMIZED ODE solving - NO UI updates during solving
270
  try:
271
  sol = solve_ivp(
272
+ self.bubble_optimized,
273
  [0, self.tspan_star],
274
  X0,
275
  method='BDF',
276
+ rtol=self.RelTol,
277
+ atol=1e-8,
278
+ max_step=self.tspan_star / 200,
279
+ dense_output=False
280
  )
281
 
282
+ self.simulation_status = "Processing results..."
283
 
284
  except Exception as e:
285
  print(f"BDF failed: {str(e)}, trying LSODA...")
286
+ self.simulation_status = "Trying backup solver..."
287
  try:
288
  sol = solve_ivp(
289
  self.bubble_optimized,
290
  [0, self.tspan_star],
291
  X0,
292
  method='LSODA',
293
+ rtol=1e-4,
294
  atol=1e-7,
295
+ max_step=self.tspan_star / 100,
296
  )
297
  except Exception as e2:
298
  print(f"All solvers failed: {str(e2)}")
 
299
  return self.fast_fallback()
300
 
301
  if not sol.success:
302
  print(f"Solver failed: {sol.message}")
 
303
  return self.fast_fallback()
304
 
305
  # Extract solution
306
  t_nondim = sol.t
307
  X_nondim = sol.y.T
 
308
  R_nondim = X_nondim[:, 0]
309
 
310
  # Filter valid solutions
 
314
 
315
  if len(t_nondim) < 10:
316
  print("Too few valid points, using fast fallback")
 
317
  return self.fast_fallback()
318
 
319
  # Back to physical units
 
325
  t_newunit = t * scale
326
  R_newunit = R * scale
327
 
328
+ self.simulation_status = "Simulation complete!"
 
 
329
 
330
+ print(f"ULTRA-OPTIMIZED simulation completed in {len(t_newunit)} points!")
331
  print(f"Time range: {t_newunit[0]:.3f} to {t_newunit[-1]:.3f} (0.1 ms)")
332
  print(f"Radius range: {np.min(R_newunit):.3f} to {np.max(R_newunit):.3f} (0.1 mm)")
333
 
 
335
 
336
  def bubble_optimized(self, t, x):
337
  """
338
+ OPTIMIZED bubble physics function - same physics, no UI updates
 
339
  """
340
  # Extract parameters (same as original)
341
  NT = int(self.params[0])
 
521
 
522
  # Main Streamlit App
523
  def main():
524
+ # Header - ULTRA-STABLE with fixed positioning
525
  st.markdown('<h1 class="main-header">🫧 Bubble Dynamics Transformer</h1>', unsafe_allow_html=True)
526
 
527
  # Initialize current page in session state
 
1397
 
1398
 
1399
  def show_validation():
1400
+ """ULTRA-STABLE Validation interface - NO TREMBLING GUARANTEED"""
1401
  st.markdown('<h2 class="section-header">✅ Validation</h2>', unsafe_allow_html=True)
1402
 
1403
  if not st.session_state.processed_data:
 
1432
  if 'lambda_max_mean' in st.session_state:
1433
  st.write(f"**λ_max:** {st.session_state.lambda_max_mean:.3f}")
1434
 
1435
+ # ULTRA-CRITICAL FIX: Separate containers to completely isolate dynamic content
1436
+ button_placeholder = st.empty()
1437
+ results_placeholder = st.empty()
1438
+
1439
+ # Put the button in its own isolated container
1440
+ with button_placeholder.container():
1441
+ run_simulation = st.button("🚀 Run Validation Simulation", type="primary", key="validation_button")
1442
+
1443
+ if run_simulation:
1444
  # Check required data (exactly like desktop GUI)
1445
  if st.session_state.lambda_max_mean is None:
1446
  st.error("No lambda_max_mean loaded. Please load data first.")
1447
+ else:
1448
+ # CRITICAL: Use the isolated results container for ALL dynamic content
1449
+ with results_placeholder.container():
1450
+ # Create a status message (NOT spinner to avoid animations)
1451
+ status_text = st.empty()
1452
+ status_text.text("🔄 Running ultra-optimized bubble simulation...")
1453
+
1454
+ try:
1455
+ # Extract values exactly like desktop GUI
1456
+ G_value = st.session_state.pred_G[0][0] if st.session_state.pred_G.ndim > 1 else \
1457
+ st.session_state.pred_G[0]
1458
+ mu_value = st.session_state.pred_mu[0][0] if st.session_state.pred_mu.ndim > 1 else \
1459
+ st.session_state.pred_mu[0]
1460
 
1461
+ # Initialize simulation
1462
+ bubble_sim = OptimizedBubbleSimulation()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1463
 
1464
+ # Run simulation (NO UI UPDATES inside simulation)
1465
+ start_time = time.time()
1466
+ t_sim, R_sim = bubble_sim.run_optimized_simulation(G_value, mu_value, st.session_state.lambda_max_mean)
1467
+ simulation_time = time.time() - start_time
1468
+
1469
+ # Clear status and show results
1470
+ status_text.empty()
1471
+
1472
+ # Store simulation results
1473
+ st.session_state.t_sim = t_sim
1474
+ st.session_state.R_sim = R_sim
1475
+
1476
+ # Create comparison plot (exactly like desktop GUI)
1477
+ fig, ax = plt.subplots(figsize=(10, 6))
1478
+
1479
+ ax.plot(st.session_state.t_interp_newunit, st.session_state.R_interp_newunit,
1480
+ 'ro', markersize=4, label='Interpolated (Experimental)', alpha=0.7)
1481
+ ax.plot(t_sim, R_sim, 'b-', linewidth=2, label='Simulated (Predicted G & μ)')
1482
+
1483
+ ax.set_xlabel('Time (0.1 ms)')
1484
+ ax.set_ylabel('Radius (0.1 mm)')
1485
+ ax.set_title('Validation: Experimental vs Simulated R-t Curves (Ultra-Optimized)')
1486
+ ax.grid(True, alpha=0.3)
1487
+ ax.legend()
1488
+
1489
+ # Calculate error metrics (exactly like desktop GUI)
1490
+ if len(t_sim) > 0 and len(st.session_state.t_interp_newunit) > 0:
1491
+ t_min = max(st.session_state.t_interp_newunit[0], t_sim[0])
1492
+ t_max = min(st.session_state.t_interp_newunit[-1], t_sim[-1])
1493
+
1494
+ if t_max > t_min:
1495
+ f_sim = interp1d(t_sim, R_sim, kind='linear', bounds_error=False, fill_value='extrapolate')
1496
+
1497
+ mask = (st.session_state.t_interp_newunit >= t_min) & (
1498
+ st.session_state.t_interp_newunit <= t_max)
1499
+ t_common = st.session_state.t_interp_newunit[mask]
1500
+ R_exp_common = st.session_state.R_interp_newunit[mask]
1501
+ R_sim_common = f_sim(t_common)
1502
+
1503
+ if len(R_exp_common) > 0:
1504
+ rmse = np.sqrt(np.mean((R_exp_common - R_sim_common) ** 2))
1505
+ mae = np.mean(np.abs(R_exp_common - R_sim_common))
1506
+ max_error = np.max(np.abs(R_exp_common - R_sim_common))
1507
+
1508
+ error_text = f'RMSE: {rmse:.3f}\nMAE: {mae:.3f}\nMax Error: {max_error:.3f}'
1509
+ ax.text(0.02, 0.98, error_text, transform=ax.transAxes,
1510
+ verticalalignment='top', bbox=dict(boxstyle='round', facecolor='white', alpha=0.8))
1511
+
1512
+ plt.tight_layout()
1513
+ st.pyplot(fig)
1514
+
1515
+ # Display validation metrics
1516
+ if 'rmse' in locals():
1517
+ col1, col2, col3 = st.columns(3)
1518
+ with col1:
1519
+ st.metric("RMSE", f"{rmse:.3f}")
1520
+ with col2:
1521
+ st.metric("MAE", f"{mae:.3f}")
1522
+ with col3:
1523
+ st.metric("Max Error", f"{max_error:.3f}")
1524
+
1525
+ # Show detailed results (matching desktop GUI message)
1526
+ validation_results = f"""**Validation Results (Ultra-Optimized):**
1527
 
1528
  **Predicted Values:**
1529
  - Shear Modulus (G): {G_value:.2e} Pa
 
1531
  - Lambda Max: {st.session_state.lambda_max_mean:.3f} (from .mat file)
1532
 
1533
  **Simulation Performance:**
1534
+ - Simulation Time: {simulation_time:.2f} seconds (ultra-fast!)
1535
  - Simulated Points: {len(R_sim)}
1536
  - Time Range: {t_sim[0]:.3f} to {t_sim[-1]:.3f} (0.1 ms)
1537
 
1538
  The plot shows comparison between experimental (dots) and
1539
  simulated (line) R-t curves using predicted material properties.
1540
+ Note: This uses ultra-optimized simulation with ZERO UI updates during execution."""
1541
 
1542
+ st.success("✅ Validation simulation completed!")
1543
+ st.info(validation_results)
1544
 
1545
+ except Exception as e:
1546
+ status_text.empty()
1547
+ st.error(f"Simulation failed: {str(e)}")
1548
 
1549
+ with st.expander("🔍 Debug Information"):
1550
+ st.write(f"**Error:** {str(e)}")
1551
+ st.write(f"**G value:** {G_value if 'G_value' in locals() else 'N/A'}")
1552
+ st.write(f"**μ value:** {mu_value if 'mu_value' in locals() else 'N/A'}")
1553
+ st.write(f"**Lambda:** {st.session_state.get('lambda_max_mean', 'N/A')}")
1554
 
1555
 
1556
  def show_results():