lehuaaa commited on
Commit
51aa7f3
·
verified ·
1 Parent(s): 20fd3d5

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +128 -199
src/streamlit_app.py CHANGED
@@ -31,35 +31,15 @@ try:
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,57 +64,6 @@ st.markdown("""
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,10 +76,15 @@ if 'model_loaded' not in st.session_state:
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,8 +118,10 @@ class OptimizedBubbleSimulation:
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,7 +132,7 @@ class OptimizedBubbleSimulation:
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,7 +150,9 @@ class OptimizedBubbleSimulation:
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,51 +198,54 @@ class OptimizedBubbleSimulation:
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,6 +255,7 @@ class OptimizedBubbleSimulation:
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,9 +267,11 @@ class OptimizedBubbleSimulation:
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,7 +279,8 @@ class OptimizedBubbleSimulation:
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,7 +466,7 @@ class OptimizedBubbleSimulation:
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,7 +1342,7 @@ Ready for validation simulation!"""
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,98 +1377,83 @@ def show_validation():
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,26 +1461,25 @@ def show_validation():
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():
 
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
  padding: 1rem;
65
  margin: 1rem 0;
66
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  </style>
68
  """, unsafe_allow_html=True)
69
 
 
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
  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
  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
  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
 
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
 
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
  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
 
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
 
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
 
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
  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
  - 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():