SivaMallikarjun commited on
Commit
8877d4f
·
verified ·
1 Parent(s): 45e57eb

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +611 -0
app.py ADDED
@@ -0,0 +1,611 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import numpy as np
3
+ import matplotlib.pyplot as plt
4
+ import pandas as pd
5
+ from sklearn.model_selection import train_test_split
6
+ from sklearn.ensemble import RandomForestRegressor
7
+ from sklearn.metrics import mean_squared_error, r2_score
8
+ import joblib
9
+ import os
10
+
11
+ # Generate synthetic dataset for beam behavior prediction
12
+ def generate_beam_dataset(n_samples=1000):
13
+ np.random.seed(42)
14
+
15
+ # Generate random beam configurations
16
+ lengths = np.random.uniform(1, 20, n_samples)
17
+
18
+ # Generate 1-3 random point loads for each beam
19
+ point_loads_data = []
20
+ for i in range(n_samples):
21
+ n_loads = np.random.randint(1, 4)
22
+ loads = []
23
+ for _ in range(n_loads):
24
+ pos = np.random.uniform(0, lengths[i])
25
+ magnitude = np.random.uniform(-10000, 10000)
26
+ loads.append((pos, magnitude))
27
+ point_loads_data.append(loads)
28
+
29
+ # Generate random UDL parameters
30
+ udl_starts = np.random.uniform(0, lengths * 0.4, n_samples)
31
+ udl_lengths = np.random.uniform(1, lengths * 0.6, n_samples)
32
+ udl_ends = np.minimum(udl_starts + udl_lengths, lengths)
33
+ udl_values = np.random.uniform(-5000, 5000, n_samples)
34
+
35
+ # Calculate features for ML
36
+ features = []
37
+ max_sfd = []
38
+ max_bmd = []
39
+
40
+ for i in range(n_samples):
41
+ # Calculate beam characteristics
42
+ length = lengths[i]
43
+ point_loads = point_loads_data[i]
44
+ udl_start = udl_starts[i]
45
+ udl_end = udl_ends[i]
46
+ udl_value = udl_values[i]
47
+
48
+ # Calculate SFD and BMD
49
+ x = np.linspace(0, length, 100)
50
+ shear_force = np.zeros_like(x)
51
+ bending_moment = np.zeros_like(x)
52
+
53
+ # Apply point loads
54
+ for pos, load in point_loads:
55
+ shear_force[x >= pos] += load
56
+
57
+ # Apply UDL
58
+ for j, xi in enumerate(x):
59
+ if udl_start <= xi <= udl_end:
60
+ for k in range(j, len(x)):
61
+ shear_force[k] += udl_value * (min(x[k], udl_end) - max(xi, udl_start))
62
+
63
+ # Compute Bending Moment by integrating shear force
64
+ for j in range(1, len(x)):
65
+ bending_moment[j] = bending_moment[j-1] + shear_force[j-1] * (x[j] - x[j-1])
66
+
67
+ # Extract features
68
+ num_loads = len(point_loads)
69
+ total_point_load = sum(load for _, load in point_loads)
70
+ avg_load_position = sum(pos*load for pos, load in point_loads) / max(1, abs(total_point_load)) if total_point_load != 0 else 0
71
+ udl_coverage = (udl_end - udl_start) / length if length > 0 else 0
72
+ total_udl_force = udl_value * (udl_end - udl_start)
73
+
74
+ features.append([
75
+ length,
76
+ num_loads,
77
+ total_point_load,
78
+ avg_load_position,
79
+ udl_start,
80
+ udl_end,
81
+ udl_value,
82
+ udl_coverage,
83
+ total_udl_force
84
+ ])
85
+
86
+ max_sfd.append(np.max(np.abs(shear_force)))
87
+ max_bmd.append(np.max(np.abs(bending_moment)))
88
+
89
+ # Create dataframe
90
+ feature_cols = [
91
+ 'beam_length',
92
+ 'num_point_loads',
93
+ 'total_point_load',
94
+ 'avg_load_position',
95
+ 'udl_start',
96
+ 'udl_end',
97
+ 'udl_value',
98
+ 'udl_coverage',
99
+ 'total_udl_force'
100
+ ]
101
+
102
+ X_df = pd.DataFrame(features, columns=feature_cols)
103
+ y_df = pd.DataFrame({
104
+ 'max_shear_force': max_sfd,
105
+ 'max_bending_moment': max_bmd
106
+ })
107
+
108
+ # Combine into a single dataset
109
+ dataset = pd.concat([X_df, y_df], axis=1)
110
+
111
+ return dataset, X_df.columns, y_df.columns
112
+
113
+ # ML Model Training Function
114
+ def train_beam_ml_models(dataset):
115
+ # Split features and targets
116
+ X = dataset.iloc[:, :9] # First 9 columns are features
117
+ y_sfd = dataset['max_shear_force']
118
+ y_bmd = dataset['max_bending_moment']
119
+
120
+ # Split into training and testing sets
121
+ X_train, X_test, y_sfd_train, y_sfd_test = train_test_split(X, y_sfd, test_size=0.2, random_state=42)
122
+ _, _, y_bmd_train, y_bmd_test = train_test_split(X, y_bmd, test_size=0.2, random_state=42)
123
+
124
+ # Train SFD model
125
+ sfd_model = RandomForestRegressor(n_estimators=100, random_state=42)
126
+ sfd_model.fit(X_train, y_sfd_train)
127
+
128
+ # Train BMD model
129
+ bmd_model = RandomForestRegressor(n_estimators=100, random_state=42)
130
+ bmd_model.fit(X_train, y_bmd_train)
131
+
132
+ # Evaluate models
133
+ sfd_preds = sfd_model.predict(X_test)
134
+ bmd_preds = bmd_model.predict(X_test)
135
+
136
+ sfd_rmse = np.sqrt(mean_squared_error(y_sfd_test, sfd_preds))
137
+ bmd_rmse = np.sqrt(mean_squared_error(y_bmd_test, bmd_preds))
138
+
139
+ sfd_r2 = r2_score(y_sfd_test, sfd_preds)
140
+ bmd_r2 = r2_score(y_bmd_test, bmd_preds)
141
+
142
+ # Save models
143
+ joblib.dump(sfd_model, 'sfd_model.pkl')
144
+ joblib.dump(bmd_model, 'bmd_model.pkl')
145
+
146
+ return {
147
+ 'sfd_model': sfd_model,
148
+ 'bmd_model': bmd_model,
149
+ 'metrics': {
150
+ 'sfd_rmse': sfd_rmse,
151
+ 'bmd_rmse': bmd_rmse,
152
+ 'sfd_r2': sfd_r2,
153
+ 'bmd_r2': bmd_r2
154
+ }
155
+ }
156
+
157
+ # Improved calculation function using exact integrals
158
+ def calculate_sfd_bmd(length, point_loads, udl_start, udl_end, udl_value):
159
+ x = np.linspace(0, length, 200)
160
+ shear_force = np.zeros_like(x)
161
+ bending_moment = np.zeros_like(x)
162
+
163
+ # Apply point loads (corrected)
164
+ for pos, load in point_loads:
165
+ shear_force[x >= pos] += load
166
+
167
+ # Calculate bending moment directly for point loads
168
+ for i, xi in enumerate(x):
169
+ if xi >= pos:
170
+ bending_moment[i] += load * (xi - pos)
171
+
172
+ # Apply UDL (corrected calculation)
173
+ udl_length = udl_end - udl_start
174
+ if udl_length > 0 and udl_value != 0:
175
+ for i, xi in enumerate(x):
176
+ # Shear force at point xi due to UDL
177
+ if xi <= udl_start:
178
+ # Before UDL: no contribution
179
+ pass
180
+ elif xi >= udl_end:
181
+ # After UDL: full contribution
182
+ shear_force[i] += udl_value * udl_length
183
+ else:
184
+ # Within UDL region: partial contribution
185
+ shear_force[i] += udl_value * (xi - udl_start)
186
+
187
+ # Bending moment calculations for UDL
188
+ if xi <= udl_start:
189
+ # No contribution before UDL
190
+ pass
191
+ elif xi >= udl_end:
192
+ # Full contribution after UDL
193
+ centroid_distance = xi - (udl_start + udl_end)/2
194
+ bending_moment[i] += udl_value * udl_length * centroid_distance
195
+ else:
196
+ # Partial contribution within UDL
197
+ partial_length = xi - udl_start
198
+ centroid_distance = partial_length/2
199
+ bending_moment[i] += udl_value * partial_length * centroid_distance
200
+
201
+ return x, shear_force, bending_moment
202
+
203
+ # AI Agent for beam analysis and optimization
204
+ class BeamAnalysisAgent:
205
+ def __init__(self):
206
+ # Initialize models
207
+ if os.path.exists('sfd_model.pkl') and os.path.exists('bmd_model.pkl'):
208
+ self.sfd_model = joblib.load('sfd_model.pkl')
209
+ self.bmd_model = joblib.load('bmd_model.pkl')
210
+ self.models_loaded = True
211
+ else:
212
+ print("Training new ML models...")
213
+ dataset, _, _ = generate_beam_dataset(1000)
214
+ model_data = train_beam_ml_models(dataset)
215
+ self.sfd_model = model_data['sfd_model']
216
+ self.bmd_model = model_data['bmd_model']
217
+ self.models_loaded = True
218
+ print(f"ML models trained. Metrics: {model_data['metrics']}")
219
+
220
+ def analyze_beam(self, length, point_loads, udl_start, udl_end, udl_value):
221
+ # Calculate exact SFD and BMD
222
+ x, shear_force, bending_moment = calculate_sfd_bmd(length, point_loads, udl_start, udl_end, udl_value)
223
+
224
+ # Extract feature vector for ML prediction
225
+ num_loads = len(point_loads)
226
+ total_point_load = sum(load for _, load in point_loads) if point_loads else 0
227
+ avg_load_position = sum(pos*load for pos, load in point_loads) / max(1, abs(total_point_load)) if point_loads and total_point_load != 0 else 0
228
+ udl_coverage = (udl_end - udl_start) / length if length > 0 else 0
229
+ total_udl_force = udl_value * (udl_end - udl_start)
230
+
231
+ feature_vector = np.array([[
232
+ length,
233
+ num_loads,
234
+ total_point_load,
235
+ avg_load_position,
236
+ udl_start,
237
+ udl_end,
238
+ udl_value,
239
+ udl_coverage,
240
+ total_udl_force
241
+ ]])
242
+
243
+ # Make predictions
244
+ if self.models_loaded:
245
+ predicted_max_sfd = self.sfd_model.predict(feature_vector)[0]
246
+ predicted_max_bmd = self.bmd_model.predict(feature_vector)[0]
247
+ else:
248
+ predicted_max_sfd = np.max(np.abs(shear_force))
249
+ predicted_max_bmd = np.max(np.abs(bending_moment))
250
+
251
+ # Calculate actual maximum values
252
+ actual_max_sfd = np.max(np.abs(shear_force))
253
+ actual_max_bmd = np.max(np.abs(bending_moment))
254
+
255
+ # Identify critical points
256
+ sfd_critical_idx = np.argmin(np.abs(shear_force))
257
+ sfd_critical_point = x[sfd_critical_idx]
258
+ bmd_max_idx = np.argmax(np.abs(bending_moment))
259
+ bmd_max_point = x[bmd_max_idx]
260
+
261
+ # Generate visualizations
262
+ fig, axs = plt.subplots(2, 1, figsize=(10, 12))
263
+
264
+ # Plot beam with loads
265
+ beam_ax = plt.subplot2grid((3, 1), (0, 0), fig=fig)
266
+ beam_ax.plot([0, length], [0, 0], 'k-', linewidth=3) # Beam
267
+ beam_ax.set_ylim(-1, 1)
268
+
269
+ # Draw point loads
270
+ for pos, load in point_loads:
271
+ if load > 0:
272
+ beam_ax.arrow(pos, 0.5, 0, -0.3, head_width=0.2, head_length=0.1, fc='r', ec='r')
273
+ beam_ax.text(pos, 0.6, f"{load}N", ha='center')
274
+ else:
275
+ beam_ax.arrow(pos, -0.5, 0, 0.3, head_width=0.2, head_length=0.1, fc='b', ec='b')
276
+ beam_ax.text(pos, -0.6, f"{abs(load)}N", ha='center')
277
+
278
+ # Draw UDL
279
+ if udl_end > udl_start and udl_value != 0:
280
+ if udl_value > 0:
281
+ for u in np.linspace(udl_start, udl_end, 20):
282
+ beam_ax.arrow(u, 0.3, 0, -0.2, head_width=0.05, head_length=0.05, fc='r', ec='r')
283
+ beam_ax.plot([udl_start, udl_end], [0.3, 0.3], 'r-', linewidth=2)
284
+ beam_ax.text((udl_start + udl_end)/2, 0.4, f"{udl_value}N/m", ha='center')
285
+ else:
286
+ for u in np.linspace(udl_start, udl_end, 20):
287
+ beam_ax.arrow(u, -0.3, 0, 0.2, head_width=0.05, head_length=0.05, fc='b', ec='b')
288
+ beam_ax.plot([udl_start, udl_end], [-0.3, -0.3], 'b-', linewidth=2)
289
+ beam_ax.text((udl_start + udl_end)/2, -0.4, f"{abs(udl_value)}N/m", ha='center')
290
+
291
+ beam_ax.set_title("Beam Configuration")
292
+ beam_ax.set_xlabel("Position (m)")
293
+ beam_ax.set_yticks([])
294
+ beam_ax.grid(True)
295
+
296
+ # Plot SFD
297
+ axs[0].plot(x, shear_force, 'b-', linewidth=2)
298
+ axs[0].fill_between(x, 0, shear_force, alpha=0.3, color='blue')
299
+ axs[0].axhline(0, color='k', linestyle='-', alpha=0.5)
300
+ axs[0].set_title("Shear Force Diagram (SFD)")
301
+ axs[0].set_xlabel("Position (m)")
302
+ axs[0].set_ylabel("Shear Force (N)")
303
+ axs[0].grid(True)
304
+
305
+ # Plot BMD
306
+ axs[1].plot(x, bending_moment, 'r-', linewidth=2)
307
+ axs[1].fill_between(x, 0, bending_moment, alpha=0.3, color='red')
308
+ axs[1].axhline(0, color='k', linestyle='-', alpha=0.5)
309
+ axs[1].set_title("Bending Moment Diagram (BMD)")
310
+ axs[1].set_xlabel("Position (m)")
311
+ axs[1].set_ylabel("Bending Moment (N⋅m)")
312
+ axs[1].grid(True)
313
+
314
+ plt.tight_layout()
315
+
316
+ # Prepare analysis report
317
+ report = {
318
+ "beam_configuration": {
319
+ "length": length,
320
+ "point_loads": point_loads,
321
+ "udl": {
322
+ "start": udl_start,
323
+ "end": udl_end,
324
+ "value": udl_value
325
+ }
326
+ },
327
+ "analysis_results": {
328
+ "max_shear_force": {
329
+ "actual": float(actual_max_sfd),
330
+ "predicted": float(predicted_max_sfd),
331
+ "prediction_error": float(abs(predicted_max_sfd - actual_max_sfd) / actual_max_sfd * 100) if actual_max_sfd != 0 else 0
332
+ },
333
+ "max_bending_moment": {
334
+ "actual": float(actual_max_bmd),
335
+ "predicted": float(predicted_max_bmd),
336
+ "prediction_error": float(abs(predicted_max_bmd - actual_max_bmd) / actual_max_bmd * 100) if actual_max_bmd != 0 else 0
337
+ },
338
+ "critical_points": {
339
+ "zero_shear_force": float(sfd_critical_point),
340
+ "max_bending_moment": float(bmd_max_point)
341
+ }
342
+ }
343
+ }
344
+
345
+ return fig, report
346
+
347
+ def suggest_optimizations(self, length, point_loads, udl_start, udl_end, udl_value, target_criterion="minimize_bending"):
348
+ original_x, original_sf, original_bm = calculate_sfd_bmd(length, point_loads, udl_start, udl_end, udl_value)
349
+ original_max_bm = np.max(np.abs(original_bm))
350
+ original_max_sf = np.max(np.abs(original_sf))
351
+
352
+ suggestions = []
353
+
354
+ # Try repositioning point loads
355
+ if len(point_loads) > 0:
356
+ for i, (pos, load) in enumerate(point_loads):
357
+ # Try moving each load to 5 different positions
358
+ test_positions = np.linspace(0.1 * length, 0.9 * length, 5)
359
+ for new_pos in test_positions:
360
+ if abs(new_pos - pos) < 0.05 * length: # Skip if too close to original
361
+ continue
362
+
363
+ # Create new point loads list with moved load
364
+ new_point_loads = point_loads.copy()
365
+ new_point_loads[i] = (new_pos, load)
366
+
367
+ # Calculate new diagrams
368
+ _, new_sf, new_bm = calculate_sfd_bmd(length, new_point_loads, udl_start, udl_end, udl_value)
369
+ new_max_bm = np.max(np.abs(new_bm))
370
+ new_max_sf = np.max(np.abs(new_sf))
371
+
372
+ # Check if this is an improvement
373
+ if target_criterion == "minimize_bending" and new_max_bm < original_max_bm * 0.9:
374
+ bm_reduction = (original_max_bm - new_max_bm) / original_max_bm * 100
375
+ suggestions.append({
376
+ "type": "reposition_load",
377
+ "original": {"position": pos, "load": load},
378
+ "suggestion": {"position": float(new_pos), "load": load},
379
+ "improvement": f"{bm_reduction:.1f}% reduction in maximum bending moment"
380
+ })
381
+ elif target_criterion == "minimize_shear" and new_max_sf < original_max_sf * 0.9:
382
+ sf_reduction = (original_max_sf - new_max_sf) / original_max_sf * 100
383
+ suggestions.append({
384
+ "type": "reposition_load",
385
+ "original": {"position": pos, "load": load},
386
+ "suggestion": {"position": float(new_pos), "load": load},
387
+ "improvement": f"{sf_reduction:.1f}% reduction in maximum shear force"
388
+ })
389
+
390
+ # Try adjusting UDL
391
+ if udl_end > udl_start and udl_value != 0:
392
+ # Try different UDL positions
393
+ test_starts = np.linspace(0, 0.5 * length, 3)
394
+ test_lengths = np.linspace(0.2 * length, 0.5 * length, 3)
395
+
396
+ for new_start in test_starts:
397
+ for new_length in test_lengths:
398
+ new_end = new_start + new_length
399
+ if new_end > length:
400
+ continue
401
+
402
+ # Too similar to original
403
+ if abs(new_start - udl_start) < 0.1 * length and abs(new_end - udl_end) < 0.1 * length:
404
+ continue
405
+
406
+ # Calculate new diagrams
407
+ _, new_sf, new_bm = calculate_sfd_bmd(length, point_loads, new_start, new_end, udl_value)
408
+ new_max_bm = np.max(np.abs(new_bm))
409
+ new_max_sf = np.max(np.abs(new_sf))
410
+
411
+ # Check if this is an improvement
412
+ if target_criterion == "minimize_bending" and new_max_bm < original_max_bm * 0.9:
413
+ bm_reduction = (original_max_bm - new_max_bm) / original_max_bm * 100
414
+ suggestions.append({
415
+ "type": "adjust_udl",
416
+ "original": {"start": udl_start, "end": udl_end},
417
+ "suggestion": {"start": float(new_start), "end": float(new_end)},
418
+ "improvement": f"{bm_reduction:.1f}% reduction in maximum bending moment"
419
+ })
420
+ elif target_criterion == "minimize_shear" and new_max_sf < original_max_sf * 0.9:
421
+ sf_reduction = (original_max_sf - new_max_sf) / original_max_sf * 100
422
+ suggestions.append({
423
+ "type": "adjust_udl",
424
+ "original": {"start": udl_start, "end": udl_end},
425
+ "suggestion": {"start": float(new_start), "end": float(new_end)},
426
+ "improvement": f"{sf_reduction:.1f}% reduction in maximum shear force"
427
+ })
428
+
429
+ # Sort suggestions by improvement
430
+ if suggestions:
431
+ suggestions.sort(key=lambda x: float(x["improvement"].split('%')[0]), reverse=True)
432
+ return suggestions[:3] # Return top 3 suggestions
433
+ else:
434
+ return [{"type": "no_suggestions", "message": "No significant improvements found with the attempted modifications."}]
435
+
436
+ # Gradio Interface Functions
437
+ def format_report(report):
438
+ text = f"## Beam Analysis Report\n\n"
439
+ text += f"### Configuration\n"
440
+ text += f"- Beam Length: {report['beam_configuration']['length']}m\n"
441
+ text += f"- Point Loads: {report['beam_configuration']['point_loads']}\n"
442
+ text += f"- UDL: {report['beam_configuration']['udl']['value']} N/m from {report['beam_configuration']['udl']['start']}m to {report['beam_configuration']['udl']['end']}m\n\n"
443
+
444
+ text += f"### Results\n"
445
+ text += f"- Maximum Shear Force: {report['analysis_results']['max_shear_force']['actual']:.2f} N\n"
446
+ text += f"- Maximum Bending Moment: {report['analysis_results']['max_bending_moment']['actual']:.2f} N⋅m\n"
447
+ text += f"- Critical Points:\n"
448
+ text += f" - Zero Shear Force (likely max bending): {report['analysis_results']['critical_points']['zero_shear_force']:.2f}m\n"
449
+ text += f" - Max Bending Moment: {report['analysis_results']['critical_points']['max_bending_moment']:.2f}m\n\n"
450
+
451
+ text += f"### ML Predictions\n"
452
+ text += f"- Predicted Max Shear Force: {report['analysis_results']['max_shear_force']['predicted']:.2f} N (Error: {report['analysis_results']['max_shear_force']['prediction_error']:.2f}%)\n"
453
+ text += f"- Predicted Max Bending Moment: {report['analysis_results']['max_bending_moment']['predicted']:.2f} N⋅m (Error: {report['analysis_results']['max_bending_moment']['prediction_error']:.2f}%)\n"
454
+
455
+ return text
456
+
457
+ def format_optimization_suggestions(suggestions):
458
+ text = f"## Optimization Suggestions\n\n"
459
+
460
+ if suggestions[0].get("type") == "no_suggestions":
461
+ text += "No significant improvements found with the attempted modifications.\n"
462
+ return text
463
+
464
+ for i, suggestion in enumerate(suggestions, 1):
465
+ text += f"### Suggestion {i}\n"
466
+
467
+ if suggestion["type"] == "reposition_load":
468
+ text += f"- Type: Reposition Point Load\n"
469
+ text += f"- Original Position: {suggestion['original']['position']:.2f}m with {suggestion['original']['load']}N\n"
470
+ text += f"- Suggested Position: {suggestion['suggestion']['position']:.2f}m\n"
471
+ text += f"- Improvement: {suggestion['improvement']}\n\n"
472
+
473
+ elif suggestion["type"] == "adjust_udl":
474
+ text += f"- Type: Adjust UDL Position\n"
475
+ text += f"- Original: {suggestion['original']['start']:.2f}m to {suggestion['original']['end']:.2f}m\n"
476
+ text += f"- Suggested: {suggestion['suggestion']['start']:.2f}m to {suggestion['suggestion']['end']:.2f}m\n"
477
+ text += f"- Improvement: {suggestion['improvement']}\n\n"
478
+
479
+ return text
480
+
481
+ def parse_point_loads(point_loads_str):
482
+ if not point_loads_str or point_loads_str.strip() == "":
483
+ return []
484
+
485
+ try:
486
+ # Handle different input formats
487
+ point_loads_str = point_loads_str.replace(';', ',')
488
+ if '[' not in point_loads_str:
489
+ # Try to parse as simple comma-separated numbers in pairs
490
+ values = [float(x.strip()) for x in point_loads_str.split(',') if x.strip()]
491
+ if len(values) % 2 != 0:
492
+ raise ValueError("Point loads must be specified as position,load pairs")
493
+
494
+ return [(values[i], values[i+1]) for i in range(0, len(values), 2)]
495
+ else:
496
+ # Parse as literal Python expression
497
+ return eval(point_loads_str)
498
+ except Exception as e:
499
+ return [(0, 0)] # Return a default value on error
500
+
501
+ # Initialize the agent
502
+ beam_agent = BeamAnalysisAgent()
503
+
504
+ def analyze_beam_ui(length, point_loads_str, udl_start, udl_end, udl_value):
505
+ point_loads = parse_point_loads(point_loads_str)
506
+ fig, report = beam_agent.analyze_beam(length, point_loads, udl_start, udl_end, udl_value)
507
+ formatted_report = format_report(report)
508
+ return fig, formatted_report
509
+
510
+ def optimize_beam_ui(length, point_loads_str, udl_start, udl_end, udl_value, target_criterion):
511
+ point_loads = parse_point_loads(point_loads_str)
512
+ suggestions = beam_agent.suggest_optimizations(length, point_loads, udl_start, udl_end, udl_value, target_criterion)
513
+ formatted_suggestions = format_optimization_suggestions(suggestions)
514
+ return formatted_suggestions
515
+
516
+ def train_model_ui():
517
+ dataset, feature_names, target_names = generate_beam_dataset(2000)
518
+ model_data = train_beam_ml_models(dataset)
519
+
520
+ # Update the agent's models
521
+ global beam_agent
522
+ beam_agent.sfd_model = model_data['sfd_model']
523
+ beam_agent.bmd_model = model_data['bmd_model']
524
+
525
+ # Format training results
526
+ metrics = model_data['metrics']
527
+ report = f"## ML Model Training Results\n\n"
528
+ report += f"### Dataset\n"
529
+ report += f"- Generated {len(dataset)} sample beam configurations\n"
530
+ report += f"- Features: {', '.join(feature_names)}\n"
531
+ report += f"- Targets: {', '.join(target_names)}\n\n"
532
+
533
+ report += f"### Model Performance\n"
534
+ report += f"- Shear Force Prediction:\n"
535
+ report += f" - RMSE: {metrics['sfd_rmse']:.2f}\n"
536
+ report += f" - R²: {metrics['sfd_r2']:.4f}\n"
537
+ report += f"- Bending Moment Prediction:\n"
538
+ report += f" - RMSE: {metrics['bmd_rmse']:.2f}\n"
539
+ report += f" - R²: {metrics['bmd_r2']:.4f}\n"
540
+
541
+ return report
542
+
543
+ # Create the Gradio interface
544
+ with gr.Blocks(title="Beam Analysis with ML Agent") as iface:
545
+ gr.Markdown("# Structural Beam Analysis with ML Agent")
546
+ gr.Markdown("This application uses machine learning to analyze and optimize structural beams.")
547
+
548
+ with gr.Tab("Beam Analysis"):
549
+ with gr.Row():
550
+ with gr.Column(scale=1):
551
+ length_input = gr.Number(value=10.0, label="Beam Length (m)")
552
+ point_loads_input = gr.Textbox(value="[(2, -1000), (8, -2000)]", label="Point Loads [(position, magnitude)]")
553
+ udl_start_input = gr.Number(value=4.0, label="UDL Start Position (m)")
554
+ udl_end_input = gr.Number(value=7.0, label="UDL End Position (m)")
555
+ udl_value_input = gr.Number(value=-500, label="UDL Value (N/m)")
556
+ analyze_btn = gr.Button("Analyze Beam")
557
+
558
+ with gr.Column(scale=2):
559
+ output_plot = gr.Plot(label="Beam Analysis Plot")
560
+ output_report = gr.Markdown(label="Analysis Report")
561
+
562
+ analyze_btn.click(
563
+ analyze_beam_ui,
564
+ inputs=[length_input, point_loads_input, udl_start_input, udl_end_input, udl_value_input],
565
+ outputs=[output_plot, output_report]
566
+ )
567
+
568
+ with gr.Tab("Beam Optimization"):
569
+ with gr.Row():
570
+ with gr.Column(scale=1):
571
+ opt_length_input = gr.Number(value=10.0, label="Beam Length (m)")
572
+ opt_point_loads_input = gr.Textbox(value="[(2, -1000), (8, -2000)]", label="Point Loads [(position, magnitude)]")
573
+ opt_udl_start_input = gr.Number(value=4.0, label="UDL Start Position (m)")
574
+ opt_udl_end_input = gr.Number(value=7.0, label="UDL End Position (m)")
575
+ opt_udl_value_input = gr.Number(value=-500, label="UDL Value (N/m)")
576
+ opt_criterion = gr.Radio(
577
+ ["minimize_bending", "minimize_shear"],
578
+ label="Optimization Target",
579
+ value="minimize_bending"
580
+ )
581
+ optimize_btn = gr.Button("Suggest Optimizations")
582
+
583
+ with gr.Column(scale=2):
584
+ optimization_suggestions = gr.Markdown(label="Optimization Suggestions")
585
+
586
+ optimize_btn.click(
587
+ optimize_beam_ui,
588
+ inputs=[
589
+ opt_length_input,
590
+ opt_point_loads_input,
591
+ opt_udl_start_input,
592
+ opt_udl_end_input,
593
+ opt_udl_value_input,
594
+ opt_criterion
595
+ ],
596
+ outputs=[optimization_suggestions]
597
+ )
598
+
599
+ with gr.Tab("ML Model Training"):
600
+ train_btn = gr.Button("Train New ML Models")
601
+ training_results = gr.Markdown(label="Training Results")
602
+
603
+ train_btn.click(
604
+ train_model_ui,
605
+ inputs=[],
606
+ outputs=[training_results]
607
+ )
608
+
609
+ # Launch the app
610
+ if __name__ == "__main__":
611
+ iface.launch()