Spaces:
Sleeping
Sleeping
import gradio as gr | |
import pandas as pd | |
from continuous_beam import ContinuousBeam | |
import matplotlib.pyplot as plt | |
import numpy as np | |
import io | |
import base64 | |
import gc # Garbage collection for memory management | |
import warnings | |
warnings.filterwarnings('ignore') # Suppress warnings for cleaner output | |
# Configure matplotlib for cloud deployment | |
plt.style.use('default') # Use simple style | |
plt.rcParams['figure.max_open_warning'] = 0 # Disable figure warnings | |
class GradioBeamApp: | |
def __init__(self): | |
self.beam = ContinuousBeam() | |
self.spans_data = [] | |
def parse_point_loads(self, point_loads_text): | |
"""Parse point loads from text input""" | |
if not point_loads_text or point_loads_text.strip() == "": | |
return [] | |
point_loads = [] | |
try: | |
# Expected format: "position1,load1; position2,load2; ..." | |
# Example: "2.0,50; 4.0,30" | |
load_pairs = point_loads_text.split(';') | |
for pair in load_pairs: | |
if pair.strip(): | |
pos_str, load_str = pair.split(',') | |
position = float(pos_str.strip()) | |
load = float(load_str.strip()) | |
point_loads.append((position, load)) | |
except: | |
raise ValueError("Invalid point load format. Use: position1,load1; position2,load2") | |
return point_loads | |
def add_span(self, length, distributed_load, point_loads_text, spans_display): | |
"""Add a span to the beam""" | |
try: | |
length = float(length) | |
distributed_load = float(distributed_load) | |
if length <= 0 or distributed_load < 0: | |
return spans_display, "Error: Please enter valid values (length > 0, distributed_load >= 0)" | |
# Parse point loads | |
point_loads = self.parse_point_loads(point_loads_text) | |
# Validate point load positions | |
for pos, load in point_loads: | |
if pos < 0 or pos > length: | |
return spans_display, f"Error: Point load at {pos}m is outside span length {length}m" | |
if load < 0: | |
return spans_display, f"Error: Point load {load}kN must be positive" | |
self.beam.add_span(length, distributed_load, point_loads) | |
# Create span description | |
span_info = f"Span {len(self.beam.spans)}: L={length}m, w={distributed_load}kN/m" | |
if point_loads: | |
point_load_str = ", ".join([f"P={load}kN@{pos}m" for pos, load in point_loads]) | |
span_info += f", {point_load_str}" | |
self.spans_data.append(span_info) | |
# Update display | |
updated_display = "\n".join(self.spans_data) | |
return updated_display, f"Added: {span_info}" | |
except ValueError as e: | |
return spans_display, f"Error: {str(e)}" | |
def clear_spans(self): | |
"""Clear all spans""" | |
self.beam = ContinuousBeam() | |
self.spans_data = [] | |
return "", "All spans cleared" | |
def design_beam(self, width, depth, fc, fy, cover, spans_display): | |
"""Design the beam and return results""" | |
if not self.beam.spans: | |
return "No spans added. Please add at least one span.", None, None, None, None, None | |
try: | |
# Limit spans for cloud deployment | |
if len(self.beam.spans) > 10: | |
return "Error: Maximum 10 spans allowed for cloud deployment.", None, None, None, None, "Error: Too many spans" | |
# Update beam properties | |
self.beam.beam_width = float(width) | |
self.beam.beam_depth = float(depth) | |
self.beam.fc = float(fc) | |
self.beam.fy = float(fy) | |
self.beam.cover = float(cover) | |
self.beam.d = self.beam.beam_depth - self.beam.cover | |
# Perform design with timeout protection | |
design_results = self.beam.design_beam() | |
# Generate report | |
report = self.beam.generate_report(design_results) | |
# Create summary table | |
summary_data = [] | |
for span_data in design_results: | |
span_num = span_data['span'] | |
for i, (reinf, stirrup) in enumerate(zip(span_data['reinforcement'], span_data['stirrups'])): | |
if reinf['moment'] != 0 or stirrup['shear'] != 0: | |
summary_data.append([ | |
span_num if i == 0 else '', | |
reinf['location'], | |
f"{reinf['moment']:.2f}" if reinf['moment'] != 0 else '-', | |
reinf['bars'] if reinf['moment'] != 0 else '-', | |
f"{stirrup['shear']:.2f}" if stirrup['shear'] != 0 else '-', | |
stirrup['stirrup_spacing'] if stirrup['shear'] != 0 else '-' | |
]) | |
# Create DataFrame for table display | |
df = pd.DataFrame(summary_data, columns=[ | |
'Span', 'Location', 'Moment (kN-m)', 'Reinforcement', 'Shear (kN)', 'Stirrups' | |
]) | |
# Generate plots with error handling | |
try: | |
bmd_sfd_plot = self.beam.plot_bmd_sfd(design_results) | |
reinforcement_plot = self.beam.plot_reinforcement_layout(design_results) | |
stirrup_plot = self.beam.plot_stirrup_layout(design_results) | |
except Exception as plot_error: | |
print(f"Plotting error: {plot_error}") | |
# Return simplified results if plotting fails | |
return report, df, None, None, None, "Design completed (plots unavailable)" | |
# Force garbage collection to free memory | |
gc.collect() | |
return report, df, bmd_sfd_plot, reinforcement_plot, stirrup_plot, "Design completed successfully!" | |
except Exception as e: | |
gc.collect() # Clean up memory on error | |
error_msg = str(e) | |
if "memory" in error_msg.lower() or "allocation" in error_msg.lower(): | |
return "Error: Insufficient memory. Try reducing the number of spans or load complexity.", None, None, None, None, "Memory Error" | |
return f"Design calculation failed: {error_msg}", None, None, None, None, f"Error: {error_msg}" | |
def create_interface(): | |
app = GradioBeamApp() | |
with gr.Blocks(title="Continuous Beam RC Design - Thai Standards", theme=gr.themes.Default()) as interface: | |
gr.Markdown("# Continuous Beam RC Design - Thai Standards") | |
gr.Markdown("*Using Finite Element Analysis with Thai reinforcement standards (DB bars, RB stirrups)*") | |
with gr.Row(): | |
with gr.Column(scale=1): | |
gr.Markdown("## Beam Properties") | |
with gr.Row(): | |
width_input = gr.Number(label="Beam Width (mm)", value=300) | |
depth_input = gr.Number(label="Beam Depth (mm)", value=500) | |
with gr.Row(): | |
fc_input = gr.Number(label="f'c (ksc)", value=280) | |
fy_input = gr.Number(label="fy (ksc)", value=4000) | |
cover_input = gr.Number(label="Cover (mm)", value=40) | |
gr.Markdown("## Spans Configuration") | |
with gr.Row(): | |
span_length_input = gr.Number(label="Span Length (m)", value=6.0) | |
distributed_load_input = gr.Number(label="Distributed Load (kN/m)", value=25.0) | |
point_loads_input = gr.Textbox( | |
label="Point Loads (position,load; position,load; ...)", | |
placeholder="Example: 2.0,50; 4.0,30 (means 50kN at 2m and 30kN at 4m)", | |
value="" | |
) | |
with gr.Row(): | |
add_span_btn = gr.Button("Add Span", variant="primary") | |
clear_spans_btn = gr.Button("Clear All", variant="secondary") | |
spans_display = gr.Textbox( | |
label="Added Spans", | |
lines=5, | |
interactive=False, | |
placeholder="No spans added yet..." | |
) | |
design_btn = gr.Button("Design Beam", variant="primary", size="lg") | |
status_output = gr.Textbox(label="Status", interactive=False) | |
with gr.Column(scale=2): | |
gr.Markdown("## Design Results") | |
with gr.Tabs(): | |
with gr.TabItem("Summary"): | |
summary_table = gr.Dataframe( | |
label="Design Summary", | |
headers=["Span", "Location", "Moment (kN-m)", "Reinforcement", "Shear (kN)", "Stirrups"], | |
interactive=False | |
) | |
with gr.TabItem("BMD & SFD"): | |
bmd_sfd_plot = gr.Plot(label="Bending Moment and Shear Force Diagrams") | |
with gr.TabItem("Reinforcement Layout"): | |
reinforcement_plot = gr.Plot(label="Reinforcement Bar Layout") | |
with gr.TabItem("Stirrup Layout"): | |
stirrup_plot = gr.Plot(label="Shear Stirrup Layout") | |
with gr.TabItem("Detailed Report"): | |
results_output = gr.Textbox( | |
label="Detailed Design Report", | |
lines=20, | |
interactive=False, | |
show_copy_button=True | |
) | |
# Event handlers | |
add_span_btn.click( | |
fn=lambda length, dist_load, point_loads, spans: app.add_span(length, dist_load, point_loads, spans), | |
inputs=[span_length_input, distributed_load_input, point_loads_input, spans_display], | |
outputs=[spans_display, status_output] | |
) | |
clear_spans_btn.click( | |
fn=lambda: app.clear_spans(), | |
outputs=[spans_display, status_output] | |
) | |
design_btn.click( | |
fn=lambda w, d, fc, fy, c, spans: app.design_beam(w, d, fc, fy, c, spans), | |
inputs=[width_input, depth_input, fc_input, fy_input, cover_input, spans_display], | |
outputs=[results_output, summary_table, bmd_sfd_plot, reinforcement_plot, stirrup_plot, status_output] | |
) | |
return interface | |
def main(): | |
interface = create_interface() | |
# Optimized for Hugging Face Spaces | |
interface.launch( | |
share=False, | |
debug=False, # Disable debug for production | |
show_error=True, | |
quiet=True, # Reduce console output | |
ssr_mode=False, # Disable SSR for compatibility | |
auth=None, # No authentication required | |
max_threads=10 # Limit concurrent threads | |
) | |
if __name__ == "__main__": | |
main() |