Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/osdag_core/Common.py
Original file line number Diff line number Diff line change
Expand Up @@ -874,7 +874,7 @@ def is_valid_custom(self):
VALUES_SUPPORTING_OPTIONS_RS = ['Profiled Metal sheeting', 'Plastered sheeting']
VALUES_SUPPORTING_OPTIONS_GNT = ['Crane']
VALUES_SUPPORTING_OPTIONS_FRC = ['Elements not susceptible to cracking', 'Element susceptible to cracking']
VALUES_SUPPORTING_OPTIONS_DEF = ['NA']
VALUES_SUPPORTING_OPTIONS_DEF = ['Not Applicable']
KEY_MAX_DEFL = 'Deflection.Max'
KEY_DISP_MAX_DEFL = 'Maximum Deflection'
VALUES_MAX_DEFL = ['Span/600','Span/800','Span/400','Span/300','Span/360','Span/150','Span/180','Span/240','Span/120','Span/500','Span/750','Span/1000']
Expand Down
11 changes: 9 additions & 2 deletions src/osdag_core/cad/common_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -2065,9 +2065,16 @@ def createPlateGirderCAD(self):
# Stiffener Logic
include_intermediate_stiffeners = True
stiffener_spacing_val = getattr(Conn, 'c', 'N/A')


# Web philosophy is the single source of truth: 'Thick Web without ITS' has no
# intermediate transverse stiffeners, so never draw them regardless of self.c.
web_philosophy = getattr(Conn, 'web_philosophy', '')

# Check if stiffener spacing is valid
if stiffener_spacing_val in ['NA', 'N/A', None, '', '0'] or isinstance(stiffener_spacing_val, str) and not stiffener_spacing_val.replace('.', '', 1).isdigit():
if web_philosophy == 'Thick Web without ITS':
include_intermediate_stiffeners = False
stiffener_spacing = 750.0
elif stiffener_spacing_val in ['NA', 'N/A', None, '', '0'] or isinstance(stiffener_spacing_val, str) and not stiffener_spacing_val.replace('.', '', 1).isdigit():
include_intermediate_stiffeners = False
stiffener_spacing = 750.0 # Default for creating the spacing if needed (though skipped)
else:
Expand Down
55 changes: 30 additions & 25 deletions src/osdag_core/design_type/member.py
Original file line number Diff line number Diff line change
Expand Up @@ -2884,32 +2884,19 @@ def optimization_tab_welded_plate_girder_design(self, input_dictionary):

optimum = []

t2 = (
KEY_EFFECTIVE_AREA_PARA, KEY_DISP_EFFECTIVE_AREA_PARA, TYPE_TEXTBOX, None, values[KEY_EFFECTIVE_AREA_PARA])
optimum.append(t2)

t1 = (KEY_ALLOW_CLASS, KEY_DISP_CLASS, TYPE_COMBOBOX, ['Yes', 'No'], values[KEY_ALLOW_CLASS])
optimum.append(t1)

t1 = (KEY_LOAD, KEY_DISP_LOAD, TYPE_COMBOBOX, KEY_DISP_LOAD_list, values[KEY_LOAD])
optimum.append(t1)

t2 = (
KEY_LENGTH_OVERWRITE, KEY_DISPP_LENGTH_OVERWRITE, TYPE_TEXTBOX, None, values[KEY_LENGTH_OVERWRITE])
optimum.append(t2)

doc_text = """
<p><b>Effective Area Parameter</b> is the parameter used to define the reduction in the area of the section due to
connection detailing and other such requirements. The default value of this parameter is set at <b>1.0</b>, which means
that the effective area is 100% of the gross area for Plastic, Compact and Semi-compact sections.</p>
<p>For <b>Slender sections</b>, the initial area will be computed based on the recommendations in Fig.2B of the National
Building Code (2016). The value of the parameter should be defined in terms of the effective area to be considered for
design simulation after deducting the area lost.</p>
<p>The maximum value of the parameter is <b>1.0</b> (effective area is 100% of the gross area) with a minimum value of <b>0.1</b>.</p>
<hr>
<p><b>Effective Length</b> is the parameter used to <b>overwrite the length multiplier</b>. The default value of this ratio is set at <b>NA</b>.
The value can be re-defined for any particular design session with a minimum of <b>0.1</b>. If an invalid value is given, it is set to <b>NA</b> or <b>1.0</b>.</p>
<p>For simply supported beams of overall depth <b>D</b> and span length <b>L</b>, the effective length LLT is given by the table below.</p>
<p><b>Allow Class</b> selects whether the optimiser may consider sections of the given
classification. <b>Type of Load</b> selects the loading condition used when deriving the
lateral-torsional-buckling effective length for the welded plate girder.</p>
<p>The effective length of the plate girder is derived automatically from the end
restraints (torsional/warping) and the loading condition; no manual length or area
override is required for this module.</p>
"""

t9 = ("textBrowser", "", TYPE_TEXT_BROWSER, doc_text , None)
Expand All @@ -2921,7 +2908,7 @@ def Stiffener_design(self, input_dictionary):
optimum = []
values = {KEY_IntermediateStiffener:'Yes',
KEY_IntermediateStiffener_spacing:'NA',
KEY_LongitudnalStiffener:'Yes',
KEY_LongitudnalStiffener:'No',
KEY_IntermediateStiffener_thickness:'6',
KEY_LongitudnalStiffener_thickness:'6',
KEY_ShearBucklingOption : KEY_DISP_SB_Option[0]
Expand All @@ -2936,7 +2923,7 @@ def Stiffener_design(self, input_dictionary):

t8 = (KEY_IntermediateStiffener_spacing, KEY_DISP_IntermediateStiffener_spacing, TYPE_TEXTBOX, None, values[KEY_IntermediateStiffener_spacing])
optimum.append(t8)
t9 = (KEY_LongitudnalStiffener, KEY_DISP_LongitudnalStiffener, TYPE_COMBOBOX, ['Yes','No'], values[KEY_LongitudnalStiffener])
t9 = (KEY_LongitudnalStiffener, KEY_DISP_LongitudnalStiffener, TYPE_COMBOBOX, ['No', 'Yes and 1 stiffener', 'Yes and 2 stiffeners'], values[KEY_LongitudnalStiffener])
optimum.append(t9)
t10 = (KEY_IntermediateStiffener_thickness, KEY_DISP_IntermediateStiffener_thickness, TYPE_COMBOBOX, ['All','Customized'], values[KEY_IntermediateStiffener_thickness])
optimum.append(t10)
Expand Down Expand Up @@ -3041,8 +3028,16 @@ def tab_girder_sec(self, input_dictionary):
web_thickness = str(web_thk_list[0])
thickness_for_mat = float(web_thk_list[0])
else:
web_thickness = str(web_thk_list) if web_thk_list else '10'
thickness_for_mat = float(web_thk_list) if web_thk_list else 20
try:
thickness_for_mat = float(web_thk_list)
web_thickness = str(web_thk_list)
except (TypeError, ValueError):
# Non-numeric marker such as 'Customized' (Optimized mode). The real
# customized thickness list is consumed by the optimizer through its
# own path; use a default here so the design-preference preview can
# still estimate the section Fy instead of crashing on float().
web_thickness = '10'
thickness_for_mat = 20
else:
web_thickness = '10'
thickness_for_mat = 20
Expand Down Expand Up @@ -3075,7 +3070,12 @@ def tab_girder_sec(self, input_dictionary):
if isinstance(tf_top_list, list) and len(tf_top_list) > 0:
top_flange_thickness = str(tf_top_list[0])
else:
top_flange_thickness = str(tf_top_list) if tf_top_list else '15'
try:
float(tf_top_list)
top_flange_thickness = str(tf_top_list)
except (TypeError, ValueError):
# 'Customized' / other non-numeric marker -> use default for preview
top_flange_thickness = '15'
else:
top_flange_thickness = '15'

Expand All @@ -3093,7 +3093,12 @@ def tab_girder_sec(self, input_dictionary):
if isinstance(tf_bot_list, list) and len(tf_bot_list) > 0:
bottom_flange_thickness = str(tf_bot_list[0])
else:
bottom_flange_thickness = str(tf_bot_list) if tf_bot_list else '20'
try:
float(tf_bot_list)
bottom_flange_thickness = str(tf_bot_list)
except (TypeError, ValueError):
# 'Customized' / other non-numeric marker -> use default for preview
bottom_flange_thickness = '20'
else:
bottom_flange_thickness = '20'

Expand Down
9 changes: 8 additions & 1 deletion src/osdag_core/design_type/plate_girder/checks/deflection.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,14 @@ def evaluate_deflection_kNm_mm(M_kNm, L, E, case, criteria, total_depth, top_fla
# For now raising error to be caught or debugged if format is weird.
raise ValueError(f"Invalid deflection criteria format: {criteria}")
else:
n = float(criteria)
try:
n = float(criteria)
except (TypeError, ValueError):
# Guard against non-numeric criteria (e.g. 'NA', '') reaching the
# check via the optimization/PSO path, which bypasses the interactive
# validation in func_for_validation. Fail cleanly instead of with an
# opaque float() traceback.
raise ValueError(f"Invalid deflection criteria: {criteria}")
allowable = L / n # mm

# Check serviceability
Expand Down
31 changes: 15 additions & 16 deletions src/osdag_core/design_type/plate_girder/checks/shear.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,14 +267,11 @@ def tension_field_end_stiffener(d, tw, fyw, shear_force, moment, c, web_philosop
bottom_flange_thickness,
Nf, gamma_m0,
A_vg, tau_b)
V_tf= result[8]
V_dp = (d * tw * fyw * math.sqrt(3))
denom = V_tf - V_cr
if denom == 0: denom = 1e-6 # Avoid division by zero
rad = 1.0 - (V_cr - V_dp) / denom
if rad < 0:
return False, 0, 0, 0, 0, 0, IntStiffnerwidth, 0 # Fail
H_q = (shear_force - V_cr) / denom
V_tf = result[8]
V_dp = (d * tw * fyw) / math.sqrt(3)
rad = 1.0 - (V_cr / V_dp) if V_dp > 0 else 0
if rad < 0: rad = 0
H_q = 1.5 * V_dp * math.sqrt(rad)
R_tf = H_q / 2
A_v= d * tw
V_n= (fyw * A_v) /( math.sqrt(3) * gamma_m0)
Expand Down Expand Up @@ -458,13 +455,12 @@ def end_panel_stiffener_calc(Bf_top, Bf_bot, tw, tq, fy, gamma_m0, d, tf_top, to
V_tf = (A_vg * tau_b + 0.9 * w_tf * tw * fv * sinφ)
V_p = d * tw * fy / (math.sqrt(3) * gamma_m0)
V_tf = min(V_tf, V_p)
V_dp = (d * tw * fy / math.sqrt(3))
V_dp = (d * tw * fy) / math.sqrt(3)

rad = 1.0 - (V_cr / V_dp)
if rad < 0:
return False, end_stiffwidth, end_stiffthickness, 0, 0, 0, 0 # Fail
rad = 1.0 - (V_cr / V_dp) if V_dp > 0 else 0
if rad < 0: rad = 0

H_q = 1.25 * V_dp * math.sqrt(rad)
H_q = 1.5 * V_dp * math.sqrt(rad)
R_tf = H_q / 2
A_v = d * tw
V_n = (fy * A_v) / (math.sqrt(3) * gamma_m0)
Expand Down Expand Up @@ -577,11 +573,14 @@ def check_longitudinal_stiffener_required(d, tw, c, epsilon, debug=False):
"""
import math

# Handle c value
if c is None or c == 'NA' or c == 0:
# Handle c value (may be 'NA'/'N/A' for thick web, or non-numeric user text)
if c is None or c in ('NA', 'N/A') or c == 0:
c_val = 3.0 * d # Conservative large value if undefined
else:
c_val = float(c)
try:
c_val = float(c)
except (ValueError, TypeError):
c_val = 3.0 * d

d_tw_ratio = d / tw

Expand Down
23 changes: 13 additions & 10 deletions src/osdag_core/design_type/plate_girder/checks/web_crippling.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,23 +50,26 @@ def check_web_crippling_IS800(shear_force, b1, tw, fy, d, tf, gamma_m0, logger,

# DDCL Eq 2.45: P_crip = (b1 + n2) * tw * fyw / gamma_m0
P_crip = (b1 + n2) * tw * fy / gamma_m0

# Additional slenderness warning
if d/tw > 200:
logger.warning("Web slenderness ratio (d/tw) exceeds 200. Additional stiffening may be required.")


# NOTE: The web-slenderness (d/tw > 200) warning is intentionally NOT logged here.
# Like the crippling-shortfall warning below, this function runs once per particle
# per PSO iteration; logging here floods the design log. It is logged once per run
# in PlateGirderWelded.set_input_values instead.

# Safety check
is_safe = P_crip >= shear_force

if debug:
print(f"[DEBUG] Web Crippling (IS 800 Cl. 8.7.4):")
print(f"[DEBUG] b1={b1:.2f}, n2={n2:.2f}, tw={tw:.2f}, fy={fy:.2f}")
print(f"[DEBUG] P_crip = ({b1:.2f} + {n2:.2f}) * {tw:.2f} * {fy:.2f} / {gamma_m0} = {P_crip:.2f} N")
print(f"[DEBUG] Applied={shear_force:.2f} N, Ratio={shear_force/P_crip if P_crip > 0 else 100:.4f}")

if not is_safe:
logger.warning(f"Web crippling resistance ({P_crip:.2f} N) is less than factored load ({shear_force:.2f} N)")


# NOTE: The "resistance less than factored load" warning is intentionally NOT logged here.
# This function is evaluated once per particle per iteration during PSO optimization, which
# would flood the design log with identical messages. The caller logs it once for the final
# design (see PlateGirderWelded.design_check / web_crippling_warning_logged).

return is_safe, P_crip

except Exception as e:
Expand Down
Loading