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
3 changes: 3 additions & 0 deletions src/osdag/Common.py
Original file line number Diff line number Diff line change
Expand Up @@ -2053,6 +2053,9 @@ def is_valid_custom(self):
KEY_OUT_DISP_WELD_LENGTH = 'Length (mm)'
KEY_OUT_WELD_LENGTH_EFF = 'Weld.EffLength'
KEY_OUT_DISP_WELD_LENGTH_EFF = 'Eff.Length (mm)'
KEY_PLATE_THICKNESS_1 = "plate_thickness_1"
KEY_PLATE_THICKNESS_2 = "plate_thickness_2"
KEY_PLATE_WIDTH = "plate_width"

KEY_OUT_DISP_MEMB_TEN_YIELD = 'Tension Yield Capacity (KN)'
KEY_OUT_DISP_MEMB_TEN_RUPTURE = 'Tension Rupture Capacity'
Expand Down
219 changes: 180 additions & 39 deletions src/osdag/design_type/tension_member/tension_bolted.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,11 @@ def customized_input(self):
# c_lst.append(t5)

return c_lst

@staticmethod
def plate_thick_customized(*args):
"""Return customized plate thickness values"""
return VALUES_PLATETHK_CUSTOMIZED

def fn_profile_section(self):

Expand Down Expand Up @@ -308,6 +313,29 @@ def input_value_changed(self):
t3 = ([KEY_SEC_PROFILE], KEY_IMAGE, TYPE_IMAGE, self.fn_conn_image)
lst.append(t3)

t_flat = ([KEY_SEC_PROFILE], KEY_LOCATION, TYPE_TEXTBOX, self.hide_for_flat_plate)
lst.append(t_flat)

t_flat2 = ([KEY_SEC_PROFILE], KEY_SECSIZE, TYPE_TEXTBOX, self.hide_for_flat_plate)
lst.append(t_flat2)

t_flat3 = ([KEY_SEC_PROFILE], KEY_LENGTH, TYPE_TEXTBOX, self.hide_for_flat_plate)
lst.append(t_flat3)

# Add handling for regular plate thickness
t_flat7 = ([KEY_SEC_PROFILE], KEY_PLATETHK, TYPE_TEXTBOX, self.hide_for_flat_plate)
lst.append(t_flat7)

# Modified: Handle Flat Plate thickness fields
t_flat4 = ([KEY_SEC_PROFILE], KEY_PLATE_THICKNESS_1, TYPE_COMBOBOX, self.fn_flat_plate_thickness)
lst.append(t_flat4)

t_flat5 = ([KEY_SEC_PROFILE], KEY_PLATE_THICKNESS_2, TYPE_COMBOBOX, self.fn_flat_plate_thickness)
lst.append(t_flat5)

t_flat6 = ([KEY_SEC_PROFILE], KEY_PLATE_WIDTH, TYPE_TEXTBOX, self.show_for_flat_plate)
lst.append(t_flat6)

t4 = ([KEY_TYP], KEY_OUT_BOLT_BEARING, TYPE_OUT_DOCK, self.out_bolt_bearing)
lst.append(t4)

Expand Down Expand Up @@ -374,6 +402,22 @@ def input_value_changed(self):
t9 = ([KEY_SECSIZE],KEY_SECSIZE,TYPE_CUSTOM_SECTION,self.new_material)
lst.append(t9)
return lst

def hide_for_flat_plate(self):
"""Hide fields when Flat Plate is selected"""
sec_type = self[0]
if sec_type == 'Flat Plate':
return [] # Return empty list to hide/disable the field
return VALUES_PLATETHK_CUSTOMIZED # Return the list of values to show/enable the field

@staticmethod
def show_for_flat_plate(sec_type):
"""Show fields only when Flat Plate is selected"""
if isinstance(sec_type, (list, tuple)):
sec_type = sec_type[0] if sec_type else None
if sec_type == 'Flat Plate':
return VALUES_PLATETHK_CUSTOMIZED # Return the list of values to show/enable the field
return [] # Return empty list to hide/disable the field

def fn_conn_type(self):

Expand All @@ -383,6 +427,9 @@ def fn_conn_type(self):
return VALUES_LOCATION_1
elif conn in ["Channels", "Back to Back Channels"]:
return VALUES_LOCATION_2

elif conn == 'Flat Plate':
return []

def fn_conn_image(self):

Expand All @@ -396,8 +443,11 @@ def fn_conn_image(self):
return VALUES_IMG_TENSIONBOLTED[2]
elif img ==VALUES_SEC_PROFILE_2[3]:
return VALUES_IMG_TENSIONBOLTED[3]
elif img == 'Flat Plate':
return VALUES_IMG_TENSIONBOLTED[0]
else:
return VALUES_IMG_TENSIONBOLTED[4]


def out_bolt_bearing(self):

Expand Down Expand Up @@ -434,7 +484,7 @@ def input_values(self, existingvalues={}):
t1 = (None, DISP_TITLE_CM, TYPE_TITLE, None, True, 'No Validator')
options_list.append(t1)

t2 = (KEY_SEC_PROFILE, KEY_DISP_SEC_PROFILE, TYPE_COMBOBOX, VALUES_SEC_PROFILE_2, True, 'No Validator')
t2 = (KEY_SEC_PROFILE, KEY_DISP_SEC_PROFILE, TYPE_COMBOBOX, VALUES_SEC_PROFILE_2 + ['Flat Plate'], True, 'No Validator')
options_list.append(t2)

t15 = (KEY_IMAGE, None, TYPE_IMAGE, VALUES_IMG_TENSIONBOLTED[0], True, 'No Validator')
Expand All @@ -453,30 +503,31 @@ def input_values(self, existingvalues={}):
t5 = (KEY_LENGTH, KEY_DISP_LENGTH, TYPE_TEXTBOX, None, True, 'Int Validator')
options_list.append(t5)

t_flat1 = (KEY_PLATE_THICKNESS_1, "Thickness of Plate-1 (mm)", TYPE_COMBOBOX, [], False, 'Int Validator')
options_list.append(t_flat1)

t_flat2 = (KEY_PLATE_THICKNESS_2, "Thickness of Plate-2 (mm)", TYPE_COMBOBOX, [], False, 'Int Validator')
options_list.append(t_flat2)

t_flat6 = (KEY_PLATE_WIDTH, "Width of Plate (mm)", TYPE_TEXTBOX, Tension_bolted.show_for_flat_plate, True, 'Float Validator')
options_list.append(t_flat6)

t6 = (None, DISP_TITLE_FSL, TYPE_TITLE, None, True, 'No Validator')
options_list.append(t6)

t7 = (KEY_AXIAL, KEY_DISP_AXIAL_STAR, TYPE_TEXTBOX, None, True, 'Int Validator')
options_list.append(t7)

t8 = (None, DISP_TITLE_BOLT, TYPE_TITLE, None, True, 'No Validator')
options_list.append(t8)

t10 = (KEY_D, KEY_DISP_D, TYPE_COMBOBOX_CUSTOMIZED, VALUES_D, True, 'No Validator')
options_list.append(t10)

t11 = (KEY_TYP, KEY_DISP_TYP, TYPE_COMBOBOX, VALUES_TYP, True, 'No Validator')
options_list.append(t11)

t12 = (KEY_GRD, KEY_DISP_GRD, TYPE_COMBOBOX_CUSTOMIZED, VALUES_GRD, True, 'No Validator')
options_list.append(t12)

t13 = (None, DISP_TITLE_PLATE, TYPE_TITLE, None, True, 'No Validator')
options_list.append(t13)

t14 = (KEY_PLATETHK, KEY_DISP_PLATETHK, TYPE_COMBOBOX_CUSTOMIZED, VALUES_PLATETHK, True, 'No Validator')
options_list.append(t14)

return options_list

def spacing(self, status):
Expand Down Expand Up @@ -734,10 +785,13 @@ def func_for_validation(self, design_dictionary):

for option in option_list:
if option[2] == TYPE_TEXTBOX:
# Only require plate width for Flat Plate
if option[0] == KEY_PLATE_WIDTH:
sec_profile = design_dictionary.get(KEY_SEC_PROFILE, None)
if sec_profile != 'Flat Plate':
continue # skip validation for non-Flat Plate
if design_dictionary[option[0]] == '':

print(f"\n option {option}")

missing_fields_list.append(option[1])
else:
if option[2] == TYPE_TEXTBOX and option[0] == KEY_LENGTH:
Expand Down Expand Up @@ -1688,33 +1742,112 @@ def get_plate_thickness(self,design_dictionary):

self.plate_last = self.plate.thickness[-1]


# if design_dictionary[KEY_TYP] == 'Bearing Bolt':
# self.bolt_bearing_capacity = IS800_2007.cl_10_3_4_bolt_bearing_capacity(f_u=self.bolt.fu_considered, f_ub=self.bolt.bolt_fu, t=self.bolt.thk_considered, d=self.bolt.bolt_diameter_provided,
# e=self.plate.end_dist_provided, p=self.plate.pitch_provided, bolt_hole_type=self.bolt.bolt_hole_type)
#
# self.bolt.kb = self.bolt.calculate_kb(e=self.plate.end_dist_provided, p=self.plate.pitch_provided, d_0= self.bolt.dia_hole, f_ub=self.bolt.bolt_fu,f_u=self.bolt.fu_considered)
#
# self.bolt.bolt_bearing_capacity = self.bolt_bearing_capacity
#
#
# self.bolt.bolt_capacity = min(self.bolt.bolt_bearing_capacity,self.bolt.bolt_shear_capacity)
# else:
# pass


# capacity = False
# while capacity == False:
# self.plate.bolt_capacity_red = self.plate.get_bolt_red(self.plate.bolts_one_line,
# self.plate.gauge_provided, self.plate.bolt_line,
# self.plate.pitch_provided, self.bolt.bolt_capacity,
# self.bolt.bolt_diameter_provided,beta_lg=self.bolt.beta_lg)
# # if self.plate.bolt_force < self.plate.bolt_capacity_red:
# # capacity = True
# break
# else:
# self.plate.bolt_line = self.plate.bolt_line + 1
# self.plate.bolt_force = self.res_force/(self.plate.bolt_line * self.plate.bolts_one_line)
if design_dictionary[KEY_SEC_PROFILE] == "Flat Plate":
self.sec_profile = "Flat Plate" # Ensure sec_profile is set for Flat Plate
print("Flat Plate calculation triggered")
import math
# 1. Extract input values
plate1_thk = float(design_dictionary.get(KEY_PLATE_THICKNESS_1, 0))
plate2_thk = float(design_dictionary.get(KEY_PLATE_THICKNESS_2, 0))
plate_width = float(design_dictionary.get(KEY_PLATE_WIDTH, 0))
plate_length = float(design_dictionary.get(KEY_LENGTH, 0))
material = design_dictionary.get(KEY_SEC_MATERIAL, None)
axial_force = float(design_dictionary.get(KEY_AXIAL, 0)) # in kN
bolt_dia = float(design_dictionary.get(KEY_D, 0))
# IS 800:2007 Table 5
gamma_m0 = 1.1
gamma_m1 = 1.25
# 2. Calculate bolt hole diameter (d0)
d0 = bolt_dia + 2 # Standard clearance for M16-M22
# 3. Calculate gross and net area for both plates
def calc_areas(thk):
Ag = plate_width * thk
An = (plate_width - d0) * thk
return Ag, An
Ag1, An1 = calc_areas(plate1_thk)
Ag2, An2 = calc_areas(plate2_thk)
# 4. Get material properties (dummy values, replace with DB lookup if needed)
if material == 'E 165 (Fe 290)':
fy = 165
fu = 290
elif material == 'E 250 (Fe 410)':
fy = 250
fu = 410
else:
fy = 250
fu = 410
# 5. Calculate strengths
Tdg1 = Ag1 * fy / gamma_m0
Tdg2 = Ag2 * fy / gamma_m0
Tdn1 = 0.9 * An1 * fu / gamma_m1
Tdn2 = 0.9 * An2 * fu / gamma_m1
# 6. Block shear (simplified for flat plate)
def block_shear(thk):
Avg = (plate_length - d0) * thk
Avn = Avg - d0 * thk
Atg = (plate_width - d0) * thk
Atn = Atg - d0 * thk
Tdb1 = (Avg * fy) / (math.sqrt(3) * gamma_m0) + (0.9 * Atn * fu) / gamma_m1
Tdb2 = (0.9 * Avn * fu) / (math.sqrt(3) * gamma_m1) + (Atg * fy) / gamma_m0
return min(Tdb1, Tdb2)
Tdb1 = block_shear(plate1_thk)
Tdb2 = block_shear(plate2_thk)
# 7. Bolt design strength (placeholder, replace with real calculation)
try:
A_sb, A_nb = IS1367_Part3_2002.bolt_area(bolt_dia)
f_ub, f_yb = IS1367_Part3_2002.get_bolt_fu_fy(bolt_grade, bolt_dia)
n_n = 1 # 1 shear plane with threads for lap joint
n_s = 0
# Use safe defaults for e and p
e = 1.7 * bolt_dia
p = 2.5 * bolt_dia
t = plate1_thk + plate2_thk
Vdsb = IS800_2007.cl_10_3_3_bolt_shear_capacity(
f_ub=f_ub, A_nb=A_nb, A_sb=A_sb, n_n=n_n, n_s=n_s, safety_factor_parameter='shop'
)
Vdpb = IS800_2007.cl_10_3_4_bolt_bearing_capacity(
f_u=fu, f_ub=f_ub, t=t, d=bolt_dia, e=e, p=p, bolt_hole_type='Standard', safety_factor_parameter='shop'
)
Vdb = min(Vdsb, Vdpb)
if Vdb <= 0 or math.isnan(Vdb):
Vdb = 40000 # fallback to placeholder if error
except Exception as ex:
Vdb = 40000 # fallback to placeholder if error
n_bolts = math.ceil((axial_force * 1000) / Vdb) if Vdb > 0 else 1
# 8. Utilization ratios
min1 = min(Tdg1, Tdn1, Tdb1)
min2 = min(Tdg2, Tdn2, Tdb2)
util1 = (axial_force * 1000) / min1 if min1 > 0 else 0
util2 = (axial_force * 1000) / min2 if min2 > 0 else 0
# 9. Set expected attributes for compatibility
self.plate_tension_capacity = min(min1, min2)
self.design_status = util1 <= 1.0 and util2 <= 1.0
self.plate_design_status = self.design_status
self.bolt_design_status = True # or set based on your logic
# Optionally, store results for UI
self.flat_plate_results = {
'Plate1': {
'Gross Area': Ag1,
'Net Area': An1,
'Yielding Strength': Tdg1,
'Rupture Strength': Tdn1,
'Block Shear': Tdb1,
'Utilization': util1,
'Bolts Required': n_bolts
},
'Plate2': {
'Gross Area': Ag2,
'Net Area': An2,
'Yielding Strength': Tdg2,
'Rupture Strength': Tdn2,
'Block Shear': Tdb2,
'Utilization': util2,
'Bolts Required': n_bolts
}
}
# Use a static image for flat plate (if needed)
self.flat_plate_image = 'flat_plate.png'
return


self.plate.length = (self.plate.bolt_line - 1) * self.plate.pitch_provided + 2 * self.plate.end_dist_provided
Expand Down Expand Up @@ -2757,4 +2890,12 @@ def save_design(self, popup_summary):


CreateLatex.save_latex(CreateLatex(), self.report_input, self.report_check, popup_summary, fname_no_ext,
rel_path, Disp_2d_image, Disp_3D_image, module=self.module)
rel_path, Disp_2d_image, Disp_3D_image, module=self.module)


def fn_flat_plate_thickness(self, *args):
"""Return plate thickness values for Flat Plate, or empty list otherwise."""
sec_type = self[0] if hasattr(self, '__getitem__') else args[0] if args else None
if sec_type == 'Flat Plate':
return VALUES_PLATETHK_CUSTOMIZED
return []