diff --git a/src/osdag/Common.py b/src/osdag/Common.py index bd5c20630..e597ace07 100644 --- a/src/osdag/Common.py +++ b/src/osdag/Common.py @@ -298,6 +298,7 @@ def is_valid_custom(self): TYPE_TITLE = 'Title' TYPE_LABEL = 'Label' TYPE_IMAGE = 'Image' +TYPE_IMAGE_BIGGER = 'Image_Bigger' TYPE_IMAGE_COMPRESSION = 'Image_compression' TYPE_COMBOBOX_CUSTOMIZED = 'ComboBox_Customized' TYPE_IN_BUTTON = 'Input_dock_Button' @@ -346,6 +347,9 @@ def is_valid_custom(self): KEY_DISP_COLUMNCOVERPLATE = 'Column-to-Column Cover Plate Bolted Connection' KEY_DISP_BEAMCOVERPLATEWELD = 'Beam-to-Beam Cover Plate Welded Connection' KEY_DISP_COLUMNCOVERPLATEWELD = 'Column-to-Column Cover Plate Welded Connection' +KEY_DISP_LAPJOINTBOLTED = 'Lap Joint Bolted Connection' +KEY_DISP_LAPJOINTWELDED = 'Lap Joint Welded Connection' +KEY_DISP_BUTTJOINTBOLTED = 'Butt Joint Bolted Connection' # KEY_DISP_BEAMENDPLATE = 'Beam End Plate Connection' KEY_DISP_COLUMNENDPLATE = 'Column-to-Column End Plate Connection' KEY_DISP_BCENDPLATE = 'Beam-to-Column End Plate Connection' @@ -449,7 +453,7 @@ def is_valid_custom(self): KEY_EULER_BUCKLING_STRESS = 'MajorBucklingStress' KEY_DISP_EULER_BUCKLING_STRESS = 'Buckling Stress (MPa)' # Euler KEY_EFF_SEC_AREA = 'MajorEffSecArea' -KEY_DISP_EFF_SEC_AREA = 'Eff. Sectional Area (mm2)' # ective +KEY_DISP_EFF_SEC_AREA = 'Eff. Sectional Area (cm2)' # ective KEY_EFF_LEN = 'Major.Effective_Length' KEY_DISP_EFF_LEN = 'Eff. Length (m)' # ective KEY_BUCKLING_CURVE = 'BucklingCurve' @@ -543,8 +547,8 @@ def is_valid_custom(self): KEY_DISP_LTB= 'Lateral Torsional Buckling Details' KEY_DISP_Elastic_CM= 'Critical Moment (Mcr)' # Elastic KEY_DISP_Elastic_CM_latex= 'Elastic Critical Moment(kNm)' # -KEY_DISP_T_constatnt= 'Torsional Constant (mm4)' # (It) -KEY_DISP_W_constatnt= 'Warping Constant (mm6)' # (Iw) +KEY_DISP_T_constatnt= 'Torsional Constant (cm4)' # (It) +KEY_DISP_W_constatnt= 'Warping Constant (cm6)' # (Iw) KEY_LTB= 'L.T.B.Details' KEY_Elastic_CM= 'Elastic.Moment' KEY_T_constatnt= 'T.Constant' @@ -591,17 +595,17 @@ def is_valid_custom(self): KEY_DISP_LOAD2 = 'Destabilizing' KEY_DISP_LOAD_list = list((KEY_DISP_LOAD1, KEY_DISP_LOAD2)) KEY_TORSIONAL_RES = 'Torsion.restraint' -DISP_TORSIONAL_RES = 'Torsional restraint *' +DISP_TORSIONAL_RES = 'Torsional Restraint *' Torsion_Restraint1 = 'Fully Restrained' Torsion_Restraint2 = 'Partially Restrained-support connection' Torsion_Restraint3 = 'Partially Restrained-bearing support' Torsion_Restraint_list = list(( Torsion_Restraint1, Torsion_Restraint2, Torsion_Restraint3)) KEY_WARPING_RES = 'Warping.restraint' -DISP_WARPING_RES = 'Warping restraint *' +DISP_WARPING_RES = 'Warping Restraint *' Warping_Restraint1 = 'Both flanges fully restrained' Warping_Restraint2 = 'Compression flange fully restrained' # Warping_Restraint3 = 'Both flanges fully restrained' -Warping_Restraint4 = 'Compressicm flange partially restrained' +Warping_Restraint4 = 'Compression flange partially restrained' Warping_Restraint5 = 'Warping not restrained in both flanges' Warping_Restraint_list = list(( Warping_Restraint1, Warping_Restraint2, Warping_Restraint4, Warping_Restraint5)) DISP_SUPPORT_RES = 'Support restraint *' @@ -646,7 +650,8 @@ def is_valid_custom(self): # Plate Girder ################################### KEY_PLATE_GIRDER_MAIN_MODULE = 'PLATE GIRDER' -KEY_DISP_PLATE_GIRDER_WELDED = 'PLATE GIRDER - WELDED' +KEY_DISP_PLATE_GIRDER_WELDED = 'PLATE GIRDER' +KEY_DISP_PG_SectionDetail = 'Section Details' KEY_tf = 'TF.Data' KEY_tw = 'TW.Data' KEY_dw = 'DW.Data' @@ -660,6 +665,103 @@ def is_valid_custom(self): KEY_DISP_Plate_Girder_PROFILE = 'Section Profile' KEY_IntermediateStiffener_spacing = 'IntermediateStiffener.Spacing' KEY_DISP_IntermediateStiffener_spacing = 'Intermediate Stiffener Spacing' +KEY_LongitudnalStiffener = 'LongitudnalStiffener.Data' +KEY_LongitudnalStiffener_thickness = 'LongitudnalStiffner.Thickness' +KEY_LongitudnalStiffener_thickness_val = 'LongitudnalStiffner.Thickness.val' +KEY_DISP_LongitudnalStiffener = 'Longitudnal Stiffener' +KEY_DISP_LongitudnalStiffener_thickness = 'Longitudnal Stiffener Thickness' +KEY_IntermediateStiffener_thickness = 'IntermediateStiffener.Thickness' +KEY_IntermediateStiffener_thickness_val = 'IntermediateStiffener.Thickness.val' +KEY_DISP_IntermediateStiffener_thickness = 'Intermediate Stiffener Thickness' +KEY_WeldWebtoflange= 'WeldWebtoflange.Data' +KEY_DISP_WeldWebtoflange= 'Weld for Web to Flange' +KEY_WeldStiffenertoweb= 'WeldStiffenertoweb.Data' +KEY_DISP_WeldStiffenertoweb= 'Weld for Stiffener to Web' +KEY_IS_IT_SYMMETRIC = 'Girder.Symmetry' +KEY_DISP_IS_IT_SYMMETRIC = 'Symmetry' +KEY_DISP_SYM = 'Symmetric Girder' +KEY_DISP_UNSYM = 'Unsymmetric Girder' +KEY_DISP_SYMMETRIC_list = list((KEY_DISP_SYM, KEY_DISP_UNSYM)) +KEY_TOP_FLANGE_THICKNESS_PG = 'TopFlange.Thickness' +KEY_DISP_TOP_FLANGE_THICKNESS_PG = 'Top Flange Thickness (mm)' +KEY_OVERALL_DEPTH_PG = 'Total.Depth' +KEY_OVERALL_DEPTH_PG_TYPE = 'Total.Design_Type' +KEY_DISP_OVERALL_DEPTH_PG_TYPE = 'Design Type' +KEY_DISP_OVERALL_DEPTH_PG = 'Total Depth (mm)' +KEY_WEB_THICKNESS_PG = 'Web.Thickness' +KEY_DISP_WEB_THICKNESS_PG = 'Web Thickness (mm)' +KEY_TOP_Bflange_PG_Type = 'Topflange.Width_Type' +KEY_DISP_TOP_Bflange_PG_Type = 'Top Flange Width Type' +KEY_TOP_Bflange_PG = 'Topflange.Width' +KEY_DISP_TOP_Bflange_PG = 'Width of Top Flange (mm)' +KEY_BOTTOM_Bflange_PG_Type = 'Bottomflange.Width_Type' +KEY_DISP_BOTTOM_Bflange_PG_Type = 'Bottom Flange Width Type' +KEY_BOTTOM_Bflange_PG = 'Bottomflange.Width' +KEY_DISP_BOTTOM_Bflange_PG = 'Width of Bottom Flange (mm)' +KEY_BOTTOM_FLANGE_THICKNESS_PG = 'BottomFlange.Thickness' +KEY_DISP_BOTTOM_FLANGE_THICKNESS_PG = 'Bottom Flange Thickness (mm)' +KEY_STR_TYPE = 'Structure.Type' +KEY_DISP_STR_TYPE = 'Type of Structure' +KEY_WEB_PHILOSOPHY = 'Web.Philosophy' +KEY_DISP_WEB_PHILOSOPHY = 'Web Philosophy' +KEY_DISP_SECTION_DATA_PG = 'Design Inputs' +KEY_LOADING = 'Factored Maximum Loads' +KEY_DISP_STR_TYP1 = 'Highway Bridge' +KEY_DISP_STR_TYP2 = 'Railway Bridge' +KEY_DISP_STR_TYP3 = 'Industrial Structure' +KEY_DISP_STR_TYP4 = 'Other Building' +KEY_DISP_STR_TYPE_list = [KEY_DISP_STR_TYP1, KEY_DISP_STR_TYP2, KEY_DISP_STR_TYP3,KEY_DISP_STR_TYP4] +KEY_DISP_PHILO1 = 'Thin Web with ITS' +KEY_DISP_PHILO2 = 'Thick Web without ITS' +WEB_PHILOSOPHY_list = list((KEY_DISP_PHILO1, KEY_DISP_PHILO2)) +KEY_DISP_DESIGN_STIFFER = 'Stiffener Design' +KEY_DISP_WELD_DESIGN = 'Weld Design' +KEY_BENDING_MOMENT_SHAPE= 'Bendingmoment.shape' +KEY_DISP_BENDING_MOMENT_SHAPE='Bending Moment Shape' +KEY_UDL_PIN_PIN_PG='UDLPINPIN.Data' +KEY_DISP_UDL_PIN_PIN_PG='Uniform Loading with pinned-pinned support' +KEY_UDL_FIX_FIX_PG= 'UDLFIXFIX.Data' +KEY_DISP_UDL_FIX_FIX_PG= 'Uniform Loading with fixed-fixed support' +KEY_PL_PIN_PIN_PG= 'PLPINPIN.Data' +KEY_DISP_PL_PIN_PIN_PG='Concentrate Load with pinned-pinned support' +KEY_PL_FIX_FIX_PG= 'PLFIXFIX.Data' +KEY_DISP_PL_FIX_FIX_PG= 'Concentrate load with fixed-fixed support' +KEY_DISP_GIRDERSEC = 'Girder Properties' +Bending_moment_shape_list= list((KEY_DISP_UDL_PIN_PIN_PG, KEY_DISP_UDL_FIX_FIX_PG, KEY_DISP_PL_PIN_PIN_PG,KEY_DISP_PL_FIX_FIX_PG)) +VALUES_DEPTH_PG = ['Customized','Optimized'] +VALUES_OPT = ['All'] +KEY_DESIGN_LOAD = 'Design.Load' +KEY_DISP_DESIGN_LOAD = 'Design Load' +VALUE_DESIGN_LOAD_list = ['Live load','Dead load', 'Crane Load(Manual operation)', 'Crane load(Electric operation up to 50t)', 'Crane load(Electric operation over 50t)'] +KEY_MEMBER_OPTIONS = 'Member.Options' +KEY_DISP_MEMBER_OPTIONS = 'Member Options' +# VALUES_MEMBER_OPTIONS_INDUS = ['Purlin and Girts', 'Simple span', 'Cantilever span', 'Rafter Supporting', 'Gantry'] +# VALUES_MEMBER_OPTIONS_OTHER = ['Floor and roof', 'Cantilever'] +# VALUES_MEMBER_OPTIONS_BRIDGE = ['Simple span', 'Cantilever span'] +VALUES_MEMBER_OPTIONS = [['Simple Span', 'Cantilever Span'],['Purlin and Girts', 'Simple span', 'Cantilever span', 'Rafter Supporting', 'Gantry'], ['Floor and roof', 'Cantilever']] +KEY_SUPPORTING_OPTIONS = 'Supporting.Options' +KEY_DISP_SUPPORTING_OPTIONS = 'Supporting Options' +VALUES_SUPPORTING_OPTIONS_PSC = ['Elastic cladding', 'Brittle cladding'] +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'] +KEY_MAX_DEFL = 'Deflection.Max' +KEY_DISP_MAX_DEFL = 'Maximum Deflection' +VALUES_MAX_DEFL = ['600','800','400','300','360','150','180','240','120','500','750','1000'] +KEY_SUPPORT_WIDTH = 'Support.Width' +KEY_DISP_SUPPORT_WIDTH = 'Support Width (mm)' +VALUES_STIFFENER_THICKNESS = ['8', '10', '12', '14', '16', '18', '20', '22', '25', '28', '32', '36', '40', '45', '50', '56', '63', '75', '80', '90', '100', + '110', '120'] +KEY_EndpanelStiffener_thickness = 'EndpanelStiffener.Thickness' +KEY_DISP_EndpanelStiffener_thickness = 'End Panel Stiffener Thickness (mm)' +KEY_LongitudnalStiffener_numbers = 'LongitudnalStiffener.Numbers' +KEY_DISP_LongitudnalStiffener_numbers = 'Number of Longitudnal Stiffeners' +KEY_LongitudinalStiffener1_pos = 'LongitudnalStiffener1.Position' +KEY_DISP_LongitudinalStiffener1_pos = 'Position of Longitudnal Stiffener 1 from NA (mm) ' +KEY_LongitudinalStiffener2_pos = 'LongitudnalStiffener2.Position' +KEY_DISP_LongitudinalStiffener2_pos = 'Position of Longitudnal Stiffener 2 from NA (mm)' + ################################### # All Input Keys ################################### @@ -758,7 +860,7 @@ def is_valid_custom(self): KEY_DP_DETAILING_EDGE_TYPE = 'Detailing.Edge_type' KEY_DP_DETAILING_GAP = 'Detailing.Gap' KEY_DP_DETAILING_CORROSIVE_INFLUENCES = 'Detailing.Corrosive_Influences' - +KEY_DP_DETAILING_PACKING_PLATE = 'Detailing.Packing_Plate' KEY_DP_DESIGN_METHOD = 'Design.Design_Method' ################### @@ -777,6 +879,7 @@ def is_valid_custom(self): # VALUES_CONN_BP = ['Welded Column Base', 'Welded+Bolted Column Base', 'Moment Base Plate', 'Hollow/Tubular Column Base'] VALUES_CONN_BP = ['Welded Column Base', 'Moment Base Plate', 'Hollow/Tubular Column Base'] VALUES_LOCATION = ['Select Location','Long Leg', 'Short Leg', 'Web'] +VALUES_COVER_PLATE = ['Single-Cover', 'Double-Cover'] # TODO: Every one is requested to use VALUES_ALL_CUSTOMIZED key instead of all other keys VALUES_ALL_CUSTOMIZED = ['All', 'Customized'] @@ -830,7 +933,11 @@ def is_valid_custom(self): VALUES_DIAM = connectdb("Bolt") # VALUES_DIAM = ['Select diameter','12','16','20','24','30','36'] - +VALUES_IMAGE_PLATEGIRDER = [str(files("osdag.data.ResourceFiles.images").joinpath("ULPPS_PG.png")), + str(files("osdag.data.ResourceFiles.images").joinpath("ULFFS_PG.png")), + str(files("osdag.data.ResourceFiles.images").joinpath("CLPPS_PG.png")), + str(files("osdag.data.ResourceFiles.images").joinpath("CLFFS_PG.png")), + str(files("osdag.data.ResourceFiles.images").joinpath("CLPPSPB_PG.png"))] VALUES_IMG_TENSIONBOLTED = [str(files("osdag.data.ResourceFiles.images").joinpath("bA.png")),str(files("osdag.data.ResourceFiles.images").joinpath("bBBA.png")),str(files("osdag.data.ResourceFiles.images").joinpath("bSA.png")),str(files("osdag.data.ResourceFiles.images").joinpath("bC.png")),str(files("osdag.data.ResourceFiles.images").joinpath("bBBC.png"))] VALUES_IMG_TENSIONWELDED = [str(files("osdag.data.ResourceFiles.images").joinpath("wA.png")),str(files("osdag.data.ResourceFiles.images").joinpath("wBBA.png")),str(files("osdag.data.ResourceFiles.images").joinpath("wSA.png")),str(files("osdag.data.ResourceFiles.images").joinpath("wC.png")),str(files("osdag.data.ResourceFiles.images").joinpath("wBBC.png"))] VALUES_IMG_TENSIONBOLTED_DF01 = [str(files("osdag.data.ResourceFiles.images").joinpath("equaldp.png")),str(files("osdag.data.ResourceFiles.images").joinpath("bblequaldp.png")),str(files("osdag.data.ResourceFiles.images").joinpath("bbsequaldp.png")),str(files("osdag.data.ResourceFiles.images").joinpath("salequaldp.png")),str(files("osdag.data.ResourceFiles.images").joinpath("sasequaldp.png"))] @@ -885,6 +992,7 @@ def is_valid_custom(self): DISP_MAX_CLEAT_HEIGHT = 'Max. Cleat Angle Height' DISP_MIN_CLEAT_THK = 'Min. Cleat Angle Thickness (mm)' DISP_MIN_WIDTH = 'Minimum Width (mm)' + DISP_MIN_PLATE_THICK = 'Min. Plate Thickness (mm)' ######### Minimun for Flange#### @@ -938,6 +1046,19 @@ def is_valid_custom(self): # VALUES_CONN_BP = ['Welded-Slab Base', 'Bolted-Slab Base', 'Gusseted Base Plate', 'Hollow Section'] +#lapjointbolted +KEY_PLATE1_THICKNESS = "Plate1Thickness" +KEY_PLATE2_THICKNESS = "Plate2Thickness" +KEY_PLATE_WIDTH = "PlateWidth" +KEY_DISP_PLATE1_THICKNESS = "Thickness of Plate-1 (mm) *" +KEY_DISP_PLATE2_THICKNESS = "Thickness of Plate-2 (mm) *" +KEY_DISP_PLATE_WIDTH = "Width of Plate (mm) *" +KEY_TENSILE_FORCE = "TensileForce*" +KEY_DISP_TENSILE_FORCE = "Tensile Force (kN) *" + +KEY_COVER_PLATE = "ButtJoint.CoverPlate" +KEY_DISP_COVER_PLATE = "Cover Plate" + KEY_DISP_LENGTH = 'Length (mm) *' KEY_DISP_LOCATION = 'Conn_Location *' KEY_DISP_LOCATION_STRUT = 'Connection *' @@ -1310,6 +1431,7 @@ def is_valid_custom(self): DISP_TITLE_INTERMITTENT = 'Intermittent Connection' DISP_TITLE_BOLTD = 'Bolt Details' +DISP_TITLE_BOLTDS = 'Bolt Design' DISP_TITLE_PLATED = 'Plate Details' KEY_DISP_DP_DETAILING_GAP = 'Gap Between Beam and
Support (mm)' @@ -1319,6 +1441,7 @@ def is_valid_custom(self): KEY_DISP_DP_DETAILING_CORROSIVE_INFLUENCES_BEAM = 'Are the Members Exposed to Corrosive Influences?' KEY_DISP_CORR_INFLUENCES = 'Members exposed to corrosive influences?' KEY_DISP_DP_DESIGN_METHOD = 'Design Method' +KEY_DISP_DP_DETAILING_PACKING_PLATE = 'Packing Plate' KEY_DISP_DP_DESIGN_BASE_PLATE = 'Base Plate Analysis' KEY_DISP_GAP = 'Gap Between Members (mm)' @@ -1799,6 +1922,8 @@ def is_valid_custom(self): KEY_OUT_GRD_PROVIDED = 'Bolt.Grade_Provided' +KEY_OUT_DISP_TYP_PROVIDED = 'Type' +KEY_OUT_TYP_PROVIDED = 'Bolt.Type_Provided' KEY_OUT_DISP_GRD_PROVIDED = 'Property Class' KEY_OUT_INTER_GRD_PROVIDED = 'Bolt.InterGrade' KEY_OUT_DISP_INTER_GRD_PROVIDED = 'Grade' @@ -1818,6 +1943,11 @@ def is_valid_custom(self): KEY_DISP_BOLT_HOLE = 'Hole Diameter (mm)' KEY_DISP_MIN_BOLT = 'Minimum Bolts (nos)' +KEY_OUT_BOLT_CONN_LEN = 'Bolt.ConnLength' +KEY_UTILIZATION_RATIO = 'Bolt.UtilizationRatio' +KEY_DISP_UTILIZATION_RATIO = 'Utilization Ratio' +KEY_OUT_DISP_BOLT_CONN_LEN = 'Length of Connection (mm)' + KEY_DISP_BOLT_AREA = 'Nominal Stress Area (mm2)' KEY_DISP_KB = 'Kb' @@ -1836,6 +1966,7 @@ def is_valid_custom(self): KEY_OUT_BETA_PK = 'Bolt.Betapk' KEY_OUT_DISP_BETA_PK = 'βpk' KEY_OUT_DISP_BOLT_SLIP= 'Slip Resistance' +KEY_OUT_BOLT_SLIP = 'Bolt.Slip' KEY_OUT_DISP_BOLT_SLIP_DR = 'Slip Resistance (kN)' KEY_OUT_BOLT_CAPACITY = 'Bolt.Capacity' KEY_OUT_BOLT_CAPACITY_SPTD = 'Bolt.Capacity_sptd' @@ -2278,7 +2409,9 @@ def is_valid_custom(self): KEY_AXFOR = 'Axial Force' KEY_DISP_AXFOR = 'Axial Force (kN)*' KEY_PLTHK = 'Plate thk' +KEY_PK_PLTHK = 'PackingPlate thk' KEY_DISP_PLTHK = 'Plate thk (mm)' +KEY_DISP_PK_PLTHK = 'Packing Plate thickness (mm)' KEY_PLTHICK = 'Plate thk' KEY_DISP_PLTHICK = 'Plate Thickness (mm)' KEY_DISP_PLATE_THICK = 'Plate Thickness (mm)' @@ -2488,6 +2621,15 @@ def get_leg_lengths(designation): "

Specifying whether the members are exposed to corrosive influences, here, only affects the calculation of the maximum edge distance as per cl. 10.2.4.3

\n" "


") +DETAILING_DESCRIPTION_LAPJOINT = str("\n" + "\n" + "

The minimum edge and end distances from the centre of any hole to the nearest edge of a plate shall not be less than 1.7 times the hole diameter in case of [sheared or hand flame cut edges] and 1.5 times the hole diameter in case of [Rolled, machine-flame cut, sawn and planed edges] (IS 800 - cl. 10. 2. 4. 2)

\n" + "


\n") + + + COLUMN_OPTIMIZATION_DESCRIPTION = str("\n" "\n" + + "

Stiffener Details

\n" + + "

1. Types of Stiffeners in Plate Girders

\n" + + "

a. Intermediate (Transverse) Stiffeners

\n" + "\n" + + "

b. End Bearing Stiffeners

\n" + "\n" + + "

c. Longitudinal Stiffeners

\n" + "\n" + + "
\n" + + "

2. Web Buckling Design Methods (as per IS 800:2007)

\n" + "

IS 800:2007 recommends two principal methods for evaluating the web’s shear resistance when web slenderness is high:

\n" + + "

a. Simple Post-Critical Method

\n" + "\n" + + "

b. Tension Field Method

\n" + "\n" + + "" +) OPTIMIZATION_TABLE_UI = str("""
@@ -2784,3 +2991,187 @@ def get_leg_lengths(designation): "p, li { white-space: pre-wrap; }\n" "\n" ) + Allowable_Utilization_Para + Effective_Area_Para + Effective_Length_Para + OPTIMIZATION_TABLE_UI + Bearing_Length_Para + + +ADDITIONAL_GIRDER_DESCRIPTION = str( + "\n" + "" + "\n" + + "

Symmetrical I Girder

\n" + "

A symmetrical I girder (or beam) is an I-shaped structural member " + "in which the top and bottom flanges are identical in shape, size, and thickness. " + "The web (the vertical part) is centered between the flanges, making the whole section " + "mirrored about its central axis.

\n" + + "

Key Features

\n" + "\n" + + "

Advantages

\n" + "\n" + + "
\n" + + "

Unsymmetrical I Girder

\n" + "

An unsymmetrical I girder is an I-shaped structural member where the top " + "and bottom flanges are not identical—meaning they differ in width, thickness, or shape. " + "The web may not be centered.

\n" + + "

Key Features

\n" + "\n" + + "

Advantages

\n" + "\n" + + "" +) + + +PLATE_GIRDER_DEFLECTION_TABLE = str(""" + + + + Clause 5.6.1 Deflection + + + + +

Clause 5.6.1 Deflection

+

Vertical Deflection - Table 6 of IS800-2007

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Type of structureLoad TypeMemberSupportingDeflection Limit
Industrial buildingLive LoadPurlins and GirtsElastic claddingSpan/150
Industrial buildingLive LoadPurlins and GirtsBrittle claddingSpan/180
Industrial buildingLive LoadSimple spanElastic claddingSpan/240
Industrial buildingLive LoadSimple spanBrittle claddingSpan/300
Industrial buildingLive LoadCantilever spanElastic claddingSpan/120
Industrial buildingLive LoadCantilever spanBrittle claddingSpan/150
Industrial buildingLive LoadRafter supportingProfiled Metal SheetingSpan/180
Industrial buildingLive LoadRafter supportingPlastered SheetingSpan/240
Industrial buildingCrane Load(Manual operation)GantryCraneSpan/500
Industrial buildingCrane load(Electric operation up to 50t)GantryCraneSpan/750
Industrial buildingCrane load(Electric operation over 50t)GantryCraneSpan/1000
Other buildingsLive LoadFloor and RoofElements not susceptible to crackingSpan/300
Other buildingsLive LoadFloor and RoofElement susceptible to crackingSpan/360
Other buildingsLive LoadCantilever SpanElements not susceptible to crackingSpan/150
Other buildingsLive LoadCantilever SpanElement susceptible to crackingSpan/180
Highway BridgesLive LoadSimple spanNASpan/600
Railway BridgesLive LoadSimple spanNASpan/600
Highway BridgesDead LoadSimple spanNASpan/800
Railway BridgesDead LoadSimple spanNASpan/800
Highway BridgesLive LoadCantilever spanNASpan/400
Railway BridgesLive LoadCantilever spanNASpan/400
Highway BridgesDead LoadCantilever spanNASpan/800
Railway BridgesDead LoadCantilever spanNASpan/800
+ + + + + + +""") + +DESIGN_METHOD_DESCRIPTION = str( + "\n" + "" + "\n" + + "

Design Method

\n" + "

The \"Design Method\" dropdown allows you to choose the basis on which the structural design calculations for the girder will be performed. The main options are:

\n" + + "

Limit State Design (LSD)

\n" + "

Description:

\n" + "

Limit State Design is the modern design philosophy adopted by most current codes (including IS 800:2007). In this method, the structure is designed to withstand all possible limit states, primarily:

\n" + "\n" + "

Advantages:

\n" + "\n" + + "

Working Stress Design (WSD)

\n" + "

Description:

\n" + "

Also known as the elastic method, Working Stress Design ensures that stresses induced by service loads do not exceed specified allowable values. It uses a single factor of safety applied to material strength.

\n" + + "

Advantages:

\n" + "\n" + + "

Limitations:

\n" + "\n" + + "" +) \ No newline at end of file diff --git a/src/osdag/cad/SimpleConnections/BoltedLapJoint/bolted_lap_joint.py b/src/osdag/cad/SimpleConnections/BoltedLapJoint/bolted_lap_joint.py new file mode 100644 index 000000000..0a8839fa0 --- /dev/null +++ b/src/osdag/cad/SimpleConnections/BoltedLapJoint/bolted_lap_joint.py @@ -0,0 +1,163 @@ +import numpy +from OCC.Display.SimpleGui import init_display +from OCC.Core.BRepAlgoAPI import BRepAlgoAPI_Fuse +from OCC.Core.BOPAlgo import BOPAlgo_Builder +from OCC.Core.Quantity import Quantity_NOC_SADDLEBROWN,Quantity_NOC_GRAY,Quantity_NOC_BLUE1,Quantity_NOC_RED +from OCC.Core.Graphic3d import * +from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeSphere +# Import the component classes +from ...items.bolt import Bolt +from ...items.nut import Nut +from ...items.plate import Plate + +def create_bolted_lap_joint(plate1_thickness = 16, plate2_thickness = 8, plate_width = 100, bolt_dia = 16, actual_overlap_length=50, + bolt_rows=4,bolt_cols=2,pitch=20,gauge=20,edge=12,end=13.6,number_bolts=7): + + plate_length = 3 * actual_overlap_length + + # Calculate the offset of the second plate + plate2_offset = plate_length - actual_overlap_length + + nut_thickness = 3.0 + # Bolt parameters + bolt_head_radius = bolt_dia/2 + bolt_head_thickness = 3.0 + bolt_length = (plate1_thickness + plate2_thickness) + nut_thickness # Enough to go through both plates + bolt_shaft_radius = 1.5 + + # Nut parameters + nut_radius = bolt_head_radius + + nut_height = bolt_head_radius + nut_inner_radius = bolt_shaft_radius + + # Create the first plate + # Position it at the origin + origin1 = numpy.array([0.0, 0.0, 0.0]) # Global origin lies at midpoint of plate 1 + uDir1 = numpy.array([0.0, 0.0, 1.0]) # Points along Z axis (height) + wDir1 = numpy.array([1.0, 0.0, 0.0]) # Points along X axis (length) + + plate1 = Plate(plate_length, plate_width, plate1_thickness) + plate1.place(origin1, uDir1, wDir1) + plate1_model = plate1.create_model() + + # Create the second plate + # Position it so that it properly overlaps with the first plate + # The second plate is elevated by plate1_thickness and offset in Y direction + + origin2 = numpy.array([0.0, plate2_offset, 0.5*(plate1_thickness+plate2_thickness)]) + uDir2 = numpy.array([0.0, 0.0, 1.0]) + wDir2 = numpy.array([1.0, 0.0, 0.0]) + + plate2 = Plate(plate_length, plate_width, plate2_thickness) + plate2.place(origin2, uDir2, wDir2) + plate2_model = plate2.create_model() + + bolt_positions=[] + + # Calculate bolt positions + count = 0 + exit_loops = False # Flag to break both loops + + for col in range(bolt_cols): + for row in range(bolt_rows): + if count==number_bolts: + exit_loops = True + break # Break out of the inner loop + + bolt_positions.append((edge + (row * gauge), + plate_length / 2 - actual_overlap_length + end + (col * pitch), + (0.5 * plate1_thickness) + plate2_thickness)) + count += 1 + + if exit_loops: # Check flag to break outer loop + break + + + + # Create bolts and nuts at the calculated positions + bolts_models = [] + nuts_models = [] + + bolt_uDir = numpy.array([1.0, 0.0, 0.0]) + bolt_shaftDir = numpy.array([0.0, 0.0, -1.0]) # Points downward through both plates + for pos in bolt_positions: + # Start bolts from the top of second plate + bolt = Bolt(bolt_head_radius, bolt_head_thickness, bolt_length, bolt_shaft_radius) + bolt.place(pos, bolt_uDir, bolt_shaftDir) + bolt_model = bolt.create_model() + bolts_models.append(bolt_model) + + # Position nuts at the bottom of the first plate + nut_origin = numpy.array([pos[0], pos[1], -0.5*plate1_thickness]) + nut_uDir = numpy.array([1.0, 0.0, 0.0]) + nut_wDir = numpy.array([0.0, 0.0, -1.0]) # Points downward + + nut = Nut(nut_radius, nut_thickness, nut_height, nut_inner_radius) + nut.place(nut_origin, nut_uDir, nut_wDir) + nut_model = nut.create_model() + nuts_models.append(nut_model) + + # Use BOPAlgo_Builder for assembly + builder = BOPAlgo_Builder() + + # Add all parts to the builder + builder.AddArgument(plate1_model) + builder.AddArgument(plate2_model) + + for bolt_model in bolts_models: + builder.AddArgument(bolt_model) + + for nut_model in nuts_models: + builder.AddArgument(nut_model) + + # Perform the boolean operation + builder.Perform() + + # Get the resulting assembly + assembly = builder.Shape() + + return assembly, plate1_model, plate2_model, bolts_models, nuts_models + +# Main execution +if __name__ == "__main__": + # Create the bolted lap joint + lap_joint, plate1, plate2, bolts, nuts = create_bolted_lap_joint() + + # Display the assembly + display, start_display, add_menu, add_function_to_menu = init_display() + + # Display individual components with different colors for better visualization + display.DisplayShape(plate1, material=Graphic3d_NOM_ALUMINIUM, update=True) + display.DisplayShape(plate2, update=True) + + for bolt in bolts: + display.DisplayShape(bolt, color=Quantity_NOC_SADDLEBROWN, update=True) + + for nut in nuts: + display.DisplayShape(nut, color=Quantity_NOC_SADDLEBROWN, update=True) + # Highlight the global origin (0,0,0) + origin_point = BRepPrimAPI_MakeSphere(1).Shape() # Small sphere to mark origin + display.DisplayShape(origin_point, color=Quantity_NOC_RED, update=True) + + # Alternative: display the full assembly as a single shape + # display.DisplayShape(lap_joint, update=True) + display.set_bg_gradient_color([51, 51, 102], [150, 150, 170]) + + display.DisableAntiAliasing() + display.FitAll() + start_display() + + +# bolt_positions = [ +# # Format: (x, y, z) +# # Left side, bottom and top corners of overlap +# (edge, plate_length/2 - actual_overlap_length + end, (0.5*plate1_thickness)+plate2_thickness), +# (edge + gauge, plate_length/2 - actual_overlap_length + end, (0.5*plate1_thickness)+plate2_thickness), +# (edge, plate_length/2 - end, (0.5*plate1_thickness)+plate2_thickness), + +# # Right side, bottom and top corners of overlap +# (plate_width - edge, plate_length/2 - actual_overlap_length + end, (0.5*plate1_thickness)+plate2_thickness), +# (plate_width - edge, plate_length/2 - end, (0.5*plate1_thickness)+plate2_thickness) +# ] + \ No newline at end of file diff --git a/src/osdag/cad/common_logic.py b/src/osdag/cad/common_logic.py index 91b9c66cf..2e9feeb5b 100644 --- a/src/osdag/cad/common_logic.py +++ b/src/osdag/cad/common_logic.py @@ -21,6 +21,7 @@ from .items.angle import Angle from .items.channel import Channel from .items.Gasset_plate import GassetPlate +from .items.plate_girder import PlateGirder from .items.stiffener_flange import Stiffener_flange from .items.rect_hollow import RectHollow from .items.circular_hollow import CircularHollow @@ -52,6 +53,8 @@ from .BBCad.nutBoltPlacement_Web import NutBoltArray_Web from .BBCad.BBCoverPlateBoltedCAD import BBCoverPlateBoltedCAD +from .SimpleConnections.BoltedLapJoint.bolted_lap_joint import * + from .MomentConnections.BBSpliceCoverlateCAD.WeldedCAD import BBSpliceCoverPlateWeldedCAD from .MomentConnections.BBEndplate.BBEndplate_cadFile import CADFillet from .MomentConnections.BBEndplate.BBEndplate_cadFile import CADGroove @@ -93,7 +96,7 @@ from .MomentConnections.BCEndplate.BCE_nutBoltPlacement import BCE_NutBoltArray from ..Common import * from math import * - +from OCC.Core.TopoDS import TopoDS_Shape # from Connections.Shear.Finplate.colWebBeamWebConnectivity import ColWebBeamWeb as finColWebBeamWeb # from Connections.Shear.Endplate.colWebBeamWebConnectivity import ColWebBeamWeb as endColWebBeamWeb # from Connections.Shear.cleatAngle.colWebBeamWebConnectivity import ColWebBeamWeb as cleatColWebBeamWeb @@ -1783,6 +1786,35 @@ def createColumnInFrameCAD(self): return sec + def createBoltedLapJoint(self): + + Conn = self.module_class + print("THIS IS CONN") + print(Conn) + for attr in dir(Conn): + if not callable(getattr(Conn, attr)) and not attr.startswith("__"): + print(f"{attr}: {getattr(Conn, attr)}") + + print(f"Plate 1 Thickness: {float(Conn.plate1thk)}") + print(f"Plate 2 Thickness: {float(Conn.plate2thk)}") + print(f"Plate Width: {float(Conn.width)}") + print(f"Bolt Diameter: {Conn.bolt.bolt_diameter_provided}") + print(f"Actual Overlap Length: {Conn.len_conn}") + print(f"Bolt Columns: {Conn.cols}") + print(f"Bolt Rows: {Conn.rows}") + print(f"Number of Bolts: {Conn.number_bolts}") + print(f"Pitch: {Conn.final_pitch}") + print(f"Gauge: {Conn.final_gauge}") + print(f"Edge Distance: {Conn.final_edge_dist}") + print(f"End Distance: {Conn.final_end_dist}") + + lap_joint, plate1, plate2, bolts, nuts = create_bolted_lap_joint(plate1_thickness = float(Conn.plate1thk), plate2_thickness = float(Conn.plate2thk), plate_width = float(Conn.width), bolt_dia = Conn.bolt.bolt_diameter_provided, + actual_overlap_length=Conn.len_conn,bolt_cols=Conn.cols,bolt_rows=Conn.rows, number_bolts=Conn.number_bolts, + pitch=Conn.final_pitch,gauge=Conn.final_gauge, + edge=Conn.final_edge_dist,end=Conn.final_end_dist) + return lap_joint, plate1, plate2, bolts, nuts + + def createSimplySupportedBeam(self): Flex = self.module_class @@ -1951,6 +1983,54 @@ def createStrutsInTrusses(self): return shape + def createPlateGirder(self): #im working here + + # Val_obj = self.module_class + # Val_obj.section_property = Val_obj.section_connect_database(Val_obj, Val_obj.result_designation) + + Val_obj = self.module_class + print("THIS IS Val_obj") + print(Val_obj) + for attr in dir(Val_obj): + if not callable(getattr(Val_obj, attr)) and not attr.startswith("__"): + print(f"{attr}: {getattr(Val_obj, attr)}") + + design_type = Val_obj.design_type + print("Design type : ", design_type) + length = int(Val_obj.length) + print("Total Length : ", length) + + D = int(Val_obj.total_depth) + print("Total Depth : ", D) + + tw = int(Val_obj.web_thickness) + print("Web Thickness : ", tw) + + B_ft = int(Val_obj.top_flange_width) + print("Top Flange Width : ", B_ft) + + T_ft = int(Val_obj.top_flange_thickness) + print("Top Flange Thickness : ", T_ft) + + B_fb = int(Val_obj.bottom_flange_width) + print("Bottom Flange Width : ", B_fb) + + T_fb = int(Val_obj.bottom_flange_thickness) + print("Bottom Flange Thickness : ", T_fb) + + gap = int(Val_obj.c) + print("Gap Between Stiffener : ", gap) + + + + + plate_girder_model = PlateGirder(D, tw, length, gap, T_ft, T_fb, B_ft, B_fb) + + model = plate_girder_model.createPlateGirder() + + return model + + def display_3DModel(self, component, bgcolor): self.component = component @@ -2269,6 +2349,20 @@ def display_3DModel(self, component, bgcolor): if self.component == "Model": osdag_display_shape(self.display, self.ColObj, update=True) + elif self.mainmodule == 'Lap Joint Bolted Connection': + self.col = self.module_class() + self.assembly,self.plate1_model,self.plate2_model,self.bolt_models,self.nuts_models = self.createBoltedLapJoint() + + if self.component == "Model": + osdag_display_shape(self.display, self.plate1_model, update=True, material=Graphic3d_NOM_ALUMINIUM) + osdag_display_shape(self.display, self.plate2_model, update=True) + for bolt in self.bolt_models: + osdag_display_shape(self.display, bolt, update=True, + color=Quantity_NOC_SADDLEBROWN) + for nut in self.nuts_models: + osdag_display_shape(self.display, nut, update=True, + color=Quantity_NOC_SADDLEBROWN) + elif self.mainmodule == 'Flexure Member': self.flex = self.module_class() self.FObj = self.createSimplySupportedBeam() @@ -2290,6 +2384,14 @@ def display_3DModel(self, component, bgcolor): if self.component == "Model": osdag_display_shape(self.display, self.ColObj, update=True) + + elif self.mainmodule == KEY_DISP_PLATE_GIRDER_WELDED: #im working here + self.col = self.module_class() + self.ColObj = self.createPlateGirder() + + if self.component == "Model": + osdag_display_shape(self.display, self.ColObj, update=True) + else: if self.connection == KEY_DISP_TENSION_BOLTED: self.T = self.module_class() @@ -2475,6 +2577,24 @@ def call_3DModel(self, flag, module_class): # Done else: self.display.EraseAll() + elif self.mainmodule == 'Lap Joint Bolted Connection': + if flag is True: + self.ColObj = self.createBoltedLapJoint() + + self.display_3DModel("Model", "gradient_bg") + + else: + self.display.EraseAll() + + elif self.mainmodule == KEY_DISP_PLATE_GIRDER_WELDED:#im working here + if flag is True: + self.ColObj = self.createPlateGirder() + + self.display_3DModel("Model", "gradient_bg") + + else: + self.display.EraseAll() + else: if self.connection == KEY_DISP_TENSION_BOLTED or self.connection == KEY_DISP_TENSION_WELDED: diff --git a/src/osdag/cad/items/plate_girder.py b/src/osdag/cad/items/plate_girder.py new file mode 100644 index 000000000..cf7e85f39 --- /dev/null +++ b/src/osdag/cad/items/plate_girder.py @@ -0,0 +1,182 @@ +# optimised_plate_girder_refactored.py + +from .ISection import ISection +from .notch import Notch +from .plate import Plate +from .filletweld import FilletWeld +import math +import time + +from OCC.Core.gp import gp_Pnt, gp_Vec, gp_Trsf, gp_Ax1, gp_Dir, gp_Ax3 +from OCC.Core.BRepBuilderAPI import ( + BRepBuilderAPI_MakePolygon, BRepBuilderAPI_MakeFace, BRepBuilderAPI_Transform, + BRepBuilderAPI_MakeEdge, BRepBuilderAPI_MakeWire +) +from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakePrism +from OCC.Core.BRepAlgoAPI import BRepAlgoAPI_Fuse +from OCC.Core.BRep import BRep_Builder +from OCC.Core.TopoDS import TopoDS_Compound +from OCC.Core.AIS import AIS_Shape +from OCC.Core.Quantity import Quantity_Color, Quantity_TOC_RGB +from OCC.Core.Graphic3d import Graphic3d_NOM_ALUMINIUM +from OCC.Display.SimpleGui import init_display + + +class PlateGirder: + def __init__(self, D, tw, length, gap, T_ft, T_fb, B_ft, B_fb): + self.D = D + self.tw = tw + self.length = length + self.gap = gap + self.T_ft = T_ft + self.T_fb = T_fb + self.B_ft = B_ft + self.B_fb = B_fb + + def createPlateGirder(self): + chamfer_length = 30 + T_is = 15 + L = (min(self.B_ft, self.B_fb) - self.tw) / 2 + b = h = 15 + l = L - chamfer_length + vertical_weld_height = 0.5 * chamfer_length + + center_plate_color = Quantity_Color(5/255, 5/255, 255/255, Quantity_TOC_RGB) + top_bottom_plate_color = Quantity_Color(137/255, 95/255, 16/255, Quantity_TOC_RGB) + + display, start_display, *_ = init_display() + display.set_bg_gradient_color([51, 51, 102], [150, 150, 170]) + + def plate_model_with_color(origin, l, b, h, color): + plate = Plate(l, b, h) + plate.place(origin, [0., 0., 1.], [0., 1., 0.]) + shape = plate.create_model() + ais_shape = AIS_Shape(shape) + ais_shape.SetColor(color) + display.Context.Display(ais_shape, True) + return shape + + def fuse_models(models): + builder = BRep_Builder() + compound = TopoDS_Compound() + builder.MakeCompound(compound) + for m in models: + builder.Add(compound, m) + return compound + + def translation_movement(x, y, z, model): + trsf = gp_Trsf() + trsf.SetTranslation(gp_Vec(x, y, z)) + return BRepBuilderAPI_Transform(model, trsf).Shape() + + def translation_rotation(angle, axis, model): + trsf = gp_Trsf() + trsf.SetRotation(axis, math.radians(angle)) + return BRepBuilderAPI_Transform(model, trsf).Shape() + + def stiffner_plate(position, b, a, thickness, direction): + c = chamfer_length + x, y, z = map(float, position) + y -= thickness/2 + if direction == "right": + pts = [gp_Pnt(0, 0, (a/2)-c), gp_Pnt(c, 0, a/2), gp_Pnt(b, 0, a/2), + gp_Pnt(b, 0, -a/2), gp_Pnt(c, 0, -a/2), gp_Pnt(0, 0, (-a/2)+c)] + else: + pts = [gp_Pnt(0, 0, (a/2)-c), gp_Pnt(-c, 0, a/2), gp_Pnt(-b, 0, a/2), + gp_Pnt(-b, 0, -a/2), gp_Pnt(-c, 0, -a/2), gp_Pnt(0, 0, (-a/2)+c)] + + wire = BRepBuilderAPI_MakeWire() + for i in range(len(pts)): + wire.Add(BRepBuilderAPI_MakeEdge(pts[i], pts[(i+1) % len(pts)]).Edge()) + face = BRepBuilderAPI_MakeFace(wire.Wire()).Face() + prism = BRepPrimAPI_MakePrism(face, gp_Vec(0, thickness, 0)).Shape() + + local_ax3 = gp_Ax3(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1), gp_Dir(0, 1, 0)) + global_ax3 = gp_Ax3(gp_Pnt(x, y, z), gp_Dir(0, 0, 1), gp_Dir(0, 1, 0)) + trsf = gp_Trsf() + trsf.SetDisplacement(local_ax3, global_ax3) + return BRepBuilderAPI_Transform(prism, trsf, True).Shape() + + def vertical_weld(weld_height, length): + p1, p2, p3 = gp_Pnt(0, 0, 0), gp_Pnt(weld_height, 0, 0), gp_Pnt(0, -weld_height, 0) + edges = [BRepBuilderAPI_MakeEdge(p1, p2).Edge(), BRepBuilderAPI_MakeEdge(p2, p3).Edge(), + BRepBuilderAPI_MakeEdge(p3, p1).Edge()] + wire = BRepBuilderAPI_MakeWire(*edges).Wire() + face = BRepBuilderAPI_MakeFace(wire).Face() + return BRepPrimAPI_MakePrism(face, gp_Vec(0, 0, self.D - 2 * chamfer_length)).Shape() + + def create_weld_model(thickness, width, position, direction): + uDir, shaftDir = ([0., 0., 1.], [0., 1., 0.]) if direction == 'y' else ([1., 0., 0.], [0., 0., 1.]) + FWeld = FilletWeld(thickness, thickness, width) + FWeld.place(position, uDir, shaftDir) + return FWeld.create_model(0) + + def filletWeld_model(b, h, l, y, position): + x = self.tw//2 + chamfer_length if position == "right" else -self.tw//2 - l - chamfer_length + FWeld = FilletWeld(b, h, l) + FWeld.place([0., 0., 0.], [0., 0., 1.], [1., 0., 0.]) + base = FWeld.create_model(0) + + def rotate_and_translate(angle, dx, dy, dz): + shape = translation_rotation(angle, gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(1, 0, 0)), base) + return translation_movement(dx, dy, dz, shape) + + front = BRepAlgoAPI_Fuse( + rotate_and_translate(0, x, y - T_is//2, self.D//2), + rotate_and_translate(90, x, y - T_is//2, -self.D//2) + ).Shape() + + back = BRepAlgoAPI_Fuse( + rotate_and_translate(180, x, y + T_is//2, self.D//2), + rotate_and_translate(270, x, y + T_is//2, -self.D//2) + ).Shape() + + return BRepAlgoAPI_Fuse(front, back).Shape() + + # --- Begin assembling model --- + center_plate = plate_model_with_color(np.array([0., 0., 0.]), self.tw, self.length, self.D, center_plate_color) + top_plate = plate_model_with_color(np.array([0, 0, (self.D + self.T_ft) // 2]), self.B_ft, self.length, self.T_ft, top_bottom_plate_color) + bottom_plate = plate_model_with_color(np.array([0, 0, -(self.D + self.T_fb) // 2]), self.B_fb, self.length, self.T_fb, top_bottom_plate_color) + + ISection_model = BRepAlgoAPI_Fuse(bottom_plate, top_plate).Shape() + + # Longitudinal welds + welds = [ + create_weld_model(0.5 * chamfer_length, self.length, np.array([self.tw // 2, 0., -self.D // 2]), "y"), + create_weld_model(0.5 * chamfer_length, self.length, np.array([-self.tw // 2, 0., -self.D // 2]), "y"), + create_weld_model(0.5 * chamfer_length, self.length, np.array([self.tw // 2, 0., self.D // 2]), "y"), + create_weld_model(0.5 * chamfer_length, self.length, np.array([-self.tw // 2, 0., self.D // 2]), "y") + ] + longitudinal_weld = fuse_models(welds) + + stiffners, welds = [], [] + v_weld = vertical_weld(vertical_weld_height, self.D - 2 * chamfer_length) + for y in range(self.gap, self.length, self.gap): + stiffners.extend([ + stiffner_plate(np.array([self.tw/2, y, 0]), L, self.D, T_is, "right"), + stiffner_plate(np.array([-self.tw/2, y, 0]), L, self.D, T_is, "left") + ]) + welds.extend([ + filletWeld_model(b, h, l, y, "right"), + filletWeld_model(b, h, l, y, "left"), + translation_movement(self.tw/2, y, (-self.D/2)+chamfer_length, v_weld), + translation_movement(self.tw/2, y+T_is/2, (-self.D/2)+chamfer_length, + translation_rotation(90, gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), v_weld)), + translation_movement(-self.tw/2, y, (-self.D/2)+chamfer_length, + translation_rotation(-90, gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), v_weld)), + translation_movement(-self.tw/2, y+T_is/2, (-self.D/2)+chamfer_length, + translation_rotation(-180, gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), v_weld)) + ]) + + stiffners = fuse_models(stiffners) + welds = fuse_models(welds) + display.DisplayShape(ISection_model, update=True) + display.DisplayShape(center_plate, update=True) + display.DisplayShape(stiffners, material=Graphic3d_NOM_ALUMINIUM, update=True) + display.DisplayShape(longitudinal_weld, color="red", update=True) + display.DisplayShape(welds, color="red", update=True) + start_display() + + plate_girder_model = BRepAlgoAPI_Fuse(BRepAlgoAPI_Fuse(center_plate, ISection_model).Shape(), stiffners) + plate_girder_model = BRepAlgoAPI_Fuse(plate_girder_model, welds).Shape() + return plate_girder_model diff --git a/src/osdag/data/ResourceFiles/images/ButtJointBolted.png b/src/osdag/data/ResourceFiles/images/ButtJointBolted.png new file mode 100644 index 000000000..dc705bb3b Binary files /dev/null and b/src/osdag/data/ResourceFiles/images/ButtJointBolted.png differ diff --git a/src/osdag/data/ResourceFiles/images/ButtJointWelded.png b/src/osdag/data/ResourceFiles/images/ButtJointWelded.png new file mode 100644 index 000000000..5e52d6361 Binary files /dev/null and b/src/osdag/data/ResourceFiles/images/ButtJointWelded.png differ diff --git a/src/osdag/data/ResourceFiles/images/CLFFS_PG.png b/src/osdag/data/ResourceFiles/images/CLFFS_PG.png new file mode 100644 index 000000000..24bf87325 Binary files /dev/null and b/src/osdag/data/ResourceFiles/images/CLFFS_PG.png differ diff --git a/src/osdag/data/ResourceFiles/images/CLPPSPB_PG.png b/src/osdag/data/ResourceFiles/images/CLPPSPB_PG.png new file mode 100644 index 000000000..5cd8e1d94 Binary files /dev/null and b/src/osdag/data/ResourceFiles/images/CLPPSPB_PG.png differ diff --git a/src/osdag/data/ResourceFiles/images/CLPPS_PG.png b/src/osdag/data/ResourceFiles/images/CLPPS_PG.png new file mode 100644 index 000000000..10ae5803b Binary files /dev/null and b/src/osdag/data/ResourceFiles/images/CLPPS_PG.png differ diff --git a/src/osdag/data/ResourceFiles/images/LapJointBolted.png b/src/osdag/data/ResourceFiles/images/LapJointBolted.png new file mode 100644 index 000000000..a5b6f33a3 Binary files /dev/null and b/src/osdag/data/ResourceFiles/images/LapJointBolted.png differ diff --git a/src/osdag/data/ResourceFiles/images/ULFFS_PG.png b/src/osdag/data/ResourceFiles/images/ULFFS_PG.png new file mode 100644 index 000000000..6ed01b778 Binary files /dev/null and b/src/osdag/data/ResourceFiles/images/ULFFS_PG.png differ diff --git a/src/osdag/data/ResourceFiles/images/ULPPS_PG.png b/src/osdag/data/ResourceFiles/images/ULPPS_PG.png new file mode 100644 index 000000000..92c6574a0 Binary files /dev/null and b/src/osdag/data/ResourceFiles/images/ULPPS_PG.png differ diff --git a/src/osdag/data/ResourceFiles/images/plate_girdersample.png b/src/osdag/data/ResourceFiles/images/plate_girdersample.png new file mode 100644 index 000000000..6a37bd294 Binary files /dev/null and b/src/osdag/data/ResourceFiles/images/plate_girdersample.png differ diff --git a/src/osdag/design_type/connection/butt_joint_bolted.py b/src/osdag/design_type/connection/butt_joint_bolted.py new file mode 100644 index 000000000..4180851c0 --- /dev/null +++ b/src/osdag/design_type/connection/butt_joint_bolted.py @@ -0,0 +1,374 @@ +""" +Module: butt_joint_bolted.py +Author: Aman +Date: 2025-02-26 + +Description: + ButtJointBolted is a moment connection module that represents a bolted butt joint connection. + It inherits from MomentConnection and follows the same structure and design logic as other + connection modules (e.g., BeamCoverPlate, ColumnCoverPlate) used in Osdag. + +Reference: + - Osdag software guidelines and connection module structure documentation +""" + +from .moment_connection import MomentConnection +from ...utils.common.component import * +from ...utils.common.is800_2007 import * +from ...Common import * +from ...design_report.reportGenerator_latex import CreateLatex +from ...Report_functions import * +from ...utils.common.load import Load +import logging + +import math + +class ButtJointBolted(MomentConnection): + def __init__(self): + super(ButtJointBolted, self).__init__() + self.design_status = False + self.spacing = None + + ############################################### + # Design Preference Functions Start + ############################################### + def tab_list(self): + tabs = [] + # Only Bolt and Detailing tabs + tabs.append(("Bolt", TYPE_TAB_2, self.bolt_values)) + tabs.append(("Detailing", TYPE_TAB_2, self.detailing_values)) + return tabs + + def tab_value_changed(self): + # No tab value dependencies needed for bolt and detailing + return [] + + def edit_tabs(self): + return [] # Keep original empty implementation + + def input_dictionary_design_pref(self): + design_input = [] + + # Bolt preferences + design_input.append(("Bolt", TYPE_COMBOBOX, [ + KEY_DP_BOLT_TYPE, # For pretensioned/non-pretensioned + KEY_DP_BOLT_HOLE_TYPE, # For standard/oversized + KEY_DP_BOLT_SLIP_FACTOR # For slip factor as per Table 20 + ])) + + # Detailing preferences + design_input.append(("Detailing", TYPE_COMBOBOX, [ + KEY_DP_DETAILING_EDGE_TYPE, + KEY_DP_DETAILING_PACKING_PLATE + # For edge preparation method + ])) + + return design_input + + def input_dictionary_without_design_pref(self): + design_input = [] + + # Default values for bolt and detailing + design_input.append((None, [ + KEY_DP_BOLT_TYPE, + KEY_DP_BOLT_HOLE_TYPE, + KEY_DP_BOLT_SLIP_FACTOR, + KEY_DP_DETAILING_EDGE_TYPE,KEY_DP_DETAILING_PACKING_PLATE + ], '')) + + return design_input + + def get_values_for_design_pref(self, key, design_dictionary): + # Default values as per requirements + defaults = { + KEY_DP_BOLT_TYPE: "Non Pre-tensioned", + KEY_DP_BOLT_HOLE_TYPE: "Standard", + KEY_DP_BOLT_SLIP_FACTOR: "0.3", + KEY_DP_DETAILING_EDGE_TYPE: "Sheared or hand flame cut", + KEY_DP_DETAILING_PACKING_PLATE: "Yes" + } + return defaults.get(key) + + def detailing_values(self, input_dictionary): + values = { + KEY_DP_DETAILING_EDGE_TYPE: 'Sheared or hand flame cut', + KEY_DP_DETAILING_PACKING_PLATE: 'Yes', + } + + for key in values.keys(): + if key in input_dictionary.keys(): + values[key] = input_dictionary[key] + + detailing = [] + + # Edge preparation method as per Cl. 10.2.4 of IS:800:2007 + t1 = (KEY_DP_DETAILING_EDGE_TYPE, KEY_DISP_DP_DETAILING_EDGE_TYPE, TYPE_COMBOBOX, + ['Sheared or hand flame cut', 'Rolled, machine-flame cut, sawn and planed'], + values[KEY_DP_DETAILING_EDGE_TYPE]) + detailing.append(t1) + + t3 = (KEY_DP_DETAILING_PACKING_PLATE, KEY_DISP_DP_DETAILING_PACKING_PLATE, TYPE_COMBOBOX, + ['Yes', 'No'], values[KEY_DP_DETAILING_PACKING_PLATE]) + detailing.append(t3) + + t4 = ("textBrowser", "", TYPE_TEXT_BROWSER, DETAILING_DESCRIPTION_LAPJOINT, None) + detailing.append(t4) + + return detailing + + # def bolt_values(self, input_dictionary): + # values = { + # KEY_DP_BOLT_TYPE: 'Non Pre-tensioned', + # KEY_DP_BOLT_HOLE_TYPE: 'Standard', + # KEY_DP_BOLT_SLIP_FACTOR: '0.3' + # } + + # for key in values.keys(): + # if key in input_dictionary.keys(): + # values[key] = input_dictionary[key] + + # bolt = [] + + # # Bolt type selection + # t1 = (KEY_DP_BOLT_TYPE, "Type", TYPE_COMBOBOX, + # ['Non Pre-tensioned', 'Pre-tensioned'], + # values[KEY_DP_BOLT_TYPE]) + # bolt.append(t1) + + # # Bolt hole type + # t2 = (KEY_DP_BOLT_HOLE_TYPE, "Bolt Hole", TYPE_COMBOBOX, + # ['Standard', 'Over-sized'], + # values[KEY_DP_BOLT_HOLE_TYPE]) + # bolt.append(t2) + + # # Slip factor as per Table 20 of IS 800 + # t3 = (KEY_DP_BOLT_SLIP_FACTOR, "Slip Factor", TYPE_COMBOBOX, + # ['0.3', '0.45', '0.5'], + # values[KEY_DP_BOLT_SLIP_FACTOR]) + # bolt.append(t3) + + # return bolt + + + #################################### + # Design Preference Functions End + #################################### + + def set_osdaglogger(key): + + """ + Function to set Logger for Tension Module + """ + + # @author Arsil Zunzunia + global logger + logger = logging.getLogger('Osdag') + + logger.setLevel(logging.DEBUG) + handler = logging.StreamHandler() + formatter = logging.Formatter(fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S') + + handler.setFormatter(formatter) + logger.addHandler(handler) + handler = logging.FileHandler('logging_text.log') + + formatter = logging.Formatter(fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S') + handler.setFormatter(formatter) + logger.addHandler(handler) + + if key is not None: + handler = OurLog(key) + formatter = logging.Formatter(fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + datefmt='%Y-%m-%d %H:%M:%S') + handler.setFormatter(formatter) + logger.addHandler(handler) + + + def input_value_changed(self): + + lst = [] + + t8 = ([KEY_MATERIAL], KEY_MATERIAL, TYPE_CUSTOM_MATERIAL, self.new_material) + lst.append(t8) + + return lst + + + def input_values(self): + + options_list = [] + + t16 = (KEY_MODULE, KEY_DISP_BUTTJOINTBOLTED, TYPE_MODULE, None, True, 'No Validator') + options_list.append(t16) + + t1 = (None, DISP_TITLE_CM, TYPE_TITLE, None, True, 'No Validator') + options_list.append(t1) + + t5 = (KEY_MATERIAL, KEY_DISP_MATERIAL, TYPE_COMBOBOX, VALUES_MATERIAL, True, 'No Validator') + options_list.append(t5) + + t31 = (KEY_PLATE1_THICKNESS, KEY_DISP_PLATE1_THICKNESS, TYPE_COMBOBOX, VALUES_PLATETHK_CUSTOMIZED, True, 'Int Validator') + options_list.append(t31) + + t34 = (KEY_PLATE2_THICKNESS, KEY_DISP_PLATE2_THICKNESS, TYPE_COMBOBOX, VALUES_PLATETHK_CUSTOMIZED, True, 'Int Validator') + options_list.append(t34) + + t35 = (KEY_PLATE_WIDTH, KEY_DISP_PLATE_WIDTH, TYPE_TEXTBOX, None, True, 'Float Validator') + options_list.append(t35) + + t36 = (KEY_COVER_PLATE, KEY_DISP_COVER_PLATE, TYPE_COMBOBOX, VALUES_COVER_PLATE, True, 'No Validator') + options_list.append(t36) + + t6 = (None, DISP_TITLE_FSL, TYPE_TITLE, None, True, 'No Validator') + options_list.append(t6) + + t17 = (KEY_TENSILE_FORCE, KEY_DISP_TENSILE_FORCE, TYPE_TEXTBOX, None, True, 'Int Validator') + options_list.append(t17) + + t9 = (None, DISP_TITLE_BOLT, TYPE_TITLE, None, True, 'No Validator') + options_list.append(t9) + + t10 = (KEY_D, KEY_DISP_D, TYPE_COMBOBOX_CUSTOMIZED, VALUES_D, True, 'No Validator') + options_list.append(t10) + + t12 = (KEY_GRD, KEY_DISP_GRD, TYPE_COMBOBOX_CUSTOMIZED, VALUES_GRD, True, 'No Validator') + options_list.append(t12) + + t11 = (KEY_TYP, KEY_DISP_TYP, TYPE_COMBOBOX, VALUES_TYP, True, 'No Validator') + options_list.append(t11) + + return options_list + + def customized_input(self): + + list1 = [] + t1 = (KEY_GRD, self.grdval_customized) + list1.append(t1) + t3 = (KEY_D, self.diam_bolt_customized) + list1.append(t3) + # t5 = (KEY_PLATE1_THICKNESS, self.plate_thick_customized) + # list1.append(t5) + # t6 = (KEY_PLATE2_THICKNESS, self.plate_thick_customized) + # list1.append(t6) + + return list1 + + def spacing(self, status): + spacing = [] + + t00 = (None, "", TYPE_NOTE, "Representative Image for Spacing Details - 3 x 3 pattern considered") + spacing.append(t00) + + t99 = (None, 'Spacing Details', TYPE_SECTION, + [str(files("osdag.data.ResourceFiles.images").joinpath("spacing_3.png")), 400, 277, ""]) # [image, width, height, caption] + spacing.append(t99) + + t9 = (KEY_OUT_PITCH, KEY_OUT_DISP_PITCH, TYPE_TEXTBOX, self.plate.gauge_provided if status else '') + spacing.append(t9) + + t10 = (KEY_OUT_END_DIST, KEY_OUT_DISP_END_DIST, TYPE_TEXTBOX, self.plate.edge_dist_provided if status else '') + spacing.append(t10) + + t11 = (KEY_OUT_GAUGE, KEY_OUT_DISP_GAUGE, TYPE_TEXTBOX, self.plate.pitch_provided if status else '') + spacing.append(t11) + + t12 = (KEY_OUT_EDGE_DIST, KEY_OUT_DISP_EDGE_DIST, TYPE_TEXTBOX, self.plate.end_dist_provided if status else '') + spacing.append(t12) + + return spacing + + def output_values(self, flag): + + out_list = [] + t4 = (None, DISP_TITLE_BOLTD, TYPE_TITLE, None, True) + out_list.append(t4) + + t2 = (KEY_OUT_D_PROVIDED, KEY_OUT_DISP_D_PROVIDED, TYPE_TEXTBOX, + '', True) + out_list.append(t2) + + t3 = (KEY_OUT_GRD_PROVIDED, KEY_OUT_DISP_GRD_PROVIDED, TYPE_TEXTBOX, + '', True) + out_list.append(t3) + + t31 = (KEY_OUT_TYP_PROVIDED, KEY_OUT_DISP_TYP_PROVIDED, TYPE_TEXTBOX, + '', True) + out_list.append(t31) + + t8 = (KEY_OUT_BOLT_SHEAR,KEY_OUT_DISP_BOLT_SHEAR , TYPE_TEXTBOX, '', True) + out_list.append(t8) + + t4 = (KEY_OUT_BOLT_BEARING, KEY_OUT_DISP_BOLT_BEARING, TYPE_TEXTBOX, '', True) + out_list.append(t4) + + t5 = (KEY_OUT_BOLT_CAPACITY, KEY_OUT_DISP_BOLT_CAPACITY, TYPE_TEXTBOX, + '', True) + out_list.append(t5) + + t17 = (None, DISP_TITLE_BOLTDS, TYPE_TITLE, None, True) + out_list.append(t17) + t17 = (KEY_OUT_TOT_NO_BOLTS, KEY_OUT_DISP_TOT_NO_BOLTS, TYPE_TEXTBOX, '', True) + out_list.append(t17) + + t11 = (KEY_PK_PLTHK, KEY_DISP_PK_PLTHK, TYPE_TEXTBOX, '', True) + out_list.append(t11) + + t18 = (KEY_OUT_ROW_PROVIDED, KEY_OUT_DISP_ROW_PROVIDED, TYPE_TEXTBOX,'', True) + out_list.append(t18) + + t19 = (KEY_OUT_COL_PROVIDED, KEY_OUT_DISP_COL_PROVIDED, TYPE_TEXTBOX,'', True) + out_list.append(t19) + + t20 = (KEY_OUT_BOLT_CONN_LEN, KEY_OUT_DISP_BOLT_CONN_LEN, TYPE_TEXTBOX,'', True) + out_list.append(t20) + + # t21 = (KEY_OUT_SPACING, KEY_OUT_DISP_SPACING, TYPE_OUT_BUTTON, ['Spacing Details', self.spacing], True) + # out_list.append(t21) + + return out_list + + def module_name(self): + + return KEY_DISP_BUTTJOINTBOLTED + + def call_3DColumn(self, ui, bgcolor): + # status = self.resultObj['Bolt']['status'] + # if status is True: + # self.ui.chkBx_beamSec1.setChecked(Qt.Checked) + if ui.chkBxCol.isChecked(): + ui.btn3D.setChecked(Qt.Unchecked) + ui.chkBxCol.setChecked(Qt.Unchecked) + ui.mytabWidget.setCurrentIndex(0) + # self.display_3DModel("Beam", bgcolor) + ui.commLogicObj.display_3DModel("Column", bgcolor) + + def get_3d_components(self): + components = [] + + t1 = ('Model', self.call_3DModel) + components.append(t1) + + t3 = ('Plate1', self.call_3DColumn) + components.append(t3) + + t4 = ('Plate2', self.call_3DPlate) + components.append(t4) + + return components + + def call_3DPlate(self, ui, bgcolor): + from PyQt5.QtWidgets import QCheckBox + from PyQt5.QtCore import Qt + for chkbox in ui.frame.children(): + if chkbox.objectName() == 'Cover Plate': + continue + if isinstance(chkbox, QCheckBox): + chkbox.setChecked(Qt.Unchecked) + ui.commLogicObj.display_3DModel("Cover Plate", bgcolor) + + + ################################ Outlist Dict ##################################################################################### + + + + ################################ Design Report ##################################################################################### \ No newline at end of file diff --git a/src/osdag/design_type/connection/butt_joint_welded.py b/src/osdag/design_type/connection/butt_joint_welded.py new file mode 100644 index 000000000..5a9943394 --- /dev/null +++ b/src/osdag/design_type/connection/butt_joint_welded.py @@ -0,0 +1,374 @@ +""" +Module: butt_joint_bolted.py +Author: Aman +Date: 2025-02-26 + +Description: + ButtJointBolted is a moment connection module that represents a bolted butt joint connection. + It inherits from MomentConnection and follows the same structure and design logic as other + connection modules (e.g., BeamCoverPlate, ColumnCoverPlate) used in Osdag. + +Reference: + - Osdag software guidelines and connection module structure documentation +""" + +from .moment_connection import MomentConnection +from ...utils.common.component import * +from ...utils.common.is800_2007 import * +from ...Common import * +from ...design_report.reportGenerator_latex import CreateLatex +from ...Report_functions import * +from ...utils.common.load import Load +import logging + +import math + +class ButtJointWelded(MomentConnection): + def __init__(self): + super(ButtJointWelded, self).__init__() + self.design_status = False + self.spacing = None + + ############################################### + # Design Preference Functions Start + ############################################### + def tab_list(self): + tabs = [] + # Only Bolt and Detailing tabs + tabs.append(("Bolt", TYPE_TAB_2, self.bolt_values)) + tabs.append(("Detailing", TYPE_TAB_2, self.detailing_values)) + return tabs + + def tab_value_changed(self): + # No tab value dependencies needed for bolt and detailing + return [] + + def edit_tabs(self): + return [] # Keep original empty implementation + + def input_dictionary_design_pref(self): + design_input = [] + + # Bolt preferences + design_input.append(("Bolt", TYPE_COMBOBOX, [ + KEY_DP_BOLT_TYPE, # For pretensioned/non-pretensioned + KEY_DP_BOLT_HOLE_TYPE, # For standard/oversized + KEY_DP_BOLT_SLIP_FACTOR # For slip factor as per Table 20 + ])) + + # Detailing preferences + design_input.append(("Detailing", TYPE_COMBOBOX, [ + KEY_DP_DETAILING_EDGE_TYPE, + KEY_DP_DETAILING_PACKING_PLATE + # For edge preparation method + ])) + + return design_input + + def input_dictionary_without_design_pref(self): + design_input = [] + + # Default values for bolt and detailing + design_input.append((None, [ + KEY_DP_BOLT_TYPE, + KEY_DP_BOLT_HOLE_TYPE, + KEY_DP_BOLT_SLIP_FACTOR, + KEY_DP_DETAILING_EDGE_TYPE,KEY_DP_DETAILING_PACKING_PLATE + ], '')) + + return design_input + + def get_values_for_design_pref(self, key, design_dictionary): + # Default values as per requirements + defaults = { + KEY_DP_BOLT_TYPE: "Non Pre-tensioned", + KEY_DP_BOLT_HOLE_TYPE: "Standard", + KEY_DP_BOLT_SLIP_FACTOR: "0.3", + KEY_DP_DETAILING_EDGE_TYPE: "Sheared or hand flame cut", + KEY_DP_DETAILING_PACKING_PLATE: "Yes" + } + return defaults.get(key) + + def detailing_values(self, input_dictionary): + values = { + KEY_DP_DETAILING_EDGE_TYPE: 'Sheared or hand flame cut', + KEY_DP_DETAILING_PACKING_PLATE: 'Yes', + } + + for key in values.keys(): + if key in input_dictionary.keys(): + values[key] = input_dictionary[key] + + detailing = [] + + # Edge preparation method as per Cl. 10.2.4 of IS:800:2007 + t1 = (KEY_DP_DETAILING_EDGE_TYPE, KEY_DISP_DP_DETAILING_EDGE_TYPE, TYPE_COMBOBOX, + ['Sheared or hand flame cut', 'Rolled, machine-flame cut, sawn and planed'], + values[KEY_DP_DETAILING_EDGE_TYPE]) + detailing.append(t1) + + t3 = (KEY_DP_DETAILING_PACKING_PLATE, KEY_DISP_DP_DETAILING_PACKING_PLATE, TYPE_COMBOBOX, + ['Yes', 'No'], values[KEY_DP_DETAILING_PACKING_PLATE]) + detailing.append(t3) + + t4 = ("textBrowser", "", TYPE_TEXT_BROWSER, DETAILING_DESCRIPTION_LAPJOINT, None) + detailing.append(t4) + + return detailing + + # def bolt_values(self, input_dictionary): + # values = { + # KEY_DP_BOLT_TYPE: 'Non Pre-tensioned', + # KEY_DP_BOLT_HOLE_TYPE: 'Standard', + # KEY_DP_BOLT_SLIP_FACTOR: '0.3' + # } + + # for key in values.keys(): + # if key in input_dictionary.keys(): + # values[key] = input_dictionary[key] + + # bolt = [] + + # # Bolt type selection + # t1 = (KEY_DP_BOLT_TYPE, "Type", TYPE_COMBOBOX, + # ['Non Pre-tensioned', 'Pre-tensioned'], + # values[KEY_DP_BOLT_TYPE]) + # bolt.append(t1) + + # # Bolt hole type + # t2 = (KEY_DP_BOLT_HOLE_TYPE, "Bolt Hole", TYPE_COMBOBOX, + # ['Standard', 'Over-sized'], + # values[KEY_DP_BOLT_HOLE_TYPE]) + # bolt.append(t2) + + # # Slip factor as per Table 20 of IS 800 + # t3 = (KEY_DP_BOLT_SLIP_FACTOR, "Slip Factor", TYPE_COMBOBOX, + # ['0.3', '0.45', '0.5'], + # values[KEY_DP_BOLT_SLIP_FACTOR]) + # bolt.append(t3) + + # return bolt + + + #################################### + # Design Preference Functions End + #################################### + + def set_osdaglogger(key): + + """ + Function to set Logger for Tension Module + """ + + # @author Arsil Zunzunia + global logger + logger = logging.getLogger('Osdag') + + logger.setLevel(logging.DEBUG) + handler = logging.StreamHandler() + formatter = logging.Formatter(fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S') + + handler.setFormatter(formatter) + logger.addHandler(handler) + handler = logging.FileHandler('logging_text.log') + + formatter = logging.Formatter(fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S') + handler.setFormatter(formatter) + logger.addHandler(handler) + + if key is not None: + handler = OurLog(key) + formatter = logging.Formatter(fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + datefmt='%Y-%m-%d %H:%M:%S') + handler.setFormatter(formatter) + logger.addHandler(handler) + + + def input_value_changed(self): + + lst = [] + + t8 = ([KEY_MATERIAL], KEY_MATERIAL, TYPE_CUSTOM_MATERIAL, self.new_material) + lst.append(t8) + + return lst + + + def input_values(self): + + options_list = [] + + t16 = (KEY_MODULE, KEY_DISP_BUTTJOINTBOLTED, TYPE_MODULE, None, True, 'No Validator') + options_list.append(t16) + + t1 = (None, DISP_TITLE_CM, TYPE_TITLE, None, True, 'No Validator') + options_list.append(t1) + + t5 = (KEY_MATERIAL, KEY_DISP_MATERIAL, TYPE_COMBOBOX, VALUES_MATERIAL, True, 'No Validator') + options_list.append(t5) + + t31 = (KEY_PLATE1_THICKNESS, KEY_DISP_PLATE1_THICKNESS, TYPE_COMBOBOX, VALUES_PLATETHK_CUSTOMIZED, True, 'Int Validator') + options_list.append(t31) + + t34 = (KEY_PLATE2_THICKNESS, KEY_DISP_PLATE2_THICKNESS, TYPE_COMBOBOX, VALUES_PLATETHK_CUSTOMIZED, True, 'Int Validator') + options_list.append(t34) + + t35 = (KEY_PLATE_WIDTH, KEY_DISP_PLATE_WIDTH, TYPE_TEXTBOX, None, True, 'Float Validator') + options_list.append(t35) + + t36 = (KEY_COVER_PLATE, KEY_DISP_COVER_PLATE, TYPE_COMBOBOX, VALUES_COVER_PLATE, True, 'No Validator') + options_list.append(t36) + + t6 = (None, DISP_TITLE_FSL, TYPE_TITLE, None, True, 'No Validator') + options_list.append(t6) + + t17 = (KEY_TENSILE_FORCE, KEY_DISP_TENSILE_FORCE, TYPE_TEXTBOX, None, True, 'Int Validator') + options_list.append(t17) + + t9 = (None, DISP_TITLE_BOLT, TYPE_TITLE, None, True, 'No Validator') + options_list.append(t9) + + t10 = (KEY_D, KEY_DISP_D, TYPE_COMBOBOX_CUSTOMIZED, VALUES_D, True, 'No Validator') + options_list.append(t10) + + t12 = (KEY_GRD, KEY_DISP_GRD, TYPE_COMBOBOX_CUSTOMIZED, VALUES_GRD, True, 'No Validator') + options_list.append(t12) + + t11 = (KEY_TYP, KEY_DISP_TYP, TYPE_COMBOBOX, VALUES_TYP, True, 'No Validator') + options_list.append(t11) + + return options_list + + def customized_input(self): + + list1 = [] + t1 = (KEY_GRD, self.grdval_customized) + list1.append(t1) + t3 = (KEY_D, self.diam_bolt_customized) + list1.append(t3) + # t5 = (KEY_PLATE1_THICKNESS, self.plate_thick_customized) + # list1.append(t5) + # t6 = (KEY_PLATE2_THICKNESS, self.plate_thick_customized) + # list1.append(t6) + + return list1 + + def spacing(self, status): + spacing = [] + + t00 = (None, "", TYPE_NOTE, "Representative Image for Spacing Details - 3 x 3 pattern considered") + spacing.append(t00) + + t99 = (None, 'Spacing Details', TYPE_SECTION, + [str(files("osdag.data.ResourceFiles.images").joinpath("spacing_3.png")), 400, 277, ""]) # [image, width, height, caption] + spacing.append(t99) + + t9 = (KEY_OUT_PITCH, KEY_OUT_DISP_PITCH, TYPE_TEXTBOX, self.plate.gauge_provided if status else '') + spacing.append(t9) + + t10 = (KEY_OUT_END_DIST, KEY_OUT_DISP_END_DIST, TYPE_TEXTBOX, self.plate.edge_dist_provided if status else '') + spacing.append(t10) + + t11 = (KEY_OUT_GAUGE, KEY_OUT_DISP_GAUGE, TYPE_TEXTBOX, self.plate.pitch_provided if status else '') + spacing.append(t11) + + t12 = (KEY_OUT_EDGE_DIST, KEY_OUT_DISP_EDGE_DIST, TYPE_TEXTBOX, self.plate.end_dist_provided if status else '') + spacing.append(t12) + + return spacing + + def output_values(self, flag): + + out_list = [] + t4 = (None, DISP_TITLE_BOLTD, TYPE_TITLE, None, True) + out_list.append(t4) + + t2 = (KEY_OUT_D_PROVIDED, KEY_OUT_DISP_D_PROVIDED, TYPE_TEXTBOX, + '', True) + out_list.append(t2) + + t3 = (KEY_OUT_GRD_PROVIDED, KEY_OUT_DISP_GRD_PROVIDED, TYPE_TEXTBOX, + '', True) + out_list.append(t3) + + t31 = (KEY_OUT_TYP_PROVIDED, KEY_OUT_DISP_TYP_PROVIDED, TYPE_TEXTBOX, + '', True) + out_list.append(t31) + + t8 = (KEY_OUT_BOLT_SHEAR,KEY_OUT_DISP_BOLT_SHEAR , TYPE_TEXTBOX, '', True) + out_list.append(t8) + + t4 = (KEY_OUT_BOLT_BEARING, KEY_OUT_DISP_BOLT_BEARING, TYPE_TEXTBOX, '', True) + out_list.append(t4) + + t5 = (KEY_OUT_BOLT_CAPACITY, KEY_OUT_DISP_BOLT_CAPACITY, TYPE_TEXTBOX, + '', True) + out_list.append(t5) + + t17 = (None, DISP_TITLE_BOLTDS, TYPE_TITLE, None, True) + out_list.append(t17) + t17 = (KEY_OUT_TOT_NO_BOLTS, KEY_OUT_DISP_TOT_NO_BOLTS, TYPE_TEXTBOX, '', True) + out_list.append(t17) + + t11 = (KEY_PK_PLTHK, KEY_DISP_PK_PLTHK, TYPE_TEXTBOX, '', True) + out_list.append(t11) + + t18 = (KEY_OUT_ROW_PROVIDED, KEY_OUT_DISP_ROW_PROVIDED, TYPE_TEXTBOX,'', True) + out_list.append(t18) + + t19 = (KEY_OUT_COL_PROVIDED, KEY_OUT_DISP_COL_PROVIDED, TYPE_TEXTBOX,'', True) + out_list.append(t19) + + t20 = (KEY_OUT_BOLT_CONN_LEN, KEY_OUT_DISP_BOLT_CONN_LEN, TYPE_TEXTBOX,'', True) + out_list.append(t20) + + # t21 = (KEY_OUT_SPACING, KEY_OUT_DISP_SPACING, TYPE_OUT_BUTTON, ['Spacing Details', self.spacing], True) + # out_list.append(t21) + + return out_list + + def module_name(self): + + return KEY_DISP_BUTTJOINTBOLTED + + def call_3DColumn(self, ui, bgcolor): + # status = self.resultObj['Bolt']['status'] + # if status is True: + # self.ui.chkBx_beamSec1.setChecked(Qt.Checked) + if ui.chkBxCol.isChecked(): + ui.btn3D.setChecked(Qt.Unchecked) + ui.chkBxCol.setChecked(Qt.Unchecked) + ui.mytabWidget.setCurrentIndex(0) + # self.display_3DModel("Beam", bgcolor) + ui.commLogicObj.display_3DModel("Column", bgcolor) + + def get_3d_components(self): + components = [] + + t1 = ('Model', self.call_3DModel) + components.append(t1) + + t3 = ('Plate1', self.call_3DColumn) + components.append(t3) + + t4 = ('Plate2', self.call_3DPlate) + components.append(t4) + + return components + + def call_3DPlate(self, ui, bgcolor): + from PyQt5.QtWidgets import QCheckBox + from PyQt5.QtCore import Qt + for chkbox in ui.frame.children(): + if chkbox.objectName() == 'Cover Plate': + continue + if isinstance(chkbox, QCheckBox): + chkbox.setChecked(Qt.Unchecked) + ui.commLogicObj.display_3DModel("Cover Plate", bgcolor) + + + ################################ Outlist Dict ##################################################################################### + + + + ################################ Design Report ##################################################################################### \ No newline at end of file diff --git a/src/osdag/design_type/connection/lap_joint_bolted.py b/src/osdag/design_type/connection/lap_joint_bolted.py new file mode 100644 index 000000000..23e23bd2b --- /dev/null +++ b/src/osdag/design_type/connection/lap_joint_bolted.py @@ -0,0 +1,707 @@ +""" +Module: lap_joint_bolted.py +Author: Aman +Date: 2025-02-18 + +Description: + LapJointBolted is a moment connection module that represents a bolted lap joint connection. + It inherits from MomentConnection and follows the same structure and design logic as other + connection modules (e.g., BeamCoverPlate, ColumnCoverPlate) used in Osdag. + +Reference: + - Osdag software guidelines and connection module structure documentation +""" + +from .moment_connection import MomentConnection +from ...utils.common.component import * +from ...utils.common.is800_2007 import * +from ...Common import * +from ...design_report.reportGenerator_latex import CreateLatex +from ...Report_functions import * +from ...utils.common.load import Load +import logging + +import math + +class LapJointBolted(MomentConnection): + def __init__(self): + super(LapJointBolted, self).__init__() + self.design_status = False + + # self.spacing = None + + ############################################### + # Design Preference Functions Start + ############################################### + + def tab_list(self): + tabs = [] + # Only Bolt and Detailing tabs + tabs.append(("Bolt", TYPE_TAB_2, self.bolt_values)) + tabs.append(("Detailing", TYPE_TAB_2, self.detailing_values)) + return tabs + + def tab_value_changed(self): + # No tab value dependencies needed for bolt and detailing + return [] + + def edit_tabs(self): + return [] # Keep original empty implementation + + def input_dictionary_design_pref(self): + design_input = [] + + # Bolt preferences + design_input.append(("Bolt", TYPE_COMBOBOX, [ + KEY_DP_BOLT_TYPE, # For pretensioned/non-pretensioned + KEY_DP_BOLT_HOLE_TYPE, # For standard/oversized + KEY_DP_BOLT_SLIP_FACTOR # For slip factor as per Table 20 + ])) + + # Detailing preferences + design_input.append(("Detailing", TYPE_COMBOBOX, [ + KEY_DP_DETAILING_EDGE_TYPE # For edge preparation method + ])) + + return design_input + + def input_dictionary_without_design_pref(self): + design_input = [] + + # Default values for bolt and detailing + design_input.append((None, [ + KEY_DP_BOLT_TYPE, + KEY_DP_BOLT_HOLE_TYPE, + KEY_DP_BOLT_SLIP_FACTOR, + KEY_DP_DETAILING_EDGE_TYPE + ], '')) + + return design_input + + def get_values_for_design_pref(self, key, design_dictionary): + # Default values as per requirements + defaults = { + KEY_DP_BOLT_TYPE: "Non Pre-tensioned", + KEY_DP_BOLT_HOLE_TYPE: "Standard", + KEY_DP_BOLT_SLIP_FACTOR: "0.3", + KEY_DP_DETAILING_EDGE_TYPE: "Sheared or hand flame cut" + } + return defaults.get(key) + + def detailing_values(self, input_dictionary): + values = { + KEY_DP_DETAILING_EDGE_TYPE: 'Sheared or hand flame cut' + } + + for key in values.keys(): + if key in input_dictionary.keys(): + values[key] = input_dictionary[key] + + detailing = [] + + # Edge preparation method as per Cl. 10.2.4 of IS:800:2007 + t1 = (KEY_DP_DETAILING_EDGE_TYPE, KEY_DISP_DP_DETAILING_EDGE_TYPE, TYPE_COMBOBOX, + ['Sheared or hand flame cut', 'Rolled, machine-flame cut, sawn and planed'], + values[KEY_DP_DETAILING_EDGE_TYPE]) + detailing.append(t1) + t4 = ("textBrowser", "", TYPE_TEXT_BROWSER, DETAILING_DESCRIPTION_LAPJOINT, None) + detailing.append(t4) + + return detailing + + #################################### + # Design Preference Functions End + #################################### + def set_osdaglogger(key): + + """Function to set Logger for Tension Module""" + global logger + logger = logging.getLogger('Osdag') + + logger.setLevel(logging.DEBUG) + handler = logging.StreamHandler() + formatter = logging.Formatter(fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S') + + handler.setFormatter(formatter) + logger.addHandler(handler) + handler = logging.FileHandler('logging_text.log') + + formatter = logging.Formatter(fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S') + handler.setFormatter(formatter) + logger.addHandler(handler) + + if key is not None: + handler = OurLog(key) + formatter = logging.Formatter(fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + datefmt='%Y-%m-%d %H:%M:%S') + handler.setFormatter(formatter) + logger.addHandler(handler) + + + def input_value_changed(self): + + lst = [] + + t8 = ([KEY_MATERIAL], KEY_MATERIAL, TYPE_CUSTOM_MATERIAL, self.new_material) + lst.append(t8) + + return lst + + def input_values(self): + + options_list = [] + + t16 = (KEY_MODULE, KEY_DISP_LAPJOINTBOLTED, TYPE_MODULE, None, True, 'No Validator') + options_list.append(t16) + + t1 = (None, DISP_TITLE_CM, TYPE_TITLE, None, True, 'No Validator') + options_list.append(t1) + + t5 = (KEY_MATERIAL, KEY_DISP_MATERIAL, TYPE_COMBOBOX, VALUES_MATERIAL, True, 'No Validator') + options_list.append(t5) + + t31 = (KEY_PLATE1_THICKNESS, KEY_DISP_PLATE1_THICKNESS, TYPE_COMBOBOX, VALUES_PLATETHK_CUSTOMIZED, True, 'Int Validator') + options_list.append(t31) + + t34 = (KEY_PLATE2_THICKNESS, KEY_DISP_PLATE2_THICKNESS, TYPE_COMBOBOX, VALUES_PLATETHK_CUSTOMIZED, True, 'Int Validator') + options_list.append(t34) + + t35 = (KEY_PLATE_WIDTH, KEY_DISP_PLATE_WIDTH, TYPE_TEXTBOX, None, True, 'Float Validator') + options_list.append(t35) + + t6 = (None, DISP_TITLE_FSL, TYPE_TITLE, None, True, 'No Validator') + options_list.append(t6) + + t17 = (KEY_TENSILE_FORCE, KEY_DISP_TENSILE_FORCE, TYPE_TEXTBOX, None, True, 'Int Validator') + options_list.append(t17) + + t9 = (None, DISP_TITLE_BOLT, TYPE_TITLE, None, True, 'No Validator') + options_list.append(t9) + + t10 = (KEY_D, KEY_DISP_D, TYPE_COMBOBOX_CUSTOMIZED, VALUES_D, True, 'No Validator') + options_list.append(t10) + + t12 = (KEY_GRD, KEY_DISP_GRD, TYPE_COMBOBOX_CUSTOMIZED, VALUES_GRD, True, 'No Validator') + options_list.append(t12) + + t11 = (KEY_TYP, KEY_DISP_TYP, TYPE_COMBOBOX, VALUES_TYP, True, 'No Validator') + options_list.append(t11) + + return options_list + + def customized_input(self): + + list1 = [] + t1 = (KEY_GRD, self.grdval_customized) + list1.append(t1) + t3 = (KEY_D, self.diam_bolt_customized) + list1.append(t3) + + return list1 + + def spacing(self, status): + spacing = [] + + t00 = (None, "", TYPE_NOTE, "Representative Image for Spacing Details - 3 x 3 pattern considered") + spacing.append(t00) + + t99 = (None, 'Spacing Details', TYPE_SECTION, + [str(files("osdag.data.ResourceFiles.images").joinpath("spacing_3.png")), 400, 277, ""]) + spacing.append(t99) + + t9 = (KEY_OUT_PITCH, KEY_OUT_DISP_PITCH, TYPE_TEXTBOX, self.final_gauge if status else '') + spacing.append(t9) + + t10 = (KEY_OUT_END_DIST, KEY_OUT_DISP_END_DIST, TYPE_TEXTBOX, self.final_end_dist if status else '') + spacing.append(t10) + + t11 = (KEY_OUT_GAUGE, KEY_OUT_DISP_GAUGE, TYPE_TEXTBOX, self.final_pitch if status else '') + spacing.append(t11) + + t12 = (KEY_OUT_EDGE_DIST, KEY_OUT_DISP_EDGE_DIST, TYPE_TEXTBOX, self.final_edge_dist if status else '') + spacing.append(t12) + + return spacing + + def output_values(self, flag): + + out_list = [] + t4 = (None, DISP_TITLE_BOLTD, TYPE_TITLE, None, True) + out_list.append(t4) + + t2 = (KEY_OUT_D_PROVIDED, KEY_OUT_DISP_D_PROVIDED, TYPE_TEXTBOX, + self.bolt.bolt_diameter_provided if flag else '', True) + out_list.append(t2) + + t3 = (KEY_OUT_GRD_PROVIDED, KEY_OUT_DISP_GRD_PROVIDED, TYPE_TEXTBOX, + self.bolt.bolt_grade_provided if flag else '', True) + out_list.append(t3) + + t31 = (KEY_OUT_TYP_PROVIDED, KEY_OUT_DISP_TYP_PROVIDED, TYPE_TEXTBOX, + self.bolt.bolt_type if flag else '' , True) + out_list.append(t31) + + t8 = (KEY_OUT_BOLT_SHEAR,KEY_OUT_DISP_BOLT_SHEAR , TYPE_TEXTBOX,self.bolt.bolt_shear_capacity if flag else '', True) #convert to kn at last of the program + out_list.append(t8) + + t4 = (KEY_OUT_BOLT_BEARING, KEY_OUT_DISP_BOLT_BEARING, TYPE_TEXTBOX, self.bolt.bolt_bearing_capacity if flag else '', True) + out_list.append(t4) + + t5 = (KEY_OUT_BOLT_CAPACITY, KEY_OUT_DISP_BOLT_CAPACITY, TYPE_TEXTBOX, + self.bolt.bolt_capacity if flag else '', True) + out_list.append(t5) + + t500 = (KEY_OUT_BOLT_SLIP, KEY_OUT_DISP_BOLT_SLIP, TYPE_TEXTBOX, + self.slip_res if flag else '', True) + out_list.append(t500) + + t17 = (None, DISP_TITLE_BOLTDS, TYPE_TITLE, None, True) + out_list.append(t17) + t17 = (KEY_OUT_TOT_NO_BOLTS, KEY_OUT_DISP_TOT_NO_BOLTS, TYPE_TEXTBOX, self.number_bolts if flag else '', True) + out_list.append(t17) + t18 = (KEY_OUT_ROW_PROVIDED, KEY_OUT_DISP_ROW_PROVIDED, TYPE_TEXTBOX,self.rows if flag else '', True) + out_list.append(t18) + + t19 = (KEY_OUT_COL_PROVIDED, KEY_OUT_DISP_COL_PROVIDED, TYPE_TEXTBOX,self.cols if flag else '', True) + out_list.append(t19) + + t20 = (KEY_OUT_BOLT_CONN_LEN, KEY_OUT_DISP_BOLT_CONN_LEN, TYPE_TEXTBOX, self.len_conn if flag else '', True) + out_list.append(t20) + + t29 = (KEY_UTILIZATION_RATIO, KEY_DISP_UTILIZATION_RATIO, TYPE_TEXTBOX,self.utilization_ratio if flag else '', True) + out_list.append(t29) + + t21 = (KEY_OUT_SPACING, KEY_OUT_DISP_SPACING, TYPE_OUT_BUTTON, ['Spacing Details', self.spacing], True) + out_list.append(t21) + + + + return out_list + + def module_name(self): + + return KEY_DISP_LAPJOINTBOLTED + + def func_for_validation(self, design_dictionary): + + all_errors = [] + "check valid inputs and empty inputs in input dock" + self.design_status = False + flag = False + flag1 = False + flag2 = False + + option_list = self.input_values(self) + missing_fields_list = [] + + # print(f'\n func_for_validation option list = {option_list}' + # f'\n design_dictionary {design_dictionary}') + + for option in option_list: + if option[2] == TYPE_TEXTBOX: + if design_dictionary[option[0]] == '': + + missing_fields_list.append(option[1]) + else: + if option[2] == TYPE_TEXTBOX and option[0] == KEY_PLATE_WIDTH: + + if float(design_dictionary[option[0]]) <= 0.0: + error = "Input value(s) cannot be equal or less than zero." + all_errors.append(error) + else: + flag1 = True + + if option[2] == TYPE_TEXTBOX and option[0] == KEY_TENSILE_FORCE: + + if float(design_dictionary[option[0]]) <= 0.0: + error = "Input value(s) cannot be equal or less than zero." + all_errors.append(error) + else: + flag2 = True + else: + pass + + + if len(missing_fields_list) > 0: + error = self.generate_missing_fields_error_string(self, missing_fields_list) + all_errors.append(error) + else: + flag = True + if flag and flag1 and flag2: + self.set_input_values(self, design_dictionary) + else: + return all_errors + + def set_input_values(self, design_dictionary): + + "initialisation of components required to design a tension member along with connection" + + self.module = design_dictionary[KEY_MODULE] + self.mainmodule = "Lap Joint Bolted Connection" + self.main_material = design_dictionary[KEY_MATERIAL] + self.tensile_force = design_dictionary[KEY_TENSILE_FORCE] + self.width = design_dictionary[KEY_PLATE_WIDTH] + self.plate1 = Plate(thickness=[design_dictionary[KEY_PLATE1_THICKNESS]], + material_grade=design_dictionary[KEY_MATERIAL],width=design_dictionary[KEY_PLATE_WIDTH]) + self.plate2 = Plate(thickness=[design_dictionary[KEY_PLATE2_THICKNESS]], + material_grade=design_dictionary[KEY_MATERIAL],width=design_dictionary[KEY_PLATE_WIDTH]) + self.bolt = Bolt(grade=design_dictionary[KEY_GRD], diameter=design_dictionary[KEY_D], + bolt_type=design_dictionary[KEY_TYP], + bolt_hole_type=design_dictionary[KEY_DP_BOLT_HOLE_TYPE], + edge_type=design_dictionary[KEY_DP_DETAILING_EDGE_TYPE], + mu_f=design_dictionary.get(KEY_DP_BOLT_SLIP_FACTOR, None), + ) + self.planes = 1 + self.count = 0 + self.slip_res = None + self.yield_stress = None + # self.number_bolts = 0 + self.cap_red = False + self.bolt_dia_grade_status = False + self.dia_available = False + self.final_pitch = 0 + self.final_end_dist = 0 + self.final_edge_dist = 0 + self.final_gauge = 0 + self.rows = 0 + self.cols = 0 + self.len_conn = 0 + self.max_gauge_round = 0 + self.max_pitch_round = 0 + self.utilization_ratio = 0 + self.bij = 0 + self.blg = 0 + self.select_bolt_dia_and_grade(self,design_dictionary) + + def select_bolt_dia_and_grade(self,design_dictionary): + self.dia_available = False + self.bolt_dia_grade_status = False + + if isinstance(self.plate1.thickness, list): + self.plate1thk = self.plate1.thickness[0] + + if isinstance(self.plate2.thickness, list): + self.plate2thk = self.plate2.thickness[0] + + self.bolt_conn_plates_t_fu_fy = [] + self.bolt_conn_plates_t_fu_fy.append((float(self.plate1thk), self.plate1.fu, self.plate1.fy)) + self.bolt_conn_plates_t_fu_fy.append((float(self.plate2thk), self.plate2.fu, self.plate2.fy)) + + if float(self.plate1thk) < float(self.plate2thk): + self.plate = self.plate1 + self.pltthk = float(self.plate1thk) + self.yield_stress = self.plate1.fy + else: + self.plate = self.plate2 + self.pltthk = float(self.plate2thk) + self.yield_stress = self.plate2.fy + + for self.bolt.bolt_diameter_provided in self.bolt.bolt_diameter: + if 8 * float(self.bolt.bolt_diameter_provided) > (float(self.plate1thk) + float(self.plate2thk)): + self.dia_available = True + + for self.bolt.bolt_grade_provided in self.bolt.bolt_grade: + + self.bolt.calculate_bolt_spacing_limits(bolt_diameter_provided=float(self.bolt.bolt_diameter_provided), + conn_plates_t_fu_fy=self.bolt_conn_plates_t_fu_fy,n=self.planes) + + # self.max_pitch_round = self.max_gauge_round = + # self.bolt.calculate_bolt_capacity(bolt_diameter_provided=float(self.bolt.bolt_diameter_provided), + # bolt_grade_provided=float(self.bolt.bolt_grade_provided), + # conn_plates_t_fu_fy=self.bolt_conn_plates_t_fu_fy, + # n_planes=self.planes, e=float(self.bolt.min_end_dist_round), + # p=float(self.bolt.min_pitch_round)) + # self.bolt.calculate_bolt_tension_capacity(bolt_diameter_provided=self.bolt.bolt_diameter_provided, + # bolt_grade_provided=self.bolt.bolt_grade_provided) + # print("fnafnafan",self.bolt.bolt_capacity) + self.bolt.min_pitch_round = min(self.bolt.min_pitch_round, 2.5 * float(self.bolt.bolt_diameter_provided)) + self.bolt.min_gauge_round = min(self.bolt.min_gauge_round, 2.5 * float(self.bolt.bolt_diameter_provided)) + + if design_dictionary[KEY_DP_DETAILING_EDGE_TYPE] == 'Sheared or hand flame cut': + self.bolt.min_edge_dist_round = round(max(1.7 * float(self.bolt.bolt_diameter_provided),self.bolt.min_edge_dist_round),0) + self.bolt.min_end_dist_round = round(max(1.7 * float(self.bolt.bolt_diameter_provided),self.bolt.min_end_dist_round),0) + else: + self.bolt.min_edge_dist_round = round(max(1.5 * float(self.bolt.bolt_diameter_provided),self.bolt.min_edge_dist_round),0) + self.bolt.min_end_dist_round = round(max(1.5 * float(self.bolt.bolt_diameter_provided),self.bolt.min_end_dist_round),0) + + self.max_pitch_round = self.max_gauge_round = min(32 * self.pltthk , 300) + + self.bolt.max_edge_dist_round = self.bolt.max_end_dist_round = round(min(self.bolt.max_edge_dist_round , 12 * self.pltthk * ((250 / self.yield_stress)** 0.5 )),0) + self.bolt.calculate_bolt_capacity(bolt_diameter_provided=float(self.bolt.bolt_diameter_provided), + bolt_grade_provided=float(self.bolt.bolt_grade_provided), + conn_plates_t_fu_fy=self.bolt_conn_plates_t_fu_fy, + n_planes=self.planes, e=float(self.bolt.min_end_dist_round), + p=float(self.bolt.min_pitch_round)) + num_bolts = float(self.tensile_force) / ( self.bolt.bolt_capacity / 1000) + # print("num_bolts",num_bolts) + + if num_bolts <= 2: + self.bolt_dia_grade_status = True + break + + + if self.bolt_dia_grade_status == True: + break + + if self.dia_available == False: + self.design_status = False + logger.warning(" : The combined thickness ({} mm) exceeds the allowable large grip limit check (of {} mm) for the minimum available " + "bolt diameter of {} mm [Ref. Cl.10.3.3.2, IS 800:2007]." + .format((float(self.plate1thk) + float(self.plate2thk)),(8*self.bolt.bolt_diameter[-1]),self.bolt.bolt_diameter[-1])) + logger.error(": Design is not safe. \n ") + logger.info(" :=========End Of design===========") + + # elif self.dia_available == True and self.bolt_dia_grade_status == False: + # self.design_status = True + # if self.bolt.bolt_type == 'Bearing Bolt': + # self.bolt.bolt_bearing_capacity = round(float(self.bolt.bolt_bearing_capacity),2) + # self.bolt.bolt_shear_capacity = round(float(self.bolt.bolt_shear_capacity),2) + # self.bolt.bolt_capacity = round(float(self.bolt.bolt_capacity),2) + # print(self.bolt) + # self.number_r_c_bolts(self, design_dictionary) + + + else: + self.design_status = True + if self.bolt.bolt_type == 'Bearing Bolt': + self.bolt.bolt_bearing_capacity = round(float(self.bolt.bolt_bearing_capacity),2) + self.bolt.bolt_shear_capacity = round(float(self.bolt.bolt_shear_capacity),2) + self.bolt.bolt_capacity = round(float(self.bolt.bolt_capacity),2) + logger.info(" : Bolt diameter and grade selected are {} mm and {} respectively.".format(self.bolt.bolt_diameter_provided, self.bolt.bolt_grade_provided)) + # print(self.bolt) + self.number_r_c_bolts(self, design_dictionary,0,0) + + + def number_r_c_bolts(self,design_dictionary,count=0,hit=0): + + bolt_cap = self.bolt.bolt_capacity + if self.bolt.bolt_type == 'Bearing Bolt': + self.slip_res = 'N/A' + else: + self.slip_res = self.bolt.bolt_capacity + self.bolt.bolt_bearing_capacity = 'N/A' + self.bolt.bolt_shear_capacity = 'N/A' + + # print("fafafa",bolt_cap) + + if hit == 0: + self.number_bolts = float(self.tensile_force) /( bolt_cap / 1000) + else: + self.number_bolts += 1 + + print("Hit",hit,self.number_bolts) + + self.number_bolts = math.ceil(self.number_bolts) + if self.number_bolts < 2: + self.number_bolts = 2 + + def check_no_cols(numbolts): #in function for recursive call + if (2 * self.bolt.min_end_dist_round) + ((numbolts - 1 )*self.bolt.min_pitch_round) >= float(self.width): + return True + else: + return False + + self.cols = 1 + self.rows = self.number_bolts + temp_rows = self.rows + while True: + if check_no_cols(temp_rows): + temp_rows = math.ceil(self.rows/(self.cols + 1)) + self.cols += 1 + else: + break + self.rows = math.ceil(self.rows/self.cols) + if self.rows == 1: + self.rows = 2 + + if self.cols>1: + self.len_conn = (self.cols - 1)*self.bolt.min_pitch_round + 2*self.bolt.min_end_dist_round + + else: + self.len_conn = self.bolt.min_pitch_round + 2*self.bolt.min_end_dist_round + if self.number_bolts >= 2 and count == 0: + self.design_status = True + # print("Num bolts leaving",self.number_bolts) + self.check_capacity_reduction_1(self, design_dictionary) + elif self.number_bolts>=2 and count == 1: + self.design_status = True + self.final_formatting(self,design_dictionary) + else: + self.design_status = False + logger.error(": Number of min bolts not satisfied. \n ") + logger.info(" :=========End Of design===========") + + + def check_capacity_reduction_1(self,design_dictionary): + # print("Capacity red check 1") + if self.number_bolts > 2: + lg = (self.rows - 1)*self.bolt.min_pitch_round + if lg > 15 * self.bolt.bolt_diameter_provided: + self.bij = 1.075 - (lg / (200 * self.bolt.bolt_diameter_provided)) + if self.bij >= 0.75 and self.bij <= 1.0: + self.cap_red = True + # print("1 cap red") + self.bolt.bolt_shear_capacity = self.bolt.bolt_shear_capacity * self.bij + if self.bolt.bolt_type == 'Bearing Bolt': + self.bolt.bolt_capacity = min(self.bolt.bolt_shear_capacity, self.bolt.bolt_bearing_capacity) + else: + self.slip_res = self.bolt.bolt_shear_capacity + self.bolt.bolt_capacity = self.slip_res + + + self.design_status = True + self.check_capacity_reduction_2(self,design_dictionary) + + def check_capacity_reduction_2(self,design_dictionary): + self.cap_red = False + # print("Capacity red check 2") + if self.plate1thk + self.plate2thk > 5 * self.bolt.bolt_diameter_provided: + self.blg = 8 / (3 + (self.plate1thk + self.plate2thk / self.bolt.bolt_diameter_provided)) + if self.blg < self.bij and self.blg != 0: + self.cap_red = True + # print("blg",self.blg) + # print("2 cap red") + self.bolt.bolt_shear_capacity = self.bolt.bolt_shear_capacity * self.blg + if self.bolt.bolt_type == 'Bearing Bolt': + self.bolt.bolt_capacity = min(self.bolt.bolt_shear_capacity, self.bolt.bolt_bearing_capacity) + else: + self.slip_res = self.bolt.bolt_shear_capacity + self.bolt.bolt_capacity = self.slip_res + + self.number_r_c_bolts(self,design_dictionary,1,0) + + if self.cap_red == False: + self.design_status = True + # print("Going to formatting") + # print("After checks 2 numbolts",self.number_bolts) + self.final_formatting(self,design_dictionary) + + + + def final_formatting(self,design_dictionary): + # print("I am herefa fafjafjafjafjajfjafajf") + # print(self.bolt) + + gauge_dist = (float(self.width) - 2*self.bolt.min_end_dist_round)/(self.rows - 1) + + if gauge_dist > self.max_gauge_round: + self.final_gauge = self.max_gauge_round + self.final_pitch = self.bolt.min_pitch_round + + enddist = (float(self.width) - ((self.rows - 1)*self.final_gauge))/2 + if enddist > self.bolt.max_end_dist_round: + self.design_status = False + self.number_r_c_bolts(self,design_dictionary,0,1) + # print("okay") + + # self.design_status = True + else: + self.final_end_dist = enddist + self.final_edge_dist = enddist + self.design_status = True + else: + self.final_gauge = gauge_dist + self.final_pitch = self.bolt.min_pitch_round + enddist = (float(self.width) - ((self.rows - 1)*self.final_gauge))/2 + if enddist > self.bolt.max_end_dist_round: + # self.loop_helper_func(self,design_dictionary) + # print("okay") + # self.design_status = False + self.design_status = False + self.number_r_c_bolts(self,design_dictionary,0,1) + + + else: + self.final_end_dist = enddist + self.final_edge_dist = enddist + self.design_status = True + # print("I got here") + if self.bolt.bolt_type == 'Bearing Bolt': + self.bolt.bolt_shear_capacity = self.bolt.bolt_shear_capacity/ 1000 + self.bolt.bolt_bearing_capacity = self.bolt.bolt_bearing_capacity / 1000 + self.bolt.bolt_bearing_capacity = round(self.bolt.bolt_bearing_capacity, 2) + self.bolt.bolt_shear_capacity = round(self.bolt.bolt_shear_capacity, 2) + self.bolt.bolt_capacity = self.bolt.bolt_capacity / 1000 + self.bolt.bolt_capacity = round(self.bolt.bolt_capacity, 2) + else: + self.slip_res = self.slip_res / 1000 + self.slip_res = round(self.slip_res, 2) + self.bolt.bolt_capacity = self.bolt.bolt_capacity / 1000 + self.bolt.bolt_capacity = round(self.bolt.bolt_capacity, 2) + + # print("Going for util ratio") + # print("Still here") + # print("Numbolts",self.number_bolts) + bltcap = self.bolt.bolt_capacity + if bltcap < 1: + bltcap = 1 + self.utilization_ratio = float(self.tensile_force) / (bltcap * self.number_bolts) + self.utilization_ratio = round(self.utilization_ratio, 2) + + self.final_gauge = round(self.final_gauge,0) + self.final_pitch = round(self.final_pitch,0) + # print("fafafafafa",self.final_edge_dist, self.final_end_dist, self.final_pitch, self.final_gauge) + print("FINAL FINAL",self.bolt) + print("Final Edge/End/Gauge/Pitch",self.final_edge_dist,self.final_end_dist,self.final_gauge,self.final_pitch) + logger.info("Design is successful. \n") + # print(self) + # print("faahfnafanfaf") + print("Max and min end edge dist ",self.bolt.max_end_dist_round, self.bolt.min_end_dist_round, self.bolt.max_edge_dist_round, self.bolt.min_edge_dist_round) + print("Max min gauge pitch dist",self.max_gauge_round,self.bolt.min_gauge_round, self.max_pitch_round, self.bolt.min_pitch_round) + # self.design_status = True + + + + def call_3DColumn(self, ui, bgcolor): + # status = self.resultObj['Bolt']['status'] + # if status is True: + # self.ui.chkBx_beamSec1.setChecked(Qt.Checked) + if ui.chkBxCol.isChecked(): + ui.btn3D.setChecked(Qt.Unchecked) + ui.chkBxCol.setChecked(Qt.Unchecked) + ui.mytabWidget.setCurrentIndex(0) + # self.display_3DModel("Beam", bgcolor) + ui.commLogicObj.display_3DModel("Column", bgcolor) + + def get_3d_components(self): + components = [] + + t1 = ('Model', self.call_3DModel) + components.append(t1) + + t3 = ('Plate1', self.call_3DColumn) + components.append(t3) + + t4 = ('Plate2', self.call_3DPlate) + components.append(t4) + + return components + + def call_3DPlate(self, ui, bgcolor): + from PyQt5.QtWidgets import QCheckBox + from PyQt5.QtCore import Qt + for chkbox in ui.frame.children(): + if chkbox.objectName() == 'Cover Plate': + continue + if isinstance(chkbox, QCheckBox): + chkbox.setChecked(Qt.Unchecked) + ui.commLogicObj.display_3DModel("Cover Plate", bgcolor) + + def warn_text(self): + + """ + Function to give logger warning when any old value is selected from Column and Beams table. + """ + + # @author Arsil Zunzunia + global logger + red_list = red_list_function() + if self.supported_section.designation in red_list or self.supporting_section.designation in red_list: + logger.warning( + " : You are using a section (in red color) that is not available in latest version of IS 808") + logger.info( + " : You are using a section (in red color) that is not available in latest version of IS 808") + + def save_design(self, popup_summary): + print("\n\n\n\n Enterend save design") + logger.info(" :=========Start Of design Saving Button pressed===========") \ No newline at end of file diff --git a/src/osdag/design_type/connection/lap_joint_welded.py b/src/osdag/design_type/connection/lap_joint_welded.py new file mode 100644 index 000000000..cf8a74da7 --- /dev/null +++ b/src/osdag/design_type/connection/lap_joint_welded.py @@ -0,0 +1,433 @@ +""" +Module: lap_joint_bolted.py +Author: Aman +Date: 2025-02-18 + +Description: + LapJointBolted is a moment connection module that represents a bolted lap joint connection. + It inherits from MomentConnection and follows the same structure and design logic as other + connection modules (e.g., BeamCoverPlate, ColumnCoverPlate) used in Osdag. + +Reference: + - Osdag software guidelines and connection module structure documentation +""" + +from .moment_connection import MomentConnection +from ...utils.common.component import * +from ...utils.common.is800_2007 import * +from ...Common import * +from ...design_report.reportGenerator_latex import CreateLatex +from ...Report_functions import * +from ...utils.common.load import Load +import logging + +import math + +class LapJointWelded(MomentConnection): + def __init__(self): + super(LapJointWelded, self).__init__() + self.design_status = False + self.spacing = None + + ############################################### + # Design Preference Functions Start + ############################################### + def tab_list(self): + tabs = [] + # Only Bolt and Detailing tabs + tabs.append(("Bolt", TYPE_TAB_2, self.bolt_values)) + tabs.append(("Detailing", TYPE_TAB_2, self.detailing_values)) + return tabs + + def tab_value_changed(self): + # No tab value dependencies needed for bolt and detailing + return [] + + def edit_tabs(self): + return [] # Keep original empty implementation + + def input_dictionary_design_pref(self): + design_input = [] + + # Bolt preferences + design_input.append(("Bolt", TYPE_COMBOBOX, [ + KEY_DP_BOLT_TYPE, # For pretensioned/non-pretensioned + KEY_DP_BOLT_HOLE_TYPE, # For standard/oversized + KEY_DP_BOLT_SLIP_FACTOR # For slip factor as per Table 20 + ])) + + # Detailing preferences + design_input.append(("Detailing", TYPE_COMBOBOX, [ + KEY_DP_DETAILING_EDGE_TYPE # For edge preparation method + ])) + + return design_input + + def input_dictionary_without_design_pref(self): + design_input = [] + + # Default values for bolt and detailing + design_input.append((None, [ + KEY_DP_BOLT_TYPE, + KEY_DP_BOLT_HOLE_TYPE, + KEY_DP_BOLT_SLIP_FACTOR, + KEY_DP_DETAILING_EDGE_TYPE + ], '')) + + return design_input + + def get_values_for_design_pref(self, key, design_dictionary): + # Default values as per requirements + defaults = { + KEY_DP_BOLT_TYPE: "Non Pre-tensioned", + KEY_DP_BOLT_HOLE_TYPE: "Standard", + KEY_DP_BOLT_SLIP_FACTOR: "0.3", + KEY_DP_DETAILING_EDGE_TYPE: "Sheared or hand flame cut" + } + return defaults.get(key) + + def detailing_values(self, input_dictionary): + values = { + KEY_DP_DETAILING_EDGE_TYPE: 'Sheared or hand flame cut' + } + + for key in values.keys(): + if key in input_dictionary.keys(): + values[key] = input_dictionary[key] + + detailing = [] + + # Edge preparation method as per Cl. 10.2.4 of IS:800:2007 + t1 = (KEY_DP_DETAILING_EDGE_TYPE, KEY_DISP_DP_DETAILING_EDGE_TYPE, TYPE_COMBOBOX, + ['Sheared or hand flame cut', 'Rolled, machine-flame cut, sawn and planed'], + values[KEY_DP_DETAILING_EDGE_TYPE]) + detailing.append(t1) + t4 = ("textBrowser", "", TYPE_TEXT_BROWSER, DETAILING_DESCRIPTION_LAPJOINT, None) + detailing.append(t4) + + return detailing + + # def bolt_values(self, input_dictionary): + # values = { + # KEY_DP_BOLT_TYPE: 'Non Pre-tensioned', + # KEY_DP_BOLT_HOLE_TYPE: 'Standard', + # KEY_DP_BOLT_SLIP_FACTOR: '0.3' + # } + + # for key in values.keys(): + # if key in input_dictionary.keys(): + # values[key] = input_dictionary[key] + + # bolt = [] + + # # Bolt type selection + # t1 = (KEY_DP_BOLT_TYPE, "Type", TYPE_COMBOBOX, + # ['Non Pre-tensioned', 'Pre-tensioned'], + # values[KEY_DP_BOLT_TYPE]) + # bolt.append(t1) + + # # Bolt hole type + # t2 = (KEY_DP_BOLT_HOLE_TYPE, "Bolt Hole", TYPE_COMBOBOX, + # ['Standard', 'Over-sized'], + # values[KEY_DP_BOLT_HOLE_TYPE]) + # bolt.append(t2) + + # # Slip factor as per Table 20 of IS 800 + # t3 = (KEY_DP_BOLT_SLIP_FACTOR, "Slip Factor", TYPE_COMBOBOX, + # ['0.3', '0.45', '0.5'], + # values[KEY_DP_BOLT_SLIP_FACTOR]) + # bolt.append(t3) + + # return bolt + + + #################################### + # Design Preference Functions End + #################################### + + def set_osdaglogger(key): + + """ + Function to set Logger for Tension Module + """ + + # @author Arsil Zunzunia + global logger + logger = logging.getLogger('Osdag') + + logger.setLevel(logging.DEBUG) + handler = logging.StreamHandler() + formatter = logging.Formatter(fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S') + + handler.setFormatter(formatter) + logger.addHandler(handler) + handler = logging.FileHandler('logging_text.log') + + formatter = logging.Formatter(fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S') + handler.setFormatter(formatter) + logger.addHandler(handler) + + if key is not None: + handler = OurLog(key) + formatter = logging.Formatter(fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + datefmt='%Y-%m-%d %H:%M:%S') + handler.setFormatter(formatter) + logger.addHandler(handler) + + + def input_value_changed(self): + + lst = [] + + t8 = ([KEY_MATERIAL], KEY_MATERIAL, TYPE_CUSTOM_MATERIAL, self.new_material) + lst.append(t8) + + return lst + + + def input_values(self): + + options_list = [] + + t16 = (KEY_MODULE, KEY_DISP_LAPJOINTBOLTED, TYPE_MODULE, None, True, 'No Validator') + options_list.append(t16) + + t1 = (None, DISP_TITLE_CM, TYPE_TITLE, None, True, 'No Validator') + options_list.append(t1) + + t5 = (KEY_MATERIAL, KEY_DISP_MATERIAL, TYPE_COMBOBOX, VALUES_MATERIAL, True, 'No Validator') + options_list.append(t5) + + t31 = (KEY_PLATE1_THICKNESS, KEY_DISP_PLATE1_THICKNESS, TYPE_COMBOBOX, VALUES_PLATETHK_CUSTOMIZED, True, 'Int Validator') + options_list.append(t31) + + t34 = (KEY_PLATE2_THICKNESS, KEY_DISP_PLATE2_THICKNESS, TYPE_COMBOBOX, VALUES_PLATETHK_CUSTOMIZED, True, 'Int Validator') + options_list.append(t34) + + t35 = (KEY_PLATE_WIDTH, KEY_DISP_PLATE_WIDTH, TYPE_TEXTBOX, None, True, 'Float Validator') + options_list.append(t35) + + t6 = (None, DISP_TITLE_FSL, TYPE_TITLE, None, True, 'No Validator') + options_list.append(t6) + + t17 = (KEY_TENSILE_FORCE, KEY_DISP_TENSILE_FORCE, TYPE_TEXTBOX, None, True, 'Int Validator') + options_list.append(t17) + + t9 = (None, DISP_TITLE_BOLT, TYPE_TITLE, None, True, 'No Validator') + options_list.append(t9) + + t10 = (KEY_D, KEY_DISP_D, TYPE_COMBOBOX_CUSTOMIZED, VALUES_D, True, 'No Validator') + options_list.append(t10) + + t12 = (KEY_GRD, KEY_DISP_GRD, TYPE_COMBOBOX_CUSTOMIZED, VALUES_GRD, True, 'No Validator') + options_list.append(t12) + + t11 = (KEY_TYP, KEY_DISP_TYP, TYPE_COMBOBOX, VALUES_TYP, True, 'No Validator') + options_list.append(t11) + + return options_list + + def customized_input(self): + + list1 = [] + t1 = (KEY_GRD, self.grdval_customized) + list1.append(t1) + t3 = (KEY_D, self.diam_bolt_customized) + list1.append(t3) + # t5 = (KEY_PLATE1_THICKNESS, self.plate_thick_customized) + # list1.append(t5) + # t6 = (KEY_PLATE2_THICKNESS, self.plate_thick_customized) + # list1.append(t6) + + return list1 + + def spacing(self, status): + spacing = [] + + t00 = (None, "", TYPE_NOTE, "Representative Image for Spacing Details - 3 x 3 pattern considered") + spacing.append(t00) + + t99 = (None, 'Spacing Details', TYPE_SECTION, + [str(files("osdag.data.ResourceFiles.images").joinpath("spacing_3.png")), 400, 277, ""]) # [image, width, height, caption] + spacing.append(t99) + + t9 = (KEY_OUT_PITCH, KEY_OUT_DISP_PITCH, TYPE_TEXTBOX, self.plate.gauge_provided if status else '') + spacing.append(t9) + + t10 = (KEY_OUT_END_DIST, KEY_OUT_DISP_END_DIST, TYPE_TEXTBOX, self.plate.edge_dist_provided if status else '') + spacing.append(t10) + + t11 = (KEY_OUT_GAUGE, KEY_OUT_DISP_GAUGE, TYPE_TEXTBOX, self.plate.pitch_provided if status else '') + spacing.append(t11) + + t12 = (KEY_OUT_EDGE_DIST, KEY_OUT_DISP_EDGE_DIST, TYPE_TEXTBOX, self.plate.end_dist_provided if status else '') + spacing.append(t12) + + return spacing + + def output_values(self, flag): + + out_list = [] + t4 = (None, DISP_TITLE_BOLTD, TYPE_TITLE, None, True) + out_list.append(t4) + + t2 = (KEY_OUT_D_PROVIDED, KEY_OUT_DISP_D_PROVIDED, TYPE_TEXTBOX, + '', True) + out_list.append(t2) + + t3 = (KEY_OUT_GRD_PROVIDED, KEY_OUT_DISP_GRD_PROVIDED, TYPE_TEXTBOX, + '', True) + out_list.append(t3) + + t31 = (KEY_OUT_TYP_PROVIDED, KEY_OUT_DISP_TYP_PROVIDED, TYPE_TEXTBOX, + '', True) + out_list.append(t31) + + t8 = (KEY_OUT_BOLT_SHEAR,KEY_OUT_DISP_BOLT_SHEAR , TYPE_TEXTBOX, '', True) + out_list.append(t8) + + t4 = (KEY_OUT_BOLT_BEARING, KEY_OUT_DISP_BOLT_BEARING, TYPE_TEXTBOX, '', True) + out_list.append(t4) + + t5 = (KEY_OUT_BOLT_CAPACITY, KEY_OUT_DISP_BOLT_CAPACITY, TYPE_TEXTBOX, + '', True) + out_list.append(t5) + + t17 = (None, DISP_TITLE_BOLTDS, TYPE_TITLE, None, True) + out_list.append(t17) + t17 = (KEY_OUT_TOT_NO_BOLTS, KEY_OUT_DISP_TOT_NO_BOLTS, TYPE_TEXTBOX, '', True) + out_list.append(t17) + t18 = (KEY_OUT_ROW_PROVIDED, KEY_OUT_DISP_ROW_PROVIDED, TYPE_TEXTBOX,'', True) + out_list.append(t18) + + t19 = (KEY_OUT_COL_PROVIDED, KEY_OUT_DISP_COL_PROVIDED, TYPE_TEXTBOX,'', True) + out_list.append(t19) + + t20 = (KEY_OUT_BOLT_CONN_LEN, KEY_OUT_DISP_BOLT_CONN_LEN, TYPE_TEXTBOX,'', True) + out_list.append(t20) + + t21 = (KEY_OUT_SPACING, KEY_OUT_DISP_SPACING, TYPE_OUT_BUTTON, ['Spacing Details', self.spacing], True) + out_list.append(t21) + + return out_list + + def module_name(self): + + return KEY_DISP_LAPJOINTBOLTED + + def func_for_validation(self, design_dictionary): + + all_errors = [] + "check valid inputs and empty inputs in input dock" + # print(design_dictionary,'djsgggggggggggggggggggggggggggggggggggggggggggggggggggggggg') + self.design_status = False + + flag = False + flag1 = False + flag2 = False + # self.include_status = True + + option_list = self.input_values(self) + missing_fields_list = [] + + print(f'\n func_for_validation option list = {option_list}' + f'\n design_dictionary {design_dictionary}') + + for option in option_list: + if option[2] == TYPE_TEXTBOX: + 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_PLATE_WIDTH: + # val = option[4] + # print(design_dictionary[option[0]], "jhvhj") + if float(design_dictionary[option[0]]) <= 0.0: + error = "Input value(s) cannot be equal or less than zero." + all_errors.append(error) + else: + flag1 = True + + if option[2] == TYPE_TEXTBOX and option[0] == KEY_TENSILE_FORCE: + + if float(design_dictionary[option[0]]) <= 0.0: + error = "Input value(s) cannot be equal or less than zero." + all_errors.append(error) + else: + flag2 = True + else: + pass + + + if len(missing_fields_list) > 0: + error = self.generate_missing_fields_error_string(self, missing_fields_list) + all_errors.append(error) + # flag = False + else: + flag = True + if flag and flag1 and flag2: + # self.set_input_values(self, design_dictionary) + # print("DESIGN DICT" + str(design_dictionary)) + print("succsess") + else: + return all_errors + + + def call_3DColumn(self, ui, bgcolor): + # status = self.resultObj['Bolt']['status'] + # if status is True: + # self.ui.chkBx_beamSec1.setChecked(Qt.Checked) + if ui.chkBxCol.isChecked(): + ui.btn3D.setChecked(Qt.Unchecked) + ui.chkBxCol.setChecked(Qt.Unchecked) + ui.mytabWidget.setCurrentIndex(0) + # self.display_3DModel("Beam", bgcolor) + ui.commLogicObj.display_3DModel("Column", bgcolor) + + def get_3d_components(self): + components = [] + + t1 = ('Model', self.call_3DModel) + components.append(t1) + + t3 = ('Plate1', self.call_3DColumn) + components.append(t3) + + t4 = ('Plate2', self.call_3DPlate) + components.append(t4) + + return components + + def call_3DPlate(self, ui, bgcolor): + from PyQt5.QtWidgets import QCheckBox + from PyQt5.QtCore import Qt + for chkbox in ui.frame.children(): + if chkbox.objectName() == 'Cover Plate': + continue + if isinstance(chkbox, QCheckBox): + chkbox.setChecked(Qt.Unchecked) + ui.commLogicObj.display_3DModel("Cover Plate", bgcolor) + + def warn_text(self): + + """ + Function to give logger warning when any old value is selected from Column and Beams table. + """ + + # @author Arsil Zunzunia + global logger + red_list = red_list_function() + if self.supported_section.designation in red_list or self.supporting_section.designation in red_list: + logger.warning( + " : You are using a section (in red color) that is not available in latest version of IS 808") + logger.info( + " : You are using a section (in red color) that is not available in latest version of IS 808") + + + ################################ Outlist Dict ##################################################################################### + + + + ################################ Design Report ##################################################################################### \ No newline at end of file diff --git a/src/osdag/design_type/connection/moment_connection.py b/src/osdag/design_type/connection/moment_connection.py index 0e44f6823..d4218ad67 100644 --- a/src/osdag/design_type/connection/moment_connection.py +++ b/src/osdag/design_type/connection/moment_connection.py @@ -21,9 +21,10 @@ def __init__(self): def tab_section(self, input_dictionary): "In design preference, it shows other properties of section used " - - if not input_dictionary or input_dictionary[KEY_SECSIZE] == 'Select Section' or \ - input_dictionary[KEY_MATERIAL] == 'Select Material': + section_value = input_dictionary.get(KEY_SECSIZE, 'Select Section') + material_value = input_dictionary.get(KEY_MATERIAL, 'Select Material') + if not input_dictionary or section_value == 'Select Section' or material_value == 'Select Material': + designation = '' material_grade = '' source = 'Custom' @@ -54,8 +55,8 @@ def tab_section(self, input_dictionary): warping_const = '' image = VALUES_IMG_BEAM[0] else: - designation = str(input_dictionary[KEY_SECSIZE]) - material_grade = str(input_dictionary[KEY_MATERIAL]) + designation = str(input_dictionary.get(KEY_SECSIZE, '')) + material_grade = str(input_dictionary.get(KEY_MATERIAL, '')) m_o_e = "200" m_o_r = "76.9" p_r = "0.3" diff --git a/src/osdag/design_type/main.py b/src/osdag/design_type/main.py index d4c742ee9..cab5f623f 100644 --- a/src/osdag/design_type/main.py +++ b/src/osdag/design_type/main.py @@ -90,8 +90,8 @@ def weld_values(self, input_dictionary): def detailing_values(self, input_dictionary): values = {KEY_DP_DETAILING_EDGE_TYPE: 'Sheared or hand flame cut', - KEY_DP_DETAILING_GAP: '10', - KEY_DP_DETAILING_CORROSIVE_INFLUENCES: 'No'} + KEY_DP_DETAILING_GAP: '10', + KEY_DP_DETAILING_CORROSIVE_INFLUENCES: 'No'} for key in values.keys(): if key in input_dictionary.keys(): @@ -100,15 +100,15 @@ def detailing_values(self, input_dictionary): detailing = [] t1 = (KEY_DP_DETAILING_EDGE_TYPE, KEY_DISP_DP_DETAILING_EDGE_TYPE, TYPE_COMBOBOX, - ['Sheared or hand flame cut', 'Rolled, machine-flame cut, sawn and planed'], - values[KEY_DP_DETAILING_EDGE_TYPE]) + ['Sheared or hand flame cut', 'Rolled, machine-flame cut, sawn and planed'], + values[KEY_DP_DETAILING_EDGE_TYPE]) detailing.append(t1) t2 = (KEY_DP_DETAILING_GAP, KEY_DISP_DP_DETAILING_GAP, TYPE_TEXTBOX, None, values[KEY_DP_DETAILING_GAP]) detailing.append(t2) t3 = (KEY_DP_DETAILING_CORROSIVE_INFLUENCES, KEY_DISP_DP_DETAILING_CORROSIVE_INFLUENCES, TYPE_COMBOBOX, - ['No', 'Yes'], values[KEY_DP_DETAILING_CORROSIVE_INFLUENCES]) + ['No', 'Yes'], values[KEY_DP_DETAILING_CORROSIVE_INFLUENCES]) detailing.append(t3) t4 = ("textBrowser", "", TYPE_TEXT_BROWSER, DETAILING_DESCRIPTION, None) @@ -131,6 +131,9 @@ def design_values(self, input_dictionary): values[KEY_DP_DESIGN_METHOD]) design.append(t1) + t9 = ("textBrowser", "", TYPE_TEXT_BROWSER, DESIGN_METHOD_DESCRIPTION , None) + design.append(t9) + return design def plate_connector_values(self, input_dictionary): @@ -510,4 +513,4 @@ def call_3DModel(self, ui, bgcolor): continue if isinstance(chkbox, QCheckBox): chkbox.setChecked(Qt.Unchecked) - ui.commLogicObj.display_3DModel("Model", bgcolor) + ui.commLogicObj.display_3DModel("Model", bgcolor) \ No newline at end of file diff --git a/src/osdag/design_type/member.py b/src/osdag/design_type/member.py index a4822d0a6..dd3e239a7 100644 --- a/src/osdag/design_type/member.py +++ b/src/osdag/design_type/member.py @@ -3,6 +3,7 @@ from ..utils.common.component import * from ..utils.common.Section_Properties_Calculator import * from .main import Main +from ..utils.common.Unsymmetrical_Section_Properties import Unsymmetrical_I_Section_Properties class Member(Main): @@ -2863,7 +2864,40 @@ def optimization_tab_plate_girder_design(self, input_dictionary): optimum.append(t1) t2 = (KEY_ShearBucklingOption, KEY_ShearBuckling, TYPE_COMBOBOX, KEY_DISP_SB_Option, values[KEY_ShearBucklingOption]) optimum.append(t2) - t9 = ("textBrowser", "", TYPE_TEXT_BROWSER, FLEXURE_OPTIMIZATION_DESCRIPTION , None) + t9 = ("textBrowser", "", TYPE_TEXT_BROWSER, FLEXURE_OPTIMIZATION_DESCRIPTION_SimplySupp , None) + optimum.append(t9) + + return optimum + + def optimization_tab_welded_plate_girder_design(self, input_dictionary): + print(f"optimization_tab_flexure_design input_dictionary {input_dictionary}") + values = { + KEY_EFFECTIVE_AREA_PARA: '1.0', KEY_ALLOW_CLASS: 'Yes', KEY_LOAD : 'Normal', KEY_LENGTH_OVERWRITE :'NA', + } + + for key in values.keys(): + if key in input_dictionary.keys(): + values[key] = input_dictionary[key] + + 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) + + + + t9 = ("textBrowser", "", TYPE_TEXT_BROWSER, FLEXURE_OPTIMIZATION_DESCRIPTION_SimplySupp , None) optimum.append(t9) return optimum @@ -2871,7 +2905,12 @@ def optimization_tab_plate_girder_design(self, input_dictionary): def Stiffener_design(self, input_dictionary): optimum = [] values = {KEY_IntermediateStiffener:'Yes', - KEY_IntermediateStiffener_spacing:'NA' + KEY_IntermediateStiffener_spacing:'NA', + KEY_LongitudnalStiffener:'Yes and 1 stiffener', + KEY_IntermediateStiffener_thickness:'6', + KEY_LongitudnalStiffener_thickness:'6', + KEY_ShearBucklingOption : KEY_DISP_SB_Option[0] + } for key in values.keys(): @@ -2882,26 +2921,288 @@ 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 and 1 stiffener','Yes and 2 stiffeners','No'], 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) + t11 = (KEY_LongitudnalStiffener_thickness,KEY_DISP_LongitudnalStiffener_thickness,TYPE_COMBOBOX,['All','Customized'],values[KEY_LongitudnalStiffener_thickness]) + optimum.append(t11) + t1 = (None, KEY_WEB_BUCKLING, TYPE_TITLE, None, True, 'No Validator') + optimum.append(t1) + t2 = (KEY_ShearBucklingOption, KEY_ShearBuckling, TYPE_COMBOBOX, KEY_DISP_SB_Option, values[KEY_ShearBucklingOption]) + optimum.append(t2) + t9 = ("textBrowser", "", TYPE_TEXT_BROWSER, Stiffener_Plategirder_para , None) + optimum.append(t9) return optimum + + def girder_geometry(self, input_dictionary): + values = { + KEY_IS_IT_SYMMETRIC : 'Symmetrical' + } + + for key in values.keys(): + if key in input_dictionary.keys(): + values[key] = input_dictionary[key] + + optimum = [] + + t2 = (KEY_IS_IT_SYMMETRIC, KEY_DISP_IS_IT_SYMMETRIC, TYPE_COMBOBOX, KEY_DISP_SYMMETRIC_list, values[KEY_IS_IT_SYMMETRIC]) + optimum.append(t2) + t9 = ("textBrowser", "", TYPE_TEXT_BROWSER, ADDITIONAL_GIRDER_DESCRIPTION , None) + optimum.append(t9) + + return optimum + + + def tab_girder_sec(self, input_dictionary): + + + #initialize variables + material = connectdb("Material", call_type="popup") + material_grade = material[1] + mat = Material(material_grade,41) + fu = mat.fu #material fu + fy = mat.fy #material fy + m_o_e = 200 + m_o_r = 76.9 + p_r = 0.3 + t_e = 12 + tot_depth = '750' + web_thickness = '10' + top_flange_width = '300' + top_flange_thickness = '15' + bottom_flange_width = '400' + bottom_flange_thickness = '20' + mass = '' + area = '' + mom_inertia_z = '' + mom_inertia_y = '' + rad_of_gy_z = '' + rad_of_gy_y = '' + elast_sec_mod_z = '' + elast_sec_mod_y = '' + plast_sec_mod_z = '' + plast_sec_mod_y = '' + torsion_const = '' + warping_const = '' + image = VALUES_IMG_BEAM[0] #just any image put into the place just to check + + + + section = [] + + t2 = (None, KEY_DISP_MECH_PROP, TYPE_TITLE, None, None) + section.append(t2) + + t34 = (KEY_SEC_MATERIAL, KEY_DISP_MATERIAL, TYPE_COMBOBOX, material, material_grade) + section.append(t34) + + t3 = (KEY_SEC_FU, KEY_DISP_FU, TYPE_TEXTBOX, None, fu) + section.append(t3) + + t4 = (KEY_SEC_FY, KEY_DISP_FY, TYPE_TEXTBOX, None, fy) + section.append(t4) + + t15 = ('Label_1', KEY_DISP_MOD_OF_ELAST, TYPE_TEXTBOX, None, m_o_e) + section.append(t15) + + t16 = ('Label_2', KEY_DISP_MOD_OF_RIGID, TYPE_TEXTBOX, None, m_o_r) + section.append(t16) + + t31 = ('Label_3', KEY_DISP_POISSON_RATIO, TYPE_TEXTBOX, None, p_r) + section.append(t31) + + t32 = ('Label_4', KEY_DISP_THERMAL_EXP, TYPE_TEXTBOX, None, t_e) + section.append(t32) + + t14 = ('Label_5', KEY_DISP_TYPE, TYPE_COMBOBOX, ['Welded'], 'Welded') + section.append(t14) + + t5 = (None, KEY_DISP_DIMENSIONS, TYPE_TITLE, None, None) + section.append(t5) + + t6 = ('Label_6', KEY_DISP_OVERALL_DEPTH_PG, TYPE_TEXTBOX, None, tot_depth) + section.append(t6) + + t9 = ('Label_7', KEY_DISP_WEB_THICKNESS_PG, TYPE_TEXTBOX, None, web_thickness) + section.append(t9) + + t7 = ('Label_8',KEY_DISP_TOP_Bflange_PG , TYPE_TEXTBOX, None, top_flange_width) + section.append(t7) + + t8 = ('Label_9', KEY_DISP_TOP_FLANGE_THICKNESS_PG, TYPE_TEXTBOX, None, top_flange_thickness) + section.append(t8) + + t7 = ('Label_10',KEY_DISP_BOTTOM_Bflange_PG , TYPE_TEXTBOX, None, bottom_flange_width) + section.append(t7) + + t8 = ('Label_11', KEY_DISP_BOTTOM_FLANGE_THICKNESS_PG, TYPE_TEXTBOX, None, bottom_flange_thickness) + section.append(t8) + + t13 = (None, None, TYPE_BREAK, None, None) + section.append(t13) + + t17 = (None, KEY_DISP_SEC_PROP, TYPE_TITLE, None, None) + section.append(t17) + + t18 = ('Label_12', KEY_DISP_MASS, TYPE_TEXTBOX, None, mass) + section.append(t18) + + t19 = ('Label_13', KEY_DISP_AREA, TYPE_TEXTBOX, None, area) + section.append(t19) + + t20 = ('Label_14', KEY_DISP_MOA_IZ, TYPE_TEXTBOX, None, mom_inertia_z) + section.append(t20) + + t21 = ('Label_15', KEY_DISP_MOA_IY, TYPE_TEXTBOX, None, mom_inertia_y) + section.append(t21) + + t22 = ('Label_16', KEY_DISP_ROG_RZ, TYPE_TEXTBOX, None, rad_of_gy_z) + section.append(t22) + + t23 = ('Label_17', KEY_DISP_ROG_RY, TYPE_TEXTBOX, None, rad_of_gy_y) + section.append(t23) + + t24 = ('Label_18', KEY_DISP_EM_ZZ, TYPE_TEXTBOX, None, elast_sec_mod_z) + section.append(t24) + + t25 = ('Label_19', KEY_DISP_EM_ZY, TYPE_TEXTBOX, None, elast_sec_mod_y) + section.append(t25) + + t26 = ('Label_20', KEY_DISP_PM_ZPZ, TYPE_TEXTBOX, None, plast_sec_mod_z) + section.append(t26) + + t27 = ('Label_21', KEY_DISP_PM_ZPY, TYPE_TEXTBOX, None, plast_sec_mod_y) + section.append(t27) + + t26 = ('Label_22', KEY_DISP_It, TYPE_TEXTBOX, None, torsion_const) + section.append(t26) + + t27 = ('Label_23', KEY_DISP_Iw, TYPE_TEXTBOX, None, warping_const) + section.append(t27) + + t13 = (None, None, TYPE_BREAK, None, None) + section.append(t13) + + t17 = (None, 'Dynamic Image', TYPE_TITLE, None, None) + section.append(t17) + + t33 = (KEY_IMAGE, None, TYPE_IMAGE, None, image) + section.append(t33) + + return section + + def deflection_values(self, input_dictionary): + + values = {} + + for key in values.keys(): + if key in input_dictionary.keys(): + values[key] = input_dictionary[key] + + deflection = [] + + t1 = (KEY_STR_TYPE,KEY_DISP_STR_TYPE, TYPE_COMBOBOX, KEY_DISP_STR_TYPE_list, KEY_DISP_STR_TYPE_list[0]) + deflection.append(t1) + t2 = (KEY_DESIGN_LOAD, KEY_DISP_DESIGN_LOAD, TYPE_COMBOBOX, VALUE_DESIGN_LOAD_list, VALUE_DESIGN_LOAD_list[0]) + deflection.append(t2) + t3 = (KEY_MEMBER_OPTIONS,KEY_DISP_MEMBER_OPTIONS, TYPE_COMBOBOX, VALUES_MEMBER_OPTIONS[0], VALUES_MEMBER_OPTIONS[0][0]) + deflection.append(t3) + t4 = (KEY_SUPPORTING_OPTIONS,KEY_DISP_SUPPORTING_OPTIONS, TYPE_COMBOBOX, VALUES_SUPPORTING_OPTIONS_DEF, VALUES_SUPPORTING_OPTIONS_DEF[0]) + deflection.append(t4) + t5 = (KEY_MAX_DEFL,KEY_DISP_MAX_DEFL, TYPE_TEXTBOX, None , VALUES_MAX_DEFL[0]) + deflection.append(t5) + t9 = ("textBrowser", "", TYPE_TEXT_BROWSER, PLATE_GIRDER_DEFLECTION_TABLE , None) + deflection.append(t9) + return deflection ######################################## # Design Preference Functions End ######################################## + def get_fu_fy_I_section_plate_girder(self): + material_grade = self[0] - # def customized_input(self): - # - # list1 = [] - # t1 = (KEY_GRD, self.grdval_customized) - # list1.append(t1) - # t3 = (KEY_D, self.diam_bolt_customized) - # list1.append(t3) - # t6 = (KEY_PLATETHK, self.plate_thick_customized) - # list1.append(t6) - # # t8 = (KEY_SIZE, self.size_customized) - # # list1.append(t8) - # return list1 + fu = '' + fy = '' + if material_grade != "Select Material": + material = Material(material_grade, 41) + fu = material.fu + fy = material.fy + else: + pass + + d = { + KEY_SEC_FU: fu, + KEY_SEC_FY: fy} + + return d + + def Unsymm_I_Section_properties(self): + mass = '' + area = '' + mom_inertia_z = '' + mom_inertia_y = '' + rad_of_gy_z = '' + rad_of_gy_y = '' + elast_sec_mod_z = '' + elast_sec_mod_y = '' + plast_sec_mod_z = '' + plast_sec_mod_y = '' + torsion_const = '' + warping_const = '' + + # print("\n\n\n\n\n") + # print(self[6]) + # print("\n FROM NOW OBJECT 6") + # for i in self: + # print(i) + # print("\n") + + t_d = float(self[0]) + w_t = float(self[1]) + t_f_w = float(self[2]) + t_f_t = float(self[3]) + b_f_w = float(self[4]) + b_f_t = float(self[5]) + eps = math.sqrt(250/float(self[6])) # Assuming self[6] is the yield strength in MPa + + + pc = Unsymmetrical_I_Section_Properties() + + mass = pc.calc_mass(t_d,t_f_w,b_f_w,w_t,t_f_t,b_f_t) + area = pc.calc_area(t_d,t_f_w,b_f_w,w_t,t_f_t,b_f_t) + mom_inertia_z = pc.calc_MomentOfAreaZ(t_d,t_f_w,b_f_w,w_t,t_f_t,b_f_t) + mom_inertia_y = pc.calc_MomentOfAreaY(t_d,t_f_w,b_f_w,w_t,t_f_t,b_f_t) + rad_of_gy_z = pc.calc_RadiusOfGyrationZ(t_d,t_f_w,b_f_w,w_t,t_f_t,b_f_t) + rad_of_gy_y = pc.calc_RadiusOfGyrationY(t_d,t_f_w,b_f_w,w_t,t_f_t,b_f_t) + elast_sec_mod_z = pc.calc_ElasticModulusZz(t_d,t_f_w,b_f_w,w_t,t_f_t,b_f_t) + elast_sec_mod_y = pc.calc_ElasticModulusZy(t_d,t_f_w,b_f_w,w_t,t_f_t,b_f_t) + plast_sec_mod_z = pc.calc_PlasticModulusZ(t_d,t_f_w,b_f_w,w_t,t_f_t,b_f_t,eps) + plast_sec_mod_y = pc.calc_PlasticModulusY(t_d,t_f_w,b_f_w,w_t,t_f_t,b_f_t) + torsion_const = pc.calc_TorsionConstantIt(t_d,t_f_w,b_f_w,w_t,t_f_t,b_f_t) + warping_const = pc.calc_WarpingConstantIw(t_d,t_f_w,b_f_w,w_t,t_f_t,b_f_t) + + + + + + + + return { + 'Label_12': str(int(round(mass, 0))), + 'Label_13': str(int(round(area / 100, 0))), + 'Label_14': str(int(round(mom_inertia_z / 10000, 0))), + 'Label_15': str(int(round(mom_inertia_y / 10000, 0))), + 'Label_16': str(int(round(rad_of_gy_z / 10, 0))), + 'Label_17': str(int(round(rad_of_gy_y / 10, 0))), + 'Label_18': str(int(round(elast_sec_mod_z / 1000, 0))), + 'Label_19': str(int(round(elast_sec_mod_y / 1000, 0))), + 'Label_20': str(int(round(plast_sec_mod_z / 1000, 0))), + 'Label_21': str(int(round(plast_sec_mod_y / 1000, 0))), + 'Label_22': str(int(round(torsion_const / 10000, 0))), + 'Label_23': str(int(round(warping_const / 1000000, 0))) +} @staticmethod def grdval_customized(): @@ -2999,4 +3300,4 @@ def call_3DEndplate(self, ui, bgcolor): continue if isinstance(chkbox, QCheckBox): chkbox.setChecked(Qt.Unchecked) - ui.commLogicObj.display_3DModel("Endplate", bgcolor) + ui.commLogicObj.display_3DModel("Endplate", bgcolor) \ No newline at end of file diff --git a/src/osdag/design_type/plate_girder/__init__.py b/src/osdag/design_type/plate_girder/__init__.py index e69de29bb..eecdf78e3 100644 --- a/src/osdag/design_type/plate_girder/__init__.py +++ b/src/osdag/design_type/plate_girder/__init__.py @@ -0,0 +1,15 @@ +""" +================================================================================ +pyswarm: Particl swarm optimization (PSO) with constraint support +================================================================================ + +Author: Abraham Lee +Copyright: 2013-2014 + +""" +# from __future__ import absolute_import + +__author__ = 'Abraham Lee' +__version__ = '0.6' + +from pyswarm.pso import * \ No newline at end of file diff --git a/src/osdag/design_type/plate_girder/pso.py b/src/osdag/design_type/plate_girder/pso.py new file mode 100644 index 000000000..9fa969dbd --- /dev/null +++ b/src/osdag/design_type/plate_girder/pso.py @@ -0,0 +1,98 @@ +import numpy as np + +def pso(func, lb, ub, ieqcons=[], f_ieqcons=None, args=(), kwargs={}, + swarmsize=600, omega=0.5, phip=0.5, phig=0.5, maxiter=1000, + minstep=1e-8, minfunc=1e-8, debug=False): + assert len(lb) == len(ub) + lb = np.array(lb) + ub = np.array(ub) + vhigh = np.abs(ub - lb) + vlow = -vhigh + + obj = lambda x: func(x, *args, **kwargs) + if f_ieqcons is None: + cons = (lambda x: np.array([0])) if not len(ieqcons) \ + else (lambda x: np.array([y(x, *args, **kwargs) for y in ieqcons])) + else: + cons = lambda x: np.array(f_ieqcons(x, *args, **kwargs)) + + def is_feasible(x, eps=1e-12): + cons_val = cons(x) + print(f'Constraint values: {cons_val}') + return np.all(cons_val >= -eps) # strictly >=0; small epsilon for numeric tolerance + + # Helper: generate a feasible position + def random_feasible_point(): + for _ in range(10000): + candidate = lb + np.random.rand(len(lb)) * (ub - lb) + if is_feasible(candidate): + return candidate + raise RuntimeError("Cannot find feasible initial particle!") + + # Initialize + S, D = swarmsize, len(lb) + x = np.zeros((S, D)) + v = np.zeros_like(x) + p = np.zeros_like(x) + fp = np.full(S, np.inf) + g = None + fg = np.inf + + # Feasible initialization + for i in range(S): + x[i, :] = random_feasible_point() + p[i, :] = x[i, :].copy() + fp[i] = obj(p[i, :]) + if i == 0 or (fp[i] < fg and is_feasible(p[i, :])): + g = p[i, :].copy() + fg = fp[i] + v[i, :] = vlow + np.random.rand(D) * (vhigh - vlow) + + # Main loop + it = 1 + while it <= maxiter: + rp = np.random.uniform(size=(S, D)) + rg = np.random.uniform(size=(S, D)) + for i in range(S): + v[i, :] = omega * v[i, :] + phip * rp[i, :] * (p[i, :] - x[i, :]) + phig * rg[i, :] * (g - x[i, :]) + x[i, :] = x[i, :] + v[i, :] + + # Project to bounds + x[i, :] = np.clip(x[i, :], lb, ub) + + # Ensure feasibility + if not is_feasible(x[i, :]): + # Option 1: resample until feasible + x[i, :] = random_feasible_point() + # Option 2 (alternative): reflect or repair (optional) + + fx = obj(x[i, :]) + + # Personal best update + if is_feasible(x[i, :]) and (fx < fp[i] or not is_feasible(p[i, :])): + p[i, :] = x[i, :].copy() + fp[i] = fx + + # Global best update + if fx < fg or not is_feasible(g): + if debug: + print(f'New best for swarm at iteration {it}: {x[i, :]} {fx}') + tmp = x[i, :].copy() + stepsize = np.sqrt(np.sum((g - tmp) ** 2)) if g is not None else np.inf + if np.abs(fg - fx) <= minfunc: + print(f'Stopping search: Swarm best objective change less than {minfunc}') + return tmp, fx + elif stepsize <= minstep: + print(f'Stopping search: Swarm best position change less than {minstep}') + return tmp, fx + else: + g = tmp.copy() + fg = fx + if debug: + print(f'Best after iteration {it}: {g} {fg}') + it += 1 + + print(f'Stopping search: maximum iterations reached --> {maxiter}') + if not is_feasible(g): + print("However, the optimization couldn't find a feasible design. Sorry") + return g, fg diff --git a/src/osdag/design_type/plate_girder/weldedPlateGirder.py b/src/osdag/design_type/plate_girder/weldedPlateGirder.py index d73849438..de9d2d93d 100644 --- a/src/osdag/design_type/plate_girder/weldedPlateGirder.py +++ b/src/osdag/design_type/plate_girder/weldedPlateGirder.py @@ -1,8 +1,13 @@ """ @Author: Rutvik Joshi - Osdag Team, IIT Bombay [(P) rutvikjoshi63@gmail.com / 30005086@iitb.ac.in] +12.03.2025 +Revised Design for GUI: Parth Karia - Osdag Team, IIT Bombay [30006096@iitb.ac.in] + +@Module - Beam Design- Simply Supported member + - Laterally Supported Beam [Moment + Shear] + - Laterally Unsupported Beam [Moment + Shear] -@Module - Plate Girder- Welded @Reference(s): 1) IS 800: 2007, General construction in steel - Code of practice (Third revision) 2) IS 808: 1989, Dimensions for hot rolled steel beam, column, channel, and angle sections and @@ -16,7 +21,12 @@ """ import logging import math + + +import pyswarm import numpy as np +from pyswarms.single.global_best import GlobalBestPSO +from pyswarm import pso from ...Common import * # from ..connection.moment_connection import MomentConnection from ...utils.common.material import * @@ -31,130 +41,306 @@ from ...utils.common.Section_Properties_Calculator import BBAngle_Properties from ...utils.common import is800_2007 from ...utils.common.component import * -from ...utils.common.Section_Properties_Calculator import I_sectional_Properties -from ..flexural_member.flexure import Flexure -''' -Debugging tools -''' -# from icecream import ic - -class Custom_Girder():#Material - # def __new__(self,design_dictionary): - def __init__(self, design_dictionary,design): - # super(Custom_Girder,self).__init__()#material_grade - print("Girder Object Initialised") - self.designation = 'User Defined' - if design: - self.flange_thickness = 1e-3 - self.depth = 1e-3 - self.depth_web = 1e-3 - self.flange_width = 1e-3 - self.web_thickness = 1e-3 - self.flange_slope = 90 - self.root_radius = 1e-3 - self.toe_radius = 1e-3 - self.type = 'Welded' - self.shear_area = self.depth_web * self.web_thickness - self.mass = round( - I_sectional_Properties().calc_Mass(self.depth, self.flange_width, self.web_thickness, self.flange_thickness, - self.flange_slope, self.root_radius, self.toe_radius) * 10 ** 1) - self.area = round( - I_sectional_Properties().calc_Area(self.depth, self.flange_width, self.web_thickness, self.flange_thickness, - self.flange_slope, self.root_radius, self.toe_radius) * 10 ** 2) - self.mom_inertia_z = round( - I_sectional_Properties().calc_MomentOfAreaZ(self.depth, self.flange_width, self.web_thickness, - self.flange_thickness, self.flange_slope, self.root_radius, - self.toe_radius) * 10 ** 4) - self.mom_inertia_y = round( - I_sectional_Properties().calc_MomentOfAreaY(self.depth, self.flange_width, self.web_thickness, - self.flange_thickness, self.flange_slope, self.root_radius, - self.toe_radius) * 10 ** 4) - self.rad_of_gy_z = round( - I_sectional_Properties().calc_RogZ(self.depth, self.flange_width, self.web_thickness, self.flange_thickness, - self.flange_slope, self.root_radius, self.toe_radius) * 10 ** 1) - self.rad_of_gy_y = round( - I_sectional_Properties().calc_RogY(self.depth, self.flange_width, self.web_thickness, self.flange_thickness, - self.flange_slope, self.root_radius, self.toe_radius) * 10 ** 1) - self.elast_sec_mod_z = round( - I_sectional_Properties().calc_ElasticModulusZz(self.depth, self.flange_width, self.web_thickness, - self.flange_thickness, self.flange_slope, self.root_radius, - self.toe_radius) * 10 ** 3) - self.elast_sec_mod_y = round( - I_sectional_Properties().calc_ElasticModulusZy(self.depth, self.flange_width, self.web_thickness, - self.flange_thickness, self.flange_slope, self.root_radius, - self.toe_radius) * 10 ** 3) - self.plast_sec_mod_z = round( - I_sectional_Properties().calc_PlasticModulusZpz(self.depth, self.flange_width, self.web_thickness, - self.flange_thickness, self.flange_slope, self.root_radius, - self.toe_radius) * 10 ** 3) - self.plast_sec_mod_y = round( - I_sectional_Properties().calc_PlasticModulusZpy(self.depth, self.flange_width, self.web_thickness, - self.flange_thickness, self.flange_slope, self.root_radius, - self.toe_radius) * 10 ** 3) - # print(self.flange_thickness) - else : - self.section_defined(design_dictionary) - - def section_defined(self,design_dictionary): - self.flange_thickness = float(design_dictionary[KEY_tf]) - self.depth_web = float(design_dictionary[KEY_dw]) - self.depth = float(design_dictionary[KEY_dw]) + 2 * self.flange_thickness - self.flange_width = float(design_dictionary[KEY_bf]) - self.web_thickness = float(design_dictionary[KEY_tw]) - self.flange_slope = 90 - self.root_radius = 0 - self.toe_radius = 0 - self.type = 'Welded' - self.shear_area = self.depth_web * self.web_thickness - - self.mass = round( - I_sectional_Properties().calc_Mass(self.depth, self.flange_width, self.web_thickness, self.flange_thickness, - self.flange_slope, self.root_radius, self.toe_radius) * 10 ** 1) - self.area = round( - I_sectional_Properties().calc_Area(self.depth, self.flange_width, self.web_thickness, self.flange_thickness, - self.flange_slope, self.root_radius, self.toe_radius) * 10 ** 2) - self.mom_inertia_z = round( - I_sectional_Properties().calc_MomentOfAreaZ(self.depth, self.flange_width, self.web_thickness, - self.flange_thickness, self.flange_slope, self.root_radius, - self.toe_radius) * 10 ** 4) - self.mom_inertia_y = round( - I_sectional_Properties().calc_MomentOfAreaY(self.depth, self.flange_width, self.web_thickness, - self.flange_thickness, self.flange_slope, self.root_radius, - self.toe_radius) * 10 ** 4) - self.rad_of_gy_z = round( - I_sectional_Properties().calc_RogZ(self.depth, self.flange_width, self.web_thickness, self.flange_thickness, - self.flange_slope, self.root_radius, self.toe_radius) * 10 ** 1) - self.rad_of_gy_y = round( - I_sectional_Properties().calc_RogY(self.depth, self.flange_width, self.web_thickness, self.flange_thickness, - self.flange_slope, self.root_radius, self.toe_radius) * 10 ** 1) - self.elast_sec_mod_z = round( - I_sectional_Properties().calc_ElasticModulusZz(self.depth, self.flange_width, self.web_thickness, - self.flange_thickness, self.flange_slope, self.root_radius, - self.toe_radius) * 10 ** 3) - self.elast_sec_mod_y = round( - I_sectional_Properties().calc_ElasticModulusZy(self.depth, self.flange_width, self.web_thickness, - self.flange_thickness, self.flange_slope, self.root_radius, - self.toe_radius) * 10 ** 3) - self.plast_sec_mod_z = round( - I_sectional_Properties().calc_PlasticModulusZpz(self.depth, self.flange_width, self.web_thickness, - self.flange_thickness, self.flange_slope, self.root_radius, - self.toe_radius) * 10 ** 3) - self.plast_sec_mod_y = round( - I_sectional_Properties().calc_PlasticModulusZpy(self.depth, self.flange_width, self.web_thickness, - self.flange_thickness, self.flange_slope, self.root_radius, - self.toe_radius) * 10 ** 3) - # print(self.flange_thickness) - def __str__(self) -> str: - return "Customised Girder generated" +from osdag.cad.items.plate import Plate +from ...utils.common.Unsymmetrical_Section_Properties import Unsymmetrical_I_Section_Properties + + +#GUI TO SELECT CUSTOM IN DESIGN PREFERENCES +from PyQt5 import QtCore, QtWidgets +from PyQt5.QtWidgets import QDialog, QListWidget, QListWidgetItem +from PyQt5.QtWidgets import ( + QDialog, QLabel, QLineEdit, QPushButton, QFormLayout, + QApplication, QMessageBox +) +from PyQt5.QtGui import QFont +from PyQt5.QtCore import Qt +import re +import sys + +scale = 1 # For resizing components + +class RangeInputDialog(QDialog): + def __init__(self): + super().__init__() + self.setWindowTitle("Custom Range Input") + self.setFixedSize(350, 200) + self.set_styles() + + self.values = [] + + self.lower_input = QLineEdit() + self.upper_input = QLineEdit() + self.step_input = QLineEdit() + + for widget in [self.lower_input, self.upper_input, self.step_input]: + widget.setFont(QFont("Segoe UI", 11)) # Slightly larger font + widget.setFixedHeight(32) # Increased height + + # Form layout + form_layout = QFormLayout() + form_layout.setLabelAlignment(Qt.AlignRight) + form_layout.setFormAlignment(Qt.AlignCenter) + + lower_label = QLabel("Lower Bound:") + upper_label = QLabel("Upper Bound:") + step_label = QLabel("Step:") + + for label in [lower_label, upper_label, step_label]: + label.setFont(QFont("Segoe UI", 10)) + + form_layout.addRow(lower_label, self.lower_input) + form_layout.addRow(upper_label, self.upper_input) + form_layout.addRow(step_label, self.step_input) + + self.submit_button = QPushButton("Add") + self.submit_button.setFont(QFont("Segoe UI", 10, QFont.Bold)) + self.submit_button.clicked.connect(self.validate_and_submit) + + form_layout.addRow(self.submit_button) + self.setLayout(form_layout) + + def set_styles(self): + self.setStyleSheet(""" + QDialog { + background-color: white; + } + QLabel { + font-size: 10pt; + } + QLineEdit { + font-size: 11pt; + padding: 4px 6px; + border: 1px solid #aaa; + border-radius: 3px; + } + QPushButton { + background-color: #814c4c; + color: white; + font-size: 10pt; + font-weight: bold; + height: 28px; + border-radius: 4px; + } + QPushButton:hover { + background-color: #a05c5c; + } + """) + + def validate_and_submit(self): + lower_text = self.lower_input.text().strip() + upper_text = self.upper_input.text().strip() + step_text = self.step_input.text().strip() + + if not lower_text or not upper_text or not step_text: + self.show_error("All fields must be filled.") + return + + try: + lower = float(lower_text) + upper = float(upper_text) + step = float(step_text) + + if step <= 0: + self.show_error("Step must be greater than 0.") + return + + self.values = [lower, upper, step] + self.accept() + + except ValueError: + self.show_error("Please enter valid numeric values.") + + def show_error(self, message): + QMessageBox.warning(self, "Input Error", message) + + def get_values(self): + return self.values + + +class My_ListWidget(QListWidget): + def addItems(self, Iterable, p_str=None): + super().addItems(Iterable) + self.sortItems() + + def addItem(self, *__args): + super().addItem(My_ListWidgetItem(__args[0])) + self.sortItems() + +class My_ListWidgetItem(QListWidgetItem): + def __lt__(self, other): + try: + self_text = str(re.sub("[^0-9.]", "", self.text())) + other_text = str(re.sub("[^0-9.]", "", other.text())) + return float(self_text) < float(other_text) + except Exception: + return super().__lt__(other) + +class PopupDialog(QDialog): + def __init__(self, disabled_values=[], note="", parent=None): + super().__init__(parent) + self.disabled_values = disabled_values + self.note = note + self.setWindowTitle("Customized") + self.resize(int(scale*540), int(scale*470)) + self.init_ui() + self.set_styles() + + def init_ui(self): + self.label = QtWidgets.QLabel("Available:", self) + self.label.setGeometry(QtCore.QRect(20, 20, 150, 30)) + + self.label_2 = QtWidgets.QLabel("Selected:", self) + self.label_2.setGeometry(QtCore.QRect(int(scale * 320), 20, 150, 30)) + + self.listWidget = My_ListWidget(self) + self.listWidget.setGeometry(QtCore.QRect(20, 50, int(scale*180), int(scale*300))) + self.listWidget.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) + self.listWidget.itemDoubleClicked.connect(self.move_to_selected) + + self.listWidget_2 = My_ListWidget(self) + self.listWidget_2.setGeometry(QtCore.QRect(int(scale*320), 50, int(scale*180), int(scale*300))) + self.listWidget_2.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) + self.listWidget_2.itemDoubleClicked.connect(self.move_to_available) + + self.pushButton = QtWidgets.QPushButton(">>", self) + self.pushButton.setGeometry(QtCore.QRect(int(scale*225), int(scale*140), int(scale*70), int(scale*30))) + + self.pushButton_2 = QtWidgets.QPushButton(">", self) + self.pushButton_2.setGeometry(QtCore.QRect(int(scale*225), int(scale*180), int(scale*70), int(scale*30))) + + self.pushButton_3 = QtWidgets.QPushButton("<", self) + self.pushButton_3.setGeometry(QtCore.QRect(int(scale*225), int(scale*220), int(scale*70), int(scale*30))) + + self.pushButton_4 = QtWidgets.QPushButton("<<", self) + self.pushButton_4.setGeometry(QtCore.QRect(int(scale*225), int(scale*260), int(scale*70), int(scale*30))) + + self.pushButton_5 = QtWidgets.QPushButton("Submit", self) + self.pushButton_5.setGeometry(QtCore.QRect(int(scale*190), int(scale*400), int(scale*140), int(scale*35))) + self.pushButton_5.setDefault(True) + + self.pushButton.clicked.connect(self.move_all_to_selected) + self.pushButton_2.clicked.connect(self.move_selected_to_selected) + self.pushButton_3.clicked.connect(self.move_selected_to_available) + self.pushButton_4.clicked.connect(self.move_all_to_available) + self.pushButton_5.clicked.connect(self.accept) + + self.listWidget.itemSelectionChanged.connect(self.update_buttons_status) + self.listWidget_2.itemSelectionChanged.connect(self.update_buttons_status) + + self.update_buttons_status() + + def update_buttons_status(self): + self.pushButton_2.setDisabled(not bool(self.listWidget.selectedItems())) + self.pushButton_3.setDisabled(not bool(self.listWidget_2.selectedItems())) + + def move_selected_to_selected(self): + for item in self.listWidget.selectedItems(): + self.listWidget_2.addItem(item.text()) + for item in self.listWidget.selectedItems(): + self.listWidget.takeItem(self.listWidget.row(item)) + + def move_selected_to_available(self): + for item in self.listWidget_2.selectedItems(): + self.listWidget.addItem(item.text()) + for item in self.listWidget_2.selectedItems(): + self.listWidget_2.takeItem(self.listWidget_2.row(item)) + + def move_all_to_selected(self): + while self.listWidget.count() > 0: + self.listWidget_2.addItem(self.listWidget.takeItem(0).text()) + + def move_all_to_available(self): + while self.listWidget_2.count() > 0: + self.listWidget.addItem(self.listWidget_2.takeItem(0).text()) + + def move_to_selected(self, item): + self.listWidget_2.addItem(item.text()) + self.listWidget.takeItem(self.listWidget.row(item)) + + def move_to_available(self, item): + self.listWidget.addItem(item.text()) + self.listWidget_2.takeItem(self.listWidget_2.row(item)) + + def get_selected_items(self): + return [self.listWidget_2.item(i).text() for i in range(self.listWidget_2.count())] + + def set_styles(self): + brown = "#925a5b" + grey = "#8e8e8e" + white = "#ffffff" + + button_style = f""" + QPushButton {{ + background-color: {brown}; + color: {white}; + border-radius: 6px; + font-size: 22px; + padding: 6px 18px; + border: none; + }} + QPushButton:disabled {{ + background-color: {grey}; + color: {white}; + }} + """ + for btn in [self.pushButton, self.pushButton_2, self.pushButton_3, self.pushButton_4, self.pushButton_5]: + btn.setStyleSheet(button_style) + + list_item_style = """ + QListWidget::item { + font-size: 24px; + color: black; + margin: 2px 0px; + } + """ + scrollbar_style = f""" + QScrollBar:vertical {{ + border: none; + background: #f5f5f5; + width: 12px; + border-radius: 6px; + }} + QScrollBar::handle:vertical {{ + background: {grey}; + min-height: 20px; + border-radius: 6px; + }} + QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {{ + background: none; + height: 0px; + }} + QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {{ + background: none; + }} + QScrollBar:horizontal {{ + height: 0px; + }} + """ + self.listWidget.setStyleSheet(list_item_style + scrollbar_style) + self.listWidget_2.setStyleSheet(list_item_style + scrollbar_style) + + + + + + + + class PlateGirderWelded(Member): + int_thicklist = [] + long_thicklist = [] def __init__(self): super(PlateGirderWelded, self).__init__() + self.design_status = False + + ############################################### # Design Preference Functions Start ############################################### def tab_list(self): + """ :return: This function returns the list of tuples. Each tuple will create a tab in design preferences, in the @@ -170,44 +356,54 @@ def tab_list(self): """ tabs = [] - t1 = (KEY_DISP_COLSEC, TYPE_TAB_1, self.tab_section) + + t1 = (KEY_DISP_GIRDERSEC, TYPE_TAB_1, self.tab_girder_sec) tabs.append(t1) - # t2 = ("Under Development", TYPE_TAB_2, self.optimization_tab_plate_girder_design) - # tabs.append(t2) - t5 = ("Under Development", TYPE_TAB_2, self.optimization_tab_plate_girder_design) + t5 = ("Optimisation", TYPE_TAB_2, self.optimization_tab_welded_plate_girder_design) tabs.append(t5) t1 = ("Stiffeners", TYPE_TAB_2, self.Stiffener_design) tabs.append(t1) + t1 = ("Additional Girder Data", TYPE_TAB_2, self.girder_geometry) + tabs.append(t1) + t5 = ("Design", TYPE_TAB_2, self.design_values) tabs.append(t5) + t6 = ("Deflection" , TYPE_TAB_2, self.deflection_values) + tabs.append(t6) + return tabs + def tab_value_changed(self): change_tab = [] - t1 = (KEY_DISP_COLSEC, [KEY_SEC_MATERIAL], [KEY_SEC_FU, KEY_SEC_FY], TYPE_TEXTBOX, self.get_fu_fy_I_section) + t1 = (KEY_DISP_GIRDERSEC, [KEY_SEC_MATERIAL], [KEY_SEC_FU, KEY_SEC_FY], TYPE_TEXTBOX, self.get_fu_fy_I_section_plate_girder) change_tab.append(t1) - t4 = (KEY_DISP_COLSEC, ['Label_1', 'Label_2', 'Label_3', 'Label_4', 'Label_5'], - ['Label_11', 'Label_12', 'Label_13', 'Label_14', 'Label_15', 'Label_16', 'Label_17', 'Label_18', - 'Label_19', 'Label_20', 'Label_21', 'Label_22', KEY_IMAGE], TYPE_TEXTBOX, self.get_I_sec_properties) + t4 = (KEY_DISP_GIRDERSEC, ['Label_6', 'Label_7', 'Label_8', 'Label_9', 'Label_10', 'Label_11',KEY_SEC_FY], + ['Label_12', 'Label_13', 'Label_14', 'Label_15', 'Label_16', 'Label_17', 'Label_18', + 'Label_19', 'Label_20', 'Label_21', 'Label_22','Label_23'], TYPE_TEXTBOX, self.Unsymm_I_Section_properties) change_tab.append(t4) - t5 = (KEY_DISP_COLSEC, ['Label_HS_1', 'Label_HS_2', 'Label_HS_3'], - ['Label_HS_11', 'Label_HS_12', 'Label_HS_13', 'Label_HS_14', 'Label_HS_15', 'Label_HS_16', 'Label_HS_17', 'Label_HS_18', - 'Label_HS_19', 'Label_HS_20', 'Label_HS_21', 'Label_HS_22', KEY_IMAGE], TYPE_TEXTBOX, self.get_SHS_RHS_properties) - change_tab.append(t5) + t9 = ("Deflection", [KEY_STR_TYPE], [KEY_MEMBER_OPTIONS], TYPE_COMBOBOX, self.member_options_change) + change_tab.append(t9) + t9 = ("Deflection", [KEY_MEMBER_OPTIONS], [KEY_SUPPORTING_OPTIONS], TYPE_COMBOBOX, self.supp_options_change) + change_tab.append(t9) + t9 = ("Deflection", [KEY_STR_TYPE,KEY_DESIGN_LOAD,KEY_MEMBER_OPTIONS,KEY_SUPPORTING_OPTIONS], [KEY_MAX_DEFL], TYPE_TEXTBOX, self.max_defl_change) + change_tab.append(t9) + t10 = ("Stiffeners", [KEY_IntermediateStiffener_thickness], [KEY_IntermediateStiffener_thickness_val], TYPE_COMBOBOX, self.Int_stiffener_thickness_customized) + change_tab.append(t10) + t11 = ("Stiffeners", [KEY_LongitudnalStiffener_thickness], [KEY_LongitudnalStiffener_thickness_val], TYPE_COMBOBOX, self.Long_stiffener_thickness_customized) + change_tab.append(t11) + + + # t10 = ('Stiffeners',[KEY_WEB_PHILOSOPHY],[KEY_IntermediateStiffener_spacing],TYPE_TEXTBOX,self.Intm_stiffener_spacing_change) + # change_tab.append(t10) - t6 = (KEY_DISP_COLSEC, ['Label_CHS_1', 'Label_CHS_2', 'Label_CHS_3'], - ['Label_CHS_11', 'Label_CHS_12', 'Label_CHS_13', 'Label_HS_14', 'Label_HS_15', 'Label_HS_16', 'Label_21', 'Label_22', - KEY_IMAGE], TYPE_TEXTBOX, self.get_CHS_properties) - change_tab.append(t6) - t6 = (KEY_DISP_COLSEC, [KEY_SECSIZE], [KEY_SOURCE], TYPE_TEXTBOX, self.change_source) - change_tab.append(t6) return change_tab @@ -215,6 +411,7 @@ def edit_tabs(self): """ This function is required if the tab name changes based on connectivity or profile or any other key. Not required for this module but empty list should be passed""" return [] + def input_dictionary_design_pref(self): """ @@ -223,39 +420,54 @@ def input_dictionary_design_pref(self): It returns list of tuple which contains, tab name, input widget type of keys, keys whose values to be saved, [(Tab Name, input widget type of keys, [List of keys to be saved])] - TODO : Material pop-up + """ design_input = [] - t1 = (KEY_DISP_COLSEC, TYPE_COMBOBOX, [KEY_SEC_MATERIAL])#Need to check + t1 = (KEY_DISP_GIRDERSEC, TYPE_COMBOBOX, [KEY_SEC_MATERIAL])#Need to check design_input.append(t1) - - t1 = (KEY_DISP_COLSEC, TYPE_TEXTBOX, [KEY_SEC_FU, KEY_SEC_FY]) + + t1 = (KEY_DISP_GIRDERSEC, TYPE_TEXTBOX, [KEY_SEC_FU, KEY_SEC_FY]) design_input.append(t1) - t2 = ("Under Development", TYPE_TEXTBOX, [ KEY_EFFECTIVE_AREA_PARA, KEY_LENGTH_OVERWRITE, KEY_BEARING_LENGTH]) #, KEY_STEEL_COST + t2 = ("Optimisation", TYPE_TEXTBOX, [KEY_EFFECTIVE_AREA_PARA, KEY_LENGTH_OVERWRITE]) # , KEY_STEEL_COST design_input.append(t2) - t2 = ("Under Development", TYPE_COMBOBOX, [KEY_ALLOW_CLASS, KEY_LOAD, KEY_ShearBucklingOption]) #, KEY_STEEL_COST + t2 = ("Optimisation", TYPE_COMBOBOX, [KEY_ALLOW_CLASS, KEY_LOAD]) # , KEY_STEEL_COST design_input.append(t2) - t2 = ("Stiffeners", TYPE_COMBOBOX, [KEY_IntermediateStiffener]) + t2 = ("Stiffeners", TYPE_COMBOBOX, [KEY_IntermediateStiffener,KEY_LongitudnalStiffener,KEY_IntermediateStiffener_thickness,KEY_LongitudnalStiffener_thickness]) design_input.append(t2) t2 = ("Stiffeners", TYPE_TEXTBOX, [KEY_IntermediateStiffener_spacing]) design_input.append(t2) + t2 = ("Stiffeners", TYPE_COMBOBOX, [KEY_ShearBucklingOption,KEY_IntermediateStiffener_thickness_val,KEY_LongitudnalStiffener_thickness_val]) + design_input.append(t2) + + t2 = ("Additional Girder Data", TYPE_COMBOBOX, [KEY_IS_IT_SYMMETRIC]) + design_input.append(t2) + t6 = ("Design", TYPE_COMBOBOX, [KEY_DP_DESIGN_METHOD]) design_input.append(t6) + t7 = ("Deflection",TYPE_COMBOBOX, [KEY_STR_TYPE,KEY_DESIGN_LOAD,KEY_MEMBER_OPTIONS,KEY_SUPPORTING_OPTIONS]) + design_input.append(t7) + t7 = ("Deflection",TYPE_TEXTBOX, [KEY_MAX_DEFL]) + design_input.append(t7) + return design_input + def input_dictionary_without_design_pref(self): design_input = [] + t2 = (KEY_MATERIAL, [KEY_DP_DESIGN_METHOD], 'Input Dock') design_input.append(t2) - t2 = (None, [KEY_ALLOW_CLASS, KEY_EFFECTIVE_AREA_PARA, KEY_LENGTH_OVERWRITE,KEY_BEARING_LENGTH, KEY_LOAD, KEY_DP_DESIGN_METHOD, KEY_ShearBucklingOption, KEY_IntermediateStiffener_spacing, KEY_IntermediateStiffener], '') + t2 = (None, [KEY_ALLOW_CLASS, KEY_EFFECTIVE_AREA_PARA, KEY_LENGTH_OVERWRITE, KEY_LOAD, KEY_DP_DESIGN_METHOD,KEY_STR_TYPE,KEY_DESIGN_LOAD,KEY_MEMBER_OPTIONS,KEY_MAX_DEFL, + KEY_SUPPORTING_OPTIONS,KEY_ShearBucklingOption, KEY_IntermediateStiffener_spacing, KEY_IntermediateStiffener,KEY_LongitudnalStiffener,KEY_IntermediateStiffener_thickness_val,KEY_LongitudnalStiffener_thickness_val, + KEY_IntermediateStiffener_thickness,KEY_LongitudnalStiffener_thickness, KEY_IS_IT_SYMMETRIC], '') design_input.append(t2) return design_input @@ -264,41 +476,160 @@ def refresh_input_dock(self): add_buttons = [] - t2 = (KEY_DISP_COLSEC, KEY_SECSIZE, TYPE_COMBOBOX, KEY_SECSIZE, None, None, "Columns") - add_buttons.append(t2) - return add_buttons def get_values_for_design_pref(self, key, design_dictionary): - if design_dictionary[KEY_MATERIAL] != 'Select Material': - material = Material(design_dictionary[KEY_MATERIAL], 41) - fu = material.fu - fy = material.fy - else: - fu = '' - fy = '' + # if design_dictionary[KEY_MATERIAL] != 'Select Material': + # material = Material(design_dictionary[KEY_MATERIAL], 41) + # material_grade = design_dictionary[KEY_MATERIAL] + # fu = material.fu + # fy = material.fy + # else: + # fu = '' + # fy = '' + + val = { KEY_ALLOW_CLASS: 'Yes', KEY_EFFECTIVE_AREA_PARA: '1.0', - KEY_LENGTH_OVERWRITE :'NA', - KEY_BEARING_LENGTH : 'NA', - KEY_LOAD : 'Normal', + KEY_LENGTH_OVERWRITE: 'NA', + KEY_LOAD: 'Normal', KEY_DP_DESIGN_METHOD: "Limit State Design", KEY_ShearBucklingOption: KEY_DISP_SB_Option[0], - KEY_IntermediateStiffener:'Yes', - KEY_IntermediateStiffener_spacing:'NA' + KEY_IS_IT_SYMMETRIC: 'Symmetrical', + KEY_IntermediateStiffener_spacing:'NA', + KEY_IntermediateStiffener: 'No', + KEY_IntermediateStiffener_thickness:'All', + KEY_LongitudnalStiffener: 'Yes and 1 stiffener', + KEY_LongitudnalStiffener_thickness:'All', + KEY_STR_TYPE:'Highway Bridge', + KEY_DESIGN_LOAD:'Live Load', + KEY_MEMBER_OPTIONS :'Simple Span', + KEY_SUPPORTING_OPTIONS: 'NA', + KEY_MAX_DEFL : 600, + KEY_IntermediateStiffener_thickness_val : VALUES_STIFFENER_THICKNESS, + KEY_LongitudnalStiffener_thickness_val : VALUES_STIFFENER_THICKNESS }[key] return val + def member_options_change(self): + if self[0] == KEY_DISP_STR_TYP3: + return {KEY_MEMBER_OPTIONS : VALUES_MEMBER_OPTIONS[1]} + elif self[0] == KEY_DISP_STR_TYP4: + return {KEY_MEMBER_OPTIONS :VALUES_MEMBER_OPTIONS[2]} + else: + return {KEY_MEMBER_OPTIONS : VALUES_MEMBER_OPTIONS[0]} + + + def supp_options_change(self): + if self[0] in ['Purlin and Girts', 'Simple span', 'Cantilever span']: + return {KEY_SUPPORTING_OPTIONS : VALUES_SUPPORTING_OPTIONS_PSC} + elif self[0] == 'Rafter Supporting': + return {KEY_SUPPORTING_OPTIONS : VALUES_SUPPORTING_OPTIONS_RS} + elif self[0] == 'Gantry': + return {KEY_SUPPORTING_OPTIONS : VALUES_SUPPORTING_OPTIONS_GNT} + elif self[0] in ['Floor and roof', 'Cantilever']: + return {KEY_SUPPORTING_OPTIONS : VALUES_SUPPORTING_OPTIONS_FRC} + else: + return {KEY_SUPPORTING_OPTIONS : VALUES_SUPPORTING_OPTIONS_DEF} + + def max_defl_change(self): + if self[0] in ['Highway Bridge','Railway Bridge']: + if self[2] == 'Simple Span': + if self[1] == 'Live load': + return {KEY_MAX_DEFL :VALUES_MAX_DEFL[0]} + elif self[1] == 'Dead load': + return {KEY_MAX_DEFL : VALUES_MAX_DEFL[1]} + else: + return {KEY_MAX_DEFL : 'NA'} + + else: + if self[1] == 'Live load': + return {KEY_MAX_DEFL : VALUES_MAX_DEFL[2]} + elif self[1] == 'Dead load': + return {KEY_MAX_DEFL : VALUES_MAX_DEFL[1]} + else: + return {KEY_MAX_DEFL : 'NA'} + + elif self[0] == 'Other Building': + if self[1] == 'Live load': + if self[2] == 'Floor and roof': + if self[3] == 'Elements not susceptible to cracking': + return {KEY_MAX_DEFL : VALUES_MAX_DEFL[3]} + else: + return {KEY_MAX_DEFL : VALUES_MAX_DEFL[4]} + else: + if self[3] == 'Elements not susceptible to cracking': + return {KEY_MAX_DEFL : VALUES_MAX_DEFL[5]} + else: + return {KEY_MAX_DEFL : VALUES_MAX_DEFL[6]} + else: + return {KEY_MAX_DEFL : 'NA'} + else: + if self[2] == 'Purlin and Girts' and self[1] == 'Live load': + if self[3] == 'Elastic cladding': + return {KEY_MAX_DEFL : VALUES_MAX_DEFL[5]} + else: + return {KEY_MAX_DEFL : VALUES_MAX_DEFL[6]} + elif self[2] == 'Simple span' and self[1] == 'Live load': + if self[3] == 'Elastic cladding': + return {KEY_MAX_DEFL : VALUES_MAX_DEFL[7]} + else: + return {KEY_MAX_DEFL : VALUES_MAX_DEFL[3]} + elif self[2] == 'Cantilever span' and self[1] == 'Live load': + if self[3] == 'Elastic cladding': + return {KEY_MAX_DEFL : VALUES_MAX_DEFL[8]} + else: + return {KEY_MAX_DEFL : VALUES_MAX_DEFL[5]} + elif self[2] == 'Rafter Supporting' and self[1] == 'Live load': + if self[3] == 'Profiled Metal sheeting': + return {KEY_MAX_DEFL : VALUES_MAX_DEFL[6]} + else: + return {KEY_MAX_DEFL : VALUES_MAX_DEFL[7]} + elif self[2] == 'Gantry' and self[1] == 'Live load': + if self[1] == 'Crane Load(Manual operation)': + return {KEY_MAX_DEFL : VALUES_MAX_DEFL[9]} + elif self[1] == 'Crane load(Electric operation up to 50t)': + return {KEY_MAX_DEFL : VALUES_MAX_DEFL[10]} + else: + return {KEY_MAX_DEFL : VALUES_MAX_DEFL[11]} + else: + return {KEY_MAX_DEFL : 'NA'} + + def Int_stiffener_thickness_customized(self): + selected_items = [] + if self[0] == 'All': + return {KEY_IntermediateStiffener_thickness_val : VALUES_STIFFENER_THICKNESS} + else: + popup = PopupDialog() + popup.listWidget.addItems(VALUES_STIFFENER_THICKNESS) # Set available items + if popup.exec_() == QDialog.Accepted: + selected_items = popup.get_selected_items() + # print("Selected:", selected_items) + PlateGirderWelded.int_thicklist = selected_items + return {KEY_IntermediateStiffener_thickness_val : selected_items} + + def Long_stiffener_thickness_customized(self): + selected_items2 = [] + if self[0] == 'All': + return {KEY_LongitudnalStiffener_thickness_val : VALUES_STIFFENER_THICKNESS} + else: + popup = PopupDialog() + popup.listWidget.addItems(VALUES_STIFFENER_THICKNESS) # Set available items + if popup.exec_() == QDialog.Accepted: + selected_items2 = popup.get_selected_items() + # print("Selected:", selected_items2) + PlateGirderWelded.long_thicklist = selected_items2 + return {KEY_LongitudnalStiffener_thickness_val : selected_items2} + #################################### # Design Preference Functions End #################################### - # Setting up logger and Input and Output Docks #################################### def module_name(self): - # self.mainmodule = KEY_PLATE_GIRDER_MAIN_MODULE + # print('in module') return KEY_DISP_PLATE_GIRDER_WELDED def set_osdaglogger(key): @@ -329,59 +660,98 @@ def set_osdaglogger(key): def customized_input(self): c_lst = [] - t1 = (KEY_SECSIZE, self.fn_profile_section) - c_lst.append(t1) # 'TEMP2' + # t1 = (KEY_SECSIZE, self.fn_profile_section) + # c_lst.append(t1) + t1 = (KEY_TOP_FLANGE_THICKNESS_PG, self.plate_thick_customized) + c_lst.append(t1) + t2 = (KEY_BOTTOM_FLANGE_THICKNESS_PG, self.plate_thick_customized) + c_lst.append(t2) + + t3= (KEY_WEB_THICKNESS_PG, self.plate_thick_customized) + c_lst.append(t3) + + # t4 = (KEY_LongitudnalStiffener_thickness,self.long_stf_thk_customized) + # c_lst.append(t4) return c_lst - # return [] - def fn_profile_section(self): - profile = self[0] - if profile == 'Beams': #Beam and Column - return connectdb("Beams", call_type="popup") - profile2 = connectdb("Columns", call_type="popup") - if profile == 'Columns': #Beam and Column - return connectdb("Columns", call_type="popup") def input_values(self): - self.module = PlateGirderWelded.module_name(self) + self.module = KEY_DISP_PLATE_GIRDER_WELDED options_list = [] - # t1 = (KEY_MODULE, KEY_DISP_FLEXURE, TYPE_MODULE, None, True, "No Validator") - # options_list.append(t1) + t1 = (None, KEY_DISP_PG_SectionDetail, TYPE_TITLE, None, True, 'No Validator') + options_list.append(t1) + + t1 = (KEY_MODULE, KEY_DISP_PLATE_GIRDER_WELDED, TYPE_MODULE, None, True, "No Validator") + options_list.append(t1) + + t4 = (KEY_MATERIAL, KEY_DISP_MATERIAL, TYPE_COMBOBOX, VALUES_MATERIAL, True, 'No Validator') + options_list.append(t4) + + t2 = (KEY_OVERALL_DEPTH_PG_TYPE, KEY_DISP_OVERALL_DEPTH_PG_TYPE, TYPE_COMBOBOX, VALUES_DEPTH_PG, True, 'No Validator') + options_list.append(t2) + t33 = (KEY_OVERALL_DEPTH_PG, KEY_DISP_OVERALL_DEPTH_PG, TYPE_TEXTBOX, None, True, 'Int Validator') + options_list.append(t33) + + # t33 = (KEY_OVERALL_DEPTH_PG_CST, KEY_DISP_OVERALL_DEPTH_PG, TYPE_COMBOBOX, ['No Inp','Bound Values'], True, 'No Validator') + # options_list.append(t33) + + t4 = (KEY_WEB_THICKNESS_PG, KEY_DISP_WEB_THICKNESS_PG, TYPE_COMBOBOX_CUSTOMIZED, VALUES_PLATETHK, True, + 'Int Validator') + options_list.append(t4) + + # t2 = (KEY_TOP_Bflange_PG_Type, KEY_DISP_TOP_Bflange_PG_Type, TYPE_COMBOBOX, VALUES_DEPTH_PG, True, 'No Validator') + # options_list.append(t2) - t2 = (KEY_SEC_PROFILE, 'Section Profile', TYPE_COMBOBOX, VALUES_SEC_PROFILE3, True, 'No Validator') # 'TEMP1' + t2 = (KEY_TOP_Bflange_PG, KEY_DISP_TOP_Bflange_PG, TYPE_TEXTBOX, None, True, 'Int Validator') options_list.append(t2) - t4 = (KEY_SECSIZE, 'Section Size', TYPE_COMBOBOX_CUSTOMIZED, ['All','Customized'], True, 'No Validator') #'TEMP2' + t4 = (KEY_TOP_FLANGE_THICKNESS_PG, KEY_DISP_TOP_FLANGE_THICKNESS_PG, TYPE_COMBOBOX_CUSTOMIZED, VALUES_PLATETHK, True, 'Int Validator') options_list.append(t4) - t1 = (KEY_MODULE, self.module, TYPE_MODULE, None, True, "No Validator") - options_list.append(t1) + # t2 = (KEY_BOTTOM_Bflange_PG_Type, KEY_DISP_BOTTOM_Bflange_PG_Type, TYPE_COMBOBOX, VALUES_DEPTH_PG, True, 'No Validator') + # options_list.append(t2) + t22 = (KEY_BOTTOM_Bflange_PG, KEY_DISP_BOTTOM_Bflange_PG, TYPE_TEXTBOX, None, True, 'Int Validator') + options_list.append(t22) - t1 = (KEY_SECTION_PROFILE, KEY_SECTION_DATA, TYPE_TITLE, None, True, 'No Validator') - options_list.append(t1) + t4 = (KEY_BOTTOM_FLANGE_THICKNESS_PG, KEY_DISP_BOTTOM_FLANGE_THICKNESS_PG, TYPE_COMBOBOX_CUSTOMIZED, VALUES_PLATETHK, True, + 'No Validator') + options_list.append(t4) - t2 = (KEY_SEC_PROFILE, KEY_DISP_Plate_Girder_PROFILE, TYPE_NOTE, KEY_PLATE_GIRDER_MAIN_MODULE, True, 'No Validator') #'Beam and Column' + t2 = (KEY_LENGTH, KEY_DISP_LENGTH, TYPE_TEXTBOX ,None, True, 'No Validator') options_list.append(t2) - t1 = (KEY_tf, KEY_DISP_tf + '*', TYPE_TEXTBOX, None, True, 'Int Validator') - options_list.append(t1) - t1 = (KEY_tw, KEY_DISP_tw + '*', TYPE_TEXTBOX, None, True, 'Int Validator') - options_list.append(t1) - t1 = (KEY_dw, KEY_DISP_dw + '*', TYPE_TEXTBOX, None, True, 'Int Validator') - options_list.append(t1) - t1 = (KEY_bf, KEY_DISP_bf + '*', TYPE_TEXTBOX, None, True, 'Int Validator') + t1 = (None, KEY_DISP_SECTION_DATA_PG, TYPE_TITLE, None, True, 'No Validator') options_list.append(t1) - t4 = (KEY_MATERIAL, KEY_DISP_MATERIAL, TYPE_COMBOBOX, VALUES_MATERIAL, True, 'No Validator') - options_list.append(t4) - t5 = (KEY_LENGTH, KEY_DISP_LENGTH_BEAM, TYPE_TEXTBOX, None, True, 'Int Validator') + t2 = ( + KEY_DESIGN_TYPE_FLEXURE, + KEY_BEAM_SUPP_TYPE, + TYPE_COMBOBOX, + VALUES_SUPP_TYPE_temp, + True, + "No Validator", + ) + options_list.append(t2) + + #t4 = (KEY_STR_TYPE, KEY_DISP_STR_TYPE, TYPE_COMBOBOX, KEY_DISP_STR_TYPE_list, True, 'No Validator') + #options_list.append(t4) + t5 = (KEY_SUPPORT_WIDTH, KEY_DISP_SUPPORT_WIDTH, TYPE_TEXTBOX, None, True, 'Int Validator') options_list.append(t5) - t7 = (None, DISP_TITLE_FSL, TYPE_TITLE, None, True, 'No Validator') + t4 = (KEY_WEB_PHILOSOPHY, KEY_DISP_WEB_PHILOSOPHY, TYPE_COMBOBOX, WEB_PHILOSOPHY_list, True, 'No Validator') + options_list.append(t4) + + t10 = (KEY_TORSIONAL_RES, DISP_TORSIONAL_RES, TYPE_COMBOBOX, Torsion_Restraint_list, True, 'No Validator') + options_list.append(t10) + + t11 = (KEY_WARPING_RES, DISP_WARPING_RES, TYPE_COMBOBOX, Warping_Restraint_list, True, 'No Validator') + options_list.append(t11) + + t7 = (None, KEY_LOADING, TYPE_TITLE, None, True, 'No Validator') options_list.append(t7) t8 = (KEY_MOMENT, KEY_DISP_MOMENT, TYPE_TEXTBOX, None, True, 'No Validator') @@ -390,769 +760,3195 @@ def input_values(self): t8 = (KEY_SHEAR, KEY_DISP_SHEAR, TYPE_TEXTBOX, None, True, 'No Validator') options_list.append(t8) - - - t8 = (KEY_BUCKLING_STRENGTH, KEY_DISP_BUCKLING_STRENGTH, TYPE_COMBOBOX, ['Yes','No'], True, 'No Validator') + t8= (KEY_BENDING_MOMENT_SHAPE, KEY_DISP_BENDING_MOMENT_SHAPE, TYPE_COMBOBOX, Bending_moment_shape_list, True, + 'No Validator' ) options_list.append(t8) - t8 = (KEY_WEB_CRIPPLING, KEY_DISP_CRIPPLING_STRENGTH, TYPE_COMBOBOX, ['Yes','No'], True, 'No Validator') - options_list.append(t8) + # t15 = (KEY_IMAGE, None, TYPE_IMAGE_BIGGER, VALUES_IMAGE_PLATEGIRDER[0], True,'No Validator') + # options_list.append(t15) return options_list + + + + + def fn_torsion_warping(self): + # print( 'Inside fn_torsion_warping', self) + if self[0] == Torsion_Restraint1: + return Warping_Restraint_list + elif self[0] == Torsion_Restraint2: + return [Warping_Restraint5] + else: + return [Warping_Restraint5] + + def axis_bending_change(self): + design = self[0] + # print( 'Inside fn_supp_image', self) + if self[0] == KEY_DISP_DESIGN_TYPE_FLEXURE: + return ['NA'] + else: + return VALUES_BENDING_TYPE + + def fn_conn_image(self): + + "Function to populate section images based on the type of section " + img = self[0] + if img == Bending_moment_shape_list[0]: + return VALUES_IMAGE_PLATEGIRDER[0] + elif img ==Bending_moment_shape_list[1]: + return VALUES_IMAGE_PLATEGIRDER[1] + elif img ==Bending_moment_shape_list[2]: + return VALUES_IMAGE_PLATEGIRDER[2] + elif img ==Bending_moment_shape_list[3]: + return VALUES_IMAGE_PLATEGIRDER[3] + else: + return VALUES_IMAGE_PLATEGIRDER[4] + + def customized_dimensions(self): + conn = self[0] + if conn == "Customized": + return KEY_DISP_OVERALL_DEPTH_PG + else: + return '' + + def customized_dimensions_1(self): + conn = self[0] + if conn == "Customized": + return KEY_DISP_TOP_Bflange_PG + else: + return '' + + def customized_dimensions_2(self): + conn = self[0] + if conn == "Customized": + return KEY_DISP_BOTTOM_Bflange_PG + else: + return '' + + def customized_dims(self): + conn = self[0] + if conn == "Customized": + return True + else: + return False + def customized_options(self): + conn = self[0] + if conn == "Customized": + return VALUES_PLATETHK + else: + return VALUES_OPT + + def customized_dimensions_cst(self): + conn = self[0] + if conn == "Optimized": + return KEY_OVERALL_DEPTH_PG_CST + else: + return '' + + def customized_dims_cst(self): + conn = self[0] + if conn == "Optimized": + return True + else: + return False + + def pop_up_bounds(self): + if self[0] == "Bound Values": + dialog = RangeInputDialog() + if dialog.exec_() == QDialog.Accepted: + # print("Returned values:", dialog.get_values()) + return str(dialog.get_values()) + + def input_value_changed(self): lst = [] + # t1 = ([KEY_BENDING_MOMENT_SHAPE], KEY_IMAGE, TYPE_IMAGE, self.fn_conn_image) + # lst.append(t1) + + t3 = ([KEY_TORSIONAL_RES], KEY_WARPING_RES, TYPE_COMBOBOX, self.fn_torsion_warping) + lst.append(t3) - t1 = ([KEY_SEC_PROFILE], KEY_SECSIZE, TYPE_COMBOBOX_CUSTOMIZED, self.fn_profile_section) - lst.append(t1) + t44 = ([KEY_OVERALL_DEPTH_PG_TYPE],KEY_OVERALL_DEPTH_PG, TYPE_LABEL, self.customized_dimensions) + lst.append(t44) + t45 = ([KEY_OVERALL_DEPTH_PG_TYPE], KEY_OVERALL_DEPTH_PG, TYPE_TEXTBOX, self.customized_dims) + lst.append(t45) + # t46 = ([KEY_OVERALL_DEPTH_PG_TYPE], KEY_WEB_THICKNESS_PG, TYPE_COMBOBOX, self.customized_options) + # lst.append(t46) + + # t45 = ([KEY_OVERALL_DEPTH_PG_TYPE], KEY_OVERALL_DEPTH_PG_CST, TYPE_LABEL, self.customized_dimensions_cst) + # lst.append(t45) + + # t45 = ([KEY_OVERALL_DEPTH_PG_TYPE], KEY_OVERALL_DEPTH_PG_CST, TYPE_COM, self.customized_dims_cst) + # lst.append(t45) + + + # t45 = ([KEY_OVERALL_DEPTH_PG_CST], KEY_OVERALL_DEPTH_PG_CST, TYPE_COMBOBOX, self.pop_up_bounds) + lst.append(t45) + + + t2 = ([KEY_OVERALL_DEPTH_PG_TYPE], KEY_TOP_Bflange_PG, TYPE_LABEL, self.customized_dimensions_1) + lst.append(t2) + t3 = ([KEY_OVERALL_DEPTH_PG_TYPE], KEY_TOP_Bflange_PG, TYPE_TEXTBOX, self.customized_dims) + lst.append(t3) + # t47 = ([KEY_OVERALL_DEPTH_PG_TYPE], KEY_TOP_FLANGE_THICKNESS_PG, TYPE_COMBOBOX, self.customized_options) + # lst.append(t47) + + t23 = ([KEY_OVERALL_DEPTH_PG_TYPE], KEY_BOTTOM_Bflange_PG, TYPE_LABEL, self.customized_dimensions_2) + lst.append(t23) + t24 = ([KEY_OVERALL_DEPTH_PG_TYPE], KEY_BOTTOM_Bflange_PG, TYPE_TEXTBOX, self.customized_dims) + lst.append(t24) + # t47 = ([KEY_OVERALL_DEPTH_PG_TYPE], KEY_BOTTOM_FLANGE_THICKNESS_PG, TYPE_COMBOBOX, self.customized_options) + # lst.append(t47) t3 = ([KEY_MATERIAL], KEY_MATERIAL, TYPE_CUSTOM_MATERIAL, self.new_material) lst.append(t3) + + t18 = ([KEY_DESIGN_TYPE_FLEXURE], + KEY_T_constatnt, TYPE_OUT_LABEL, self.output_modifier) + lst.append(t18) + + t18 = ([KEY_DESIGN_TYPE_FLEXURE], + KEY_T_constatnt, TYPE_OUT_DOCK, self.output_modifier) + lst.append(t18) + + t18 = ([KEY_DESIGN_TYPE_FLEXURE], + KEY_W_constatnt, TYPE_OUT_LABEL, self.output_modifier) + lst.append(t18) + + t18 = ([KEY_DESIGN_TYPE_FLEXURE], + KEY_W_constatnt, TYPE_OUT_DOCK, self.output_modifier) + lst.append(t18) + + # t18 = ([KEY_DESIGN_TYPE_FLEXURE], + # KEY_IMPERFECTION_FACTOR_LTB, TYPE_OUT_LABEL, self.output_modifier) + # lst.append(t18) + + # t18 = ([KEY_DESIGN_TYPE_FLEXURE], + # KEY_IMPERFECTION_FACTOR_LTB, TYPE_OUT_DOCK, self.output_modifier) + # lst.append(t18) + + # t18 = ([KEY_DESIGN_TYPE_FLEXURE], + # KEY_SR_FACTOR_LTB, TYPE_OUT_LABEL, self.output_modifier) + # lst.append(t18) + + # t18 = ([KEY_DESIGN_TYPE_FLEXURE], + # KEY_SR_FACTOR_LTB, TYPE_OUT_DOCK, self.output_modifier) + # lst.append(t18) + + # t18 = ([KEY_DESIGN_TYPE_FLEXURE], + # KEY_NON_DIM_ESR_LTB, TYPE_OUT_LABEL, self.output_modifier) + # lst.append(t18) + + # t18 = ([KEY_DESIGN_TYPE_FLEXURE], + # KEY_NON_DIM_ESR_LTB, TYPE_OUT_DOCK, self.output_modifier) + # lst.append(t18) + + # t18 = ([KEY_DESIGN_TYPE_FLEXURE], + # KEY_DESIGN_STRENGTH_COMPRESSION, TYPE_OUT_LABEL, self.output_modifier) + # lst.append(t18) + + # t18 = ([KEY_DESIGN_TYPE_FLEXURE], + # KEY_DESIGN_STRENGTH_COMPRESSION, TYPE_OUT_DOCK, self.output_modifier) + # lst.append(t18) + + t18 = ([KEY_DESIGN_TYPE_FLEXURE], + KEY_Elastic_CM, TYPE_OUT_LABEL, self.output_modifier) + lst.append(t18) + + t18 = ([KEY_DESIGN_TYPE_FLEXURE], + KEY_Elastic_CM, TYPE_OUT_DOCK, self.output_modifier) + lst.append(t18) + + t19 = ([KEY_WEB_PHILOSOPHY],KEY_IntermediateStiffener_thickness,TYPE_OUT_LABEL,self.output_modifier2) + lst.append(t19) + + t20 = ([KEY_WEB_PHILOSOPHY],KEY_IntermediateStiffener_thickness,TYPE_OUT_DOCK,self.output_modifier2) + lst.append(t20) + + t21 = ([KEY_WEB_PHILOSOPHY],KEY_LongitudnalStiffener_thickness,TYPE_OUT_LABEL,self.output_modifier2) + lst.append(t21) + + t22 = ([KEY_WEB_PHILOSOPHY],KEY_LongitudnalStiffener_thickness,TYPE_OUT_DOCK,self.output_modifier2) + lst.append(t22) + + t23 = ([KEY_WEB_PHILOSOPHY],KEY_IntermediateStiffener_spacing,TYPE_OUT_LABEL,self.output_modifier2) + lst.append(t23) + + t24 = ([KEY_WEB_PHILOSOPHY],KEY_IntermediateStiffener_spacing,TYPE_OUT_DOCK,self.output_modifier2) + lst.append(t24) + + t25 = ([KEY_WEB_PHILOSOPHY],KEY_LongitudnalStiffener_numbers,TYPE_OUT_LABEL,self.output_modifier2) + lst.append(t25) + + t26 = ([KEY_WEB_PHILOSOPHY],KEY_LongitudnalStiffener_numbers,TYPE_OUT_DOCK,self.output_modifier2) + lst.append(t26) + + t27 = ([KEY_WEB_PHILOSOPHY],KEY_LongitudinalStiffener1_pos,TYPE_OUT_LABEL,self.output_modifier2) + lst.append(t27) + + t27 = ([KEY_WEB_PHILOSOPHY],KEY_LongitudinalStiffener1_pos,TYPE_OUT_DOCK,self.output_modifier2) + lst.append(t27) + + t27 = ([KEY_WEB_PHILOSOPHY],KEY_LongitudinalStiffener2_pos,TYPE_OUT_LABEL,self.output_modifier2) + lst.append(t27) + + t27 = ([KEY_WEB_PHILOSOPHY],KEY_LongitudinalStiffener2_pos,TYPE_OUT_DOCK,self.output_modifier2) + lst.append(t27) + + return lst + def warning_majorbending(self): + # print(self) + if self[0] == VALUES_SUPP_TYPE_temp[2]: + return True + # elif self[0] == VALUES_SUPP_TYPE_temp[0] or self[0] == VALUES_SUPP_TYPE_temp[1] : + # return True + else: + return False + + def output_modifier(self): + # print(self) + if self[0] == VALUES_SUPP_TYPE_temp[2]: + return False + # elif self[0] == VALUES_SUPP_TYPE_temp[0] or self[0] == VALUES_SUPP_TYPE_temp[1] : + # return True + else: + return True + + def output_modifier_long_stiffener(self): + if self[0] == 'Thin we': + return False + else: + return True + + def output_modifier2(self): + # print(self) + if self[0] == 'Thin Web with ITS': + return False + # elif self[0] == VALUES_SUPP_TYPE_temp[0] or self[0] == VALUES_SUPP_TYPE_temp[1] : + # return True + else: + return True + + # def Design_pref_modifier(self): + # print("Design_pref_modifier",self) + + def output_values(self, flag): out_list = [] - t1 = (None, DISP_TITLE_STRUT_SECTION, TYPE_TITLE, None, True) + t0 = (None, DISP_TITLE_STRUT_SECTION, TYPE_TITLE, None, True) + out_list.append(t0) + + t1 = (KEY_TITLE_OPTIMUM_DESIGNATION, KEY_DISP_TITLE_OPTIMUM_DESIGNATION, TYPE_TEXTBOX, + self.result_designation if flag else '', True) out_list.append(t1) - t2 = (KEY_betab_constatnt, KEY_DISP_betab_constatnt, TYPE_TEXTBOX, - 'NA', True) - out_list.append(t2) - t2 = (KEY_SEC_PROFILE, KEY_DISP_Plate_Girder_PROFILE, TYPE_NOTE, KEY_PLATE_GIRDER_MAIN_MODULE, True) #'Beam and Column' + t2 = ( + KEY_OPTIMUM_UR_COMPRESSION, KEY_DISP_OPTIMUM_UR_COMPRESSION, TYPE_TEXTBOX, round(self.result_UR,3) if flag else '', True) out_list.append(t2) - t1 = (KEY_tf, KEY_DISP_tf, TYPE_TEXTBOX, self.result_tf if flag else '', True) # "NA" + t3 = (KEY_OPTIMUM_SC, KEY_DISP_OPTIMUM_SC, TYPE_TEXTBOX, self.section_classification_val if flag else '', True) + out_list.append(t3) + + t4 = (KEY_betab_constatnt,KEY_DISP_betab_constatnt, TYPE_TEXTBOX, + self.betab if flag else '', True) + out_list.append(t4) + + t5 = ( + KEY_EFF_SEC_AREA, KEY_DISP_EFF_SEC_AREA, TYPE_TEXTBOX, self.effectivearea if flag else '', + True) + out_list.append(t5) + + # t6 = (None,"Design Results" , TYPE_TITLE, None, True) + # out_list.append(t6) + + + + + + # t9 = (None, KEY_DISP_DESIGN_STIFFER , TYPE_TITLE, None, True) + # out_list.append(t9) + + t10 = (KEY_IntermediateStiffener_thickness, KEY_DISP_IntermediateStiffener_thickness, TYPE_TEXTBOX, + self.intstiffener_thk if flag else '', True) + out_list.append(t10) + + t10 = (KEY_IntermediateStiffener_spacing, KEY_DISP_IntermediateStiffener_spacing, TYPE_TEXTBOX, + self.intstiffener_spacing if flag else '', True) + out_list.append(t10) + + t1 = (KEY_LongitudnalStiffener_thickness, KEY_DISP_LongitudnalStiffener_thickness, TYPE_TEXTBOX, + self.longstiffener_thk if flag else '', True) out_list.append(t1) - t1 = (KEY_tw, KEY_DISP_tw, TYPE_TEXTBOX, self.result_tw if flag else '', True) # "NA" + + t1 = (KEY_LongitudnalStiffener_numbers, KEY_DISP_LongitudnalStiffener_numbers, TYPE_TEXTBOX, self.longstiffener_no if flag else '', True) out_list.append(t1) - t1 = (KEY_dw, KEY_DISP_dw, TYPE_TEXTBOX, self.result_dw if flag else '', True) # "NA" + + t2 = (KEY_EndpanelStiffener_thickness, KEY_DISP_EndpanelStiffener_thickness, TYPE_TEXTBOX, self.end_panel_stiffener_thickness if flag else '', True) + out_list.append(t2) + + t1 = (KEY_MOMENT_STRENGTH, KEY_DISP_MOMENT, TYPE_TEXTBOX, + self.design_moment if flag else '', True) out_list.append(t1) - t1 = (KEY_bf, KEY_DISP_bf, TYPE_TEXTBOX, self.result_bf if flag else '', True) # "NA" + + # t1 = (None, KEY_DISP_WELD_DESIGN, TYPE_TITLE, None, True) + # out_list.append(t1) + + t1 = (KEY_WeldWebtoflange, KEY_DISP_WeldWebtoflange, TYPE_TEXTBOX, + max(self.atop, self.abot) if flag else '', True) out_list.append(t1) - t1 = (KEY_SHEAR_STRENGTH, KEY_DISP_DESIGN_STRENGTH_SHEAR, TYPE_TEXTBOX, - self.result_shear if flag else - '', True) + t1 = (KEY_WeldStiffenertoweb, KEY_DISP_WeldStiffenertoweb, TYPE_TEXTBOX, + self.weld_stiff if flag else '', True) out_list.append(t1) + + # t1 = (None, KEY_DISP_LTB, TYPE_TITLE, None, False) + # out_list.append(t1) + + t2 = (KEY_T_constatnt, KEY_DISP_T_constatnt, TYPE_TEXTBOX, + self.torsion_cnst if flag else '', False) + out_list.append(t2) + + t2 = (KEY_W_constatnt, KEY_DISP_W_constatnt, TYPE_TEXTBOX, self.warping_cnst if flag else '', False) + out_list.append(t2) + + t2 = (KEY_LongitudinalStiffener1_pos, KEY_DISP_LongitudinalStiffener1_pos, TYPE_TEXTBOX, self.x1 if flag else '',True) + out_list.append(t2) + + t2 = (KEY_LongitudinalStiffener2_pos, KEY_DISP_LongitudinalStiffener2_pos, TYPE_TEXTBOX, self.x2 if flag else '',True) + out_list.append(t2) + + # t2 = (KEY_SR_FACTOR_LTB, KEY_DISP_SR_FACTOR, TYPE_TEXTBOX, '', False) + # out_list.append(t2) + + # t2 = (KEY_NON_DIM_ESR_LTB, KEY_DISP_NON_DIM_ESR, TYPE_TEXTBOX, '', False) + # out_list.append(t2) + + # t1 = (KEY_DESIGN_STRENGTH_COMPRESSION, KEY_DISP_COMP_STRESS, TYPE_TEXTBOX, + # '', False) + # out_list.append(t1) + + t2 = (KEY_Elastic_CM, KEY_DISP_Elastic_CM, TYPE_TEXTBOX, self.critical_moment if flag else '', False) + out_list.append(t2) + + # TODO @Rutvik: can add tab button for asthetics + + # t2 = (KEY_T_constatnt, KEY_DISP_T_constatnt, TYPE_TEXTBOX, + # self.result_tc if flag else '', False) + # out_list.append(t2) + + # t2 = (KEY_W_constatnt, KEY_DISP_W_constatnt, TYPE_TEXTBOX, self.result_wc if flag else '', False) + # out_list.append(t2) + + # t2 = ( + # KEY_IMPERFECTION_FACTOR_LTB, KEY_DISP_IMPERFECTION_FACTOR, TYPE_TEXTBOX, self.result_IF_lt if flag else '', + # False) + # out_list.append(t2) + + # t2 = (KEY_SR_FACTOR_LTB, KEY_DISP_SR_FACTOR, TYPE_TEXTBOX, self.result_srf_lt if flag else '', False) + # out_list.append(t2) + + # t2 = (KEY_NON_DIM_ESR_LTB, KEY_DISP_NON_DIM_ESR, TYPE_TEXTBOX, self.result_nd_esr_lt if flag else '', False) + # out_list.append(t2) + + # t1 = (KEY_DESIGN_STRENGTH_COMPRESSION, KEY_DISP_COMP_STRESS, TYPE_TEXTBOX, + # self.result_fcd__lt if flag else + # '', False) + # out_list.append(t1) + + # t2 = (KEY_Elastic_CM, KEY_DISP_Elastic_CM, TYPE_TEXTBOX, self.result_mcr if flag else '', False) + # out_list.append(t2) + + # t1 = (None, KEY_PERFORMANCE_EVALUATION, TYPE_TITLE, None, True) + # out_list.append(t1) # - t1 = (KEY_MOMENT_STRENGTH, KEY_DISP_DESIGN_STRENGTH_MOMENT, TYPE_TEXTBOX, - self.result_bending if flag else - '', True) - out_list.append(t1) + # t2 = (KEY_ESR, KEY_DISP_UTILIZATION_RATION_PG , TYPE_TEXTBOX, self.result_eff_sr if flag else '', True) + # out_list.append(t2) + # + # t2 = (KEY_EULER_BUCKLING_STRESS, KEY_DISP_PERMISSIBLE_PG, TYPE_TEXTBOX, + # self.result_ebs if flag else '', True) + # out_list.append(t2) + # + # t2 = (KEY_BUCKLING_CURVE, KEY_DISP_DEFLECTION_PG, TYPE_TEXTBOX, self.result_bc if flag else '', True) + # out_list.append(t2) return out_list + def spacing(self, status): + + spacing = [] + + t2 = (KEY_T_constatnt, KEY_DISP_T_constatnt, TYPE_TEXTBOX, + self.result_tc if status else '', False) + spacing.append(t2) + + t2 = (KEY_W_constatnt, KEY_DISP_W_constatnt, TYPE_TEXTBOX, self.result_wc if status else '', False) + spacing.append(t2) + + t2 = ( + KEY_IMPERFECTION_FACTOR_LTB, KEY_DISP_IMPERFECTION_FACTOR, TYPE_TEXTBOX, self.result_IF_lt if status else '', + False) + spacing.append(t2) + + t2 = (KEY_SR_FACTOR_LTB, KEY_DISP_SR_FACTOR, TYPE_TEXTBOX, self.result_srf_lt if status else '', False) + spacing.append(t2) + + t2 = (KEY_NON_DIM_ESR_LTB, KEY_DISP_NON_DIM_ESR, TYPE_TEXTBOX, self.result_nd_esr_lt if status else '', False) + spacing.append(t2) + + t1 = (KEY_DESIGN_STRENGTH_COMPRESSION, KEY_DISP_COMP_STRESS, TYPE_TEXTBOX, + self.result_fcd__lt if status else + '', False) + spacing.append(t1) + + t2 = (KEY_Elastic_CM, KEY_DISP_Elastic_CM, TYPE_TEXTBOX, self.result_mcr if status else '', False) + spacing.append(t2) + + return spacing def func_for_validation(self, design_dictionary): - print(f"func_for_validation here") + # print("DESIGN",design_dictionary) + # print(f"func_for_validation here") all_errors = [] self.design_status = False flag = False + self.output_values(self, flag) flag1 = False flag2 = False flag3 = False - flag4 = False option_list = self.input_values(self) missing_fields_list = [] - print(f'func_for_validation option_list {option_list}' - f"\n design_dictionary {design_dictionary}") + # print(f'func_for_validation option_list {option_list}' + # f"\n design_dictionary {design_dictionary}" + # ) for option in option_list: - # print(option_list) - if option[2] == TYPE_TEXTBOX and option[0] == KEY_LENGTH or option[0] == KEY_SHEAR or option[0] == KEY_MOMENT: - if design_dictionary[option[0]] == '': - missing_fields_list.append(option[1]) - continue - if option[0] == KEY_LENGTH: - if float(design_dictionary[option[0]]) <= 0.0: - print("Input value(s) cannot be equal or less than zero.") - error = "Input value(s) cannot be equal or less than zero." - all_errors.append(error) - else: - flag1 = True - elif option[0] == KEY_SHEAR: - if float(design_dictionary[option[0]]) < 0.0: - print("Input value(s) cannot be less than zero.") - error = "Input value(s) cannot be less than zero." + if option[2] == TYPE_TEXTBOX or option[0] == KEY_LENGTH or option[0] == KEY_SHEAR or option[0] == KEY_MOMENT: + try: + if design_dictionary[option[0]] == '': + if design_dictionary['Total.Design_Type'] == 'Optimized': + if design_dictionary[KEY_OVERALL_DEPTH_PG] == '' or design_dictionary[KEY_TOP_Bflange_PG] == '' or design_dictionary[KEY_BOTTOM_Bflange_PG] == '': + pass + else: + missing_fields_list.append(option[1]) + continue + + else: + missing_fields_list.append(option[1]) + continue + if option[0] == KEY_LENGTH: + if float(design_dictionary[option[0]]) <= 0.0: + # print("Input value(s) cannot be equal or less than zero.") + error = "Input value(s) cannot be equal or less than zero." + all_errors.append(error) + + else: + flag1 = True + elif option[0] == KEY_SHEAR: + if float(design_dictionary[option[0]]) <= 0.0: + # print("Input value(s) cannot be equal or less than zero.") + error = "Input value(s) cannot be equal or less than zero." + all_errors.append(error) + else: + flag2 = True + elif option[0] == KEY_MOMENT: + if float(design_dictionary[option[0]]) <= 0.0: + # print("Input value(s) cannot be equal or less than zero.") + error = "Input value(s) cannot be equal or less than zero." + all_errors.append(error) + else: + flag3 = True + except: + error = "Input value(s) are not valid" all_errors.append(error) - else: - flag2 = True - elif option[0] == KEY_MOMENT: - if float(design_dictionary[option[0]]) < 0.0: - print("Input value(s) cannot be less than zero.") - error = "Input value(s) cannot be less than zero." - all_errors.append(error) - else: - flag3 = True - if option[0] == KEY_tf : - if design_dictionary[KEY_tf] != "" and design_dictionary[KEY_tw] != "" and design_dictionary[KEY_dw] != "" and design_dictionary[KEY_bf] != "": - flag4 = True - # TODO elif design_dictionary[KEY_tf] == "" and design_dictionary[KEY_tw] == "" and design_dictionary[KEY_dw] == "" and design_dictionary[KEY_bf] == "": - # flag4 = True - else: - list_adder = lambda x,y: missing_fields_list.append(x) if design_dictionary[y] == "" else False - for i in [(KEY_tf,KEY_DISP_tf),(KEY_tw,KEY_DISP_tw),(KEY_dw,KEY_DISP_dw),(KEY_bf,KEY_DISP_bf)]: - list_adder(i[1],i[0]) - if len(missing_fields_list) > 0: error = self.generate_missing_fields_error_string(self, missing_fields_list) all_errors.append(error) else: flag = True - - if flag and flag1 and flag2 and flag3 and flag4: - print(f"\n design_dictionary{design_dictionary}") - self.set_input_values(self, design_dictionary) # - self.results(self, design_dictionary) # + # print(f"flag {flag} flag1 {flag1} flag2 {flag2} flag3 {flag3}") + if flag and flag1 and flag2 and flag3: + # print(f"\n design_dictionary{design_dictionary}") + self.set_input_values(self, design_dictionary) + # print("WORKING VALIDATION") + # if self.design_status ==False and len(self.failed_design_dict)>0: + # logger.error( + # "Design Failed, Check Design Report" + # ) + # return # ['Design Failed, Check Design Report'] @TODO + # elif self.design_status: + # pass + # else: + # logger.error( + # "Design Failed. Selender Sections Selected" + # ) + # return # ['Design Failed. Selender Sections Selected'] else: return all_errors - def isfloat(input_list): - for i in range(len(input_list)): - try: - print(input_list[i]) - yield isinstance(float(input_list[i]),float) - except: - yield False + + def get_3d_components(self): + + components = [] + t3 = ('Model', self.call_3DModel) + components.append(t3) + + # t3 = ('Column', self.call_3DColumn) + # components.append(t3) + + return components + + # warn if a beam of older version of IS 808 is selected + def warn_text(self): + """ give logger warning when a beam from the older version of IS 808 is selected """ + global logger + red_list = red_list_function() + + if (self.sec_profile == VALUES_SEC_PROFILE[0]) or (self.sec_profile == VALUES_SEC_PROFILE[1]): # Beams or Columns + for section in self.sec_list: + if section in red_list: + logger.warning(" : You are using a section ({}) (in red color) that is not available in latest version of IS 808".format(section)) + # Setting inputs from the input dock GUI def set_input_values(self, design_dictionary): - # out_list = [] - ### INPUT FROM INPUT DOCK #### - self.length = float(design_dictionary[KEY_LENGTH])*10**3 #m -> mm - self.material = design_dictionary[KEY_MATERIAL] - self.load = Load(0,design_dictionary[KEY_SHEAR],design_dictionary[KEY_MOMENT],unit_kNm=True) #KN -> N - print() - self.sec_profile = design_dictionary[KEY_SEC_PROFILE] - - # Safety Factors + + self.module = design_dictionary[KEY_MODULE] + self.mainmodule = 'PLATE GIRDER' + self.design_type = design_dictionary[KEY_OVERALL_DEPTH_PG_TYPE] + # print('design_type', design_dictionary[KEY_OVERALL_DEPTH_PG_TYPE]) + self.section_class = None + if self.design_type == 'Optimized': + # print('Optimized Design') + self.total_depth = 1 + self.web_thickness_list = design_dictionary[KEY_WEB_THICKNESS_PG] + self.top_flange_width = 1 + self.top_flange_thickness_list = design_dictionary[KEY_TOP_FLANGE_THICKNESS_PG] + self.bottom_flange_width = 1 + self.bottom_flange_thickness_list = design_dictionary[KEY_BOTTOM_FLANGE_THICKNESS_PG] + #optimize the initialization for list outputs + self.web_thickness = float(design_dictionary[KEY_WEB_THICKNESS_PG][0]) + self.top_flange_thickness = float(design_dictionary[KEY_TOP_FLANGE_THICKNESS_PG][0]) + self.bottom_flange_thickness = float(design_dictionary[KEY_BOTTOM_FLANGE_THICKNESS_PG][0]) + + else: + # print('Cus Design') + self.total_depth = float(design_dictionary[KEY_OVERALL_DEPTH_PG]) + self.web_thickness_list = design_dictionary[KEY_WEB_THICKNESS_PG] + self.web_thickness = float(design_dictionary[KEY_WEB_THICKNESS_PG][0]) + self.top_flange_width = float(design_dictionary[KEY_TOP_Bflange_PG]) + self.top_flange_thickness = float(design_dictionary[KEY_TOP_FLANGE_THICKNESS_PG][0]) + self.top_flange_thickness_list = design_dictionary[KEY_TOP_FLANGE_THICKNESS_PG] + self.bottom_flange_width = float(design_dictionary[KEY_BOTTOM_Bflange_PG]) + self.bottom_flange_thickness = float(design_dictionary[KEY_BOTTOM_FLANGE_THICKNESS_PG][0]) + self.bottom_flange_thickness_list = design_dictionary[KEY_BOTTOM_FLANGE_THICKNESS_PG] + + #3 list loops for V inp or self.single_section_dictionary['Check1'] == None - self.single_section_dictionary['Check1'] = self.checks(self,1) - # 5.2 servicibility_check Only for Intermediate Transverse stiffener - self.single_section_dictionary['Check2'] = self.checks(self,2) - # 5.3 compression_flange_buckling - self.single_section_dictionary['Check3'] = self.checks(self,3) - - # 6 Section Classification - _ = self.section_classification(self) - self.single_section_dictionary.update(_) - - # Calculation Variable - self.effective_depth = self.section_property.depth_web - - # 6 Shear Strength - # 6.1 Shear Strength without any Stiffeners - self.Shear_Strength(self) - self.single_section_dictionary['Shear_Strength'] = self.V_d - self.single_section_dictionary['V_d'] = self.V_d - print(self.V_d,self.load.shear_force) - - # 6.2 Shear Strength with end Stiffeners only - if self.single_section_dictionary['Shear_Strength'] < self.load.shear_force/1000: - if self.EndStiffener and self.support_cndition_shear_buckling == KEY_DISP_SB_Option[0] :#or self.support_cndition_shear_buckling == KEY_DISP_SB_Option[1]) - # Variables needed for to work - Flexure.set_osdaglogger(None) - Flexure.web_buckling_steps(self) - _ = (('Kv',self.K_v), - ('tau_crc',self.tau_crc), - ('lambda_w', self.lambda_w), - ('tau_b', self.tau_b), - ("V_cr",self.V_cr)) - self.single_section_dictionary.update(_) - - self.single_section_dictionary['Shear_Strength'] = self.single_section_dictionary["V_cr"] - elif self.EndStiffener and self.support_cndition_shear_buckling == KEY_DISP_SB_Option[1]: - self.V_p = IS800_2007.cl_8_4_design_shear_strength( - self.section_property.shear_area, - self.material_property.fy - ) / 10 ** 3 * self.gamma_m0 - self.Mfr = IS800_2007.cl_8_4_2_2_Mfr_TensionField(self.section_property.flange_width, - self.section_property.flange_thickness, self.fyf, - self.load.moment / ( - self.section_property.depth - self.section_property.flange_thickness), - self.gamma_m0) - - if self.Mfr > 0: - print('Starting loop', int(round(self.effective_length*10**4/self.effective_depth,-1)/10)) - # for c_d in range(3,self.effective_length/self.result_eff_d): - for c_d in reversed(list(range(3,int(round(self.effective_length * 1000/self.effective_depth,-1))))): - print('c_d',c_d,'c/d',self.effective_length * 1000/self.effective_depth) - c_d = c_d/10 + 0.1 - self.c = round(c_d * self.effective_depth, -1) - print('c',self.c) - self.K_v = IS800_2007.cl_8_4_2_2_K_v_Simple_postcritical('many support', self.c, self.effective_depth) - self.plate_girder_strength2(self) - - self.shear_strength = self.V_tf_girder / self.gamma_m0 * 10**-3 - logger.info('Intermediate Stiffeners required d ={}, c = {}, Section = {}, V_tf = {}, V_d = {}'.format(self.effective_depth,self.c, - self.section_property.designation,self.V_tf_girder,self.shear_strength)) - if self.shear_strength > self.load.shear_force * 10**-3: - return - - print(self.single_section_dictionary) - - def Girder_SectionProperty(self,design_dictionary,var): - print(Custom_Girder) - print(f'temp_section_list = {self.temp_section_list}') - - print(f'section_list = {self.section_list}') - # if isinstance(float(design_dictionary[KEY_tf]),float) and - - self.section_property = Custom_Girder(design_dictionary, var) - # print(self.section_property.flange_thickness, - # self.section_property.depth_web, - # self.section_property.depth_section, - # self.section_property.flange_width, - # self.section_property.web_thickness, - # self.section_property.flange_slope, - # self.section_property.root_radius, - # self.section_property.toe_radius, - # self.section_property.mass, - # self.section_property.area, # mm - # self.section_property.mom_inertia_z, - # self.section_property.mom_inertia_y, - # self.section_property.rad_of_gy_z, - # self.section_property.rad_of_gy_y, - # self.section_property.elast_sec_mod_z, - # self.section_property.elast_sec_mod_y, - # self.section_property.plast_sec_mod_z, - # self.section_property.plast_sec_mod_y) - - def optimization_tab_check(self): - print() - # self.latex_tension_zone = False - if (self.effective_area_factor <= 0.10) or (self.effective_area_factor > 1.0): - logger.error( - "The defined value of Effective Area Factor in the design preferences tab is out of the suggested range." - ) - # logger.info("Provide an appropriate input and re-design.") - logger.warning("Assuming a default value of 1.0.") - self.effective_area_factor = 1.0 - # self.design_status = False - # self.design_status_list.append(self.design_status) - self.optimization_tab_check(self) - logger.info("Provided appropriate design preference, now checking input.") - - def section_design(self,count, k= 150): - self.section_class_girder = "" - - # 180, d/tw or take span/20 and go on increasing - while self.section_class_girder != self.section_class_req and count <25: - self.section_property.depth_web = int(round((self.load.moment * k / (self.material_property.fy)) ** 0.33, -1)) + count * 5 - self.section_property.web_thickness = int(min(round((self.load.moment / (self.material_property.fy * k**2)) ** 0.33,-1)),self.section_property.depth_web/k) + count * 5 - if self.IntermediateStiffener =="Yes": - self.optimum_depth_thickness_web(self,self.checks,[1]) + is_thick_web = False + + if design_dictionary[KEY_IS_IT_SYMMETRIC] == 'Symmetric Girder': + is_symmetric = True else: - self.optimum_depth_thickness_web(self,self.checks,[1,2,3]) - - self.section_property.flange_width = self.myround(0.3 * self.section_property.depth_web - count,5 ,'low') - i = 0 - while self.section_class_girder != self.section_class_req and self.section_property.flange_thickness<60: - self.optimum_depth_thickness_flange(self,i) - i+=1 - self.section_classification(self) - # count = count+1 - # k = k + 5 - print(count,'depth & web_thickness',self.section_property.depth_web, self.section_property.web_thickness,self.section_property.flange_width,self.section_property.flange_thickness, "self.section_class_girder",self.section_class_girder) - self.designed_dict = { KEY_tf : self.section_property.flange_thickness , - KEY_dw: self.section_property.depth_web , - KEY_bf: self.section_property.flange_width , - KEY_tw: self.section_property.web_thickness ,} - - def section_design_web(self,count, k= 150): - # TODO - self.section_property.web_thickness = ic(int(min(round((self.load.moment / (self.material_property.fy * k**2)) ** 0.33,-1)),self.section_property.depth_web/k)) + count * 5 - def optimum_depth_thickness_web(self,func,var_list): - print('depth & web_thickness0',self.section_property.depth_web, self.section_property.web_thickness) - while True: - check = [] - for j in var_list: - check.append(func(self,j)) - # check3 = self.checks(self,type=3) - # print('depth & web_thickness before',self.section_property.depth_web, self.section_property.web_thickness,'check',all(check)) - if self.section_property.depth_web % 5 != 0 or self.section_property.web_thickness % 5 !=0: - self.section_property.depth_web=self.myround(self.section_property.depth_web,5,'low') - self.section_property.web_thickness = self.myround(self.section_property.web_thickness,5,'high') - print('depth & web_thickness after',self.section_property.depth_web, self.section_property.web_thickness) - - if all(check): - print('depth & web_thickness1',self.section_property.depth_web, self.section_property.web_thickness) - # self.section_classification(self) - # print("self.section_class_girder",self.section_class_girder) - break - else : - print('depth & web_thickness2',self.section_property.depth_web, self.section_property.web_thickness) - if i%2==1: - self.section_property.depth_web -= 10 + is_symmetric = False + self.optimized_method(self,design_dictionary,is_thick_web,is_symmetric) + + # pass + else: + self.design_check(self,design_dictionary) + # if self.flag: + # self.results(self, design_dictionary) + + + # else: + # pass + # # logger.warning( + # # "Plastic section modulus of selected sections is less than required." + # # ) + # return + + # Simulation starts here + def section_classification(self,design_dictionary): + self.design_status = False + + #print("THICKNESS VALUES INT STIFFNER", self.int_thickness_list) + #print("THICKNESS VALUE LONG STIFFENER",self.long_thickness_list) + flange_class_top = IS800_2007.Table2_i(((self.top_flange_width / 2)),self.top_flange_thickness,self.material.fy,'Welded')[0] + flange_class_bottom = IS800_2007.Table2_i(((self.bottom_flange_width / 2)),self.bottom_flange_thickness,self.material.fy,'Welded')[0] + web_class = IS800_2007.Table2_iii((self.total_depth - self.top_flange_thickness - self.bottom_flange_thickness),self.web_thickness,self.material.fy) + web_ratio = (self.total_depth - (self.top_flange_thickness + self.bottom_flange_thickness)) / self.web_thickness + flange_ratio_top = self.top_flange_width / (2 *self.top_flange_thickness) + flange_ratio_bottom = self.bottom_flange_width / (2 *self.bottom_flange_thickness) + # print("Section classification- top flange, bottom flange, Web",flange_class_top, flange_class_bottom,web_class,web_ratio,flange_ratio_top,flange_ratio_bottom) + if flange_class_bottom == "Slender" or web_class == "Slender" or flange_class_top == 'Slender': + self.section_class = "Slender" + else: + if flange_class_top == KEY_Plastic: + if web_class == KEY_Plastic: + if flange_class_bottom == KEY_Plastic: + self.section_class = KEY_Plastic + elif flange_class_bottom == KEY_Compact: + self.section_class = KEY_Compact + else: # SemiCompact + self.section_class = KEY_SemiCompact + elif web_class == KEY_Compact: + if flange_class_bottom in [KEY_Plastic, KEY_Compact]: + self.section_class = KEY_Compact + else: # SemiCompact + self.section_class = KEY_SemiCompact + else: # web SemiCompact + self.section_class = KEY_SemiCompact + + elif flange_class_top == KEY_Compact: + if web_class == KEY_Plastic: + if flange_class_bottom in [KEY_Plastic, KEY_Compact]: + self.section_class = KEY_Compact + else: # SemiCompact + self.section_class = KEY_SemiCompact + elif web_class == KEY_Compact: + if flange_class_bottom in [KEY_Plastic, KEY_Compact]: + self.section_class = KEY_Compact + else: # SemiCompact + self.section_class = KEY_SemiCompact + else: # web SemiCompact + self.section_class = KEY_SemiCompact + + else: # flange_class_top == SemiCompact + self.section_class = KEY_SemiCompact + # print("overall section class", self.section_class) + self.Zp_req = self.load.moment * self.gamma_m0 / self.material.fy + self.effective_length_beam(self, design_dictionary, self.length) + + # print( 'self.allow_class', self.allow_class) + + if self.section_class == 'Slender' and self.web_philosophy == 'Thick Web without ITS': + return False + else: + return True + + + def beta_value(self,design_dictionary,section_class): + self.plast_sec_mod_z = Unsymmetrical_I_Section_Properties.calc_PlasticModulusZ(self,self.total_depth,self.top_flange_width,self.bottom_flange_width, + self.web_thickness,self.top_flange_thickness,self.bottom_flange_thickness,self.epsilon) + self.elast_sec_mod_z =Unsymmetrical_I_Section_Properties.calc_ElasticModulusZz(self,self.total_depth,self.top_flange_width,self.bottom_flange_width, + self.web_thickness,self.top_flange_thickness,self.bottom_flange_thickness) + # print('total_depth',self.total_depth) + # print('top_flange_thickness',self.top_flange_thickness) + # print('bottom_flange_thickness',self.bottom_flange_thickness) + # print('eff_depth',self.eff_depth) + # print("self.plast_sec_mod_z",self.plast_sec_mod_z) + # print("self.elast_sec_mod_z",self.elast_sec_mod_z) + self.Zp_req = self.load.moment * self.gamma_m0 / self.material.fy + if self.plast_sec_mod_z >= self.Zp_req: + pass + # logger.info( 'self.section_property.plast_sec_mod_z More than Requires',self.plast_sec_mod_z,self.Zp_req) + if section_class == KEY_Plastic or section_class == KEY_Compact: + self.beta_b_lt = 1.0 + else: + self.beta_b_lt = (self.elast_sec_mod_z/ self.plast_sec_mod_z) + # print("Beta value",self.beta_b_lt) + + + #-----add a check function to call everything. + + #checks thick web thickness + def min_web_thickness_thick_web(self, d, tw, eps, stiffener_type, c): + + if IS800_2007.cl_8_6_1_1_and_8_6_1_2_web_thickness_check(d, tw, eps, stiffener_type, c): + # print("Web thickness is sufficient for thick web") + return True + else: + # print("Web thickness is not sufficient for thick web") + return False + + + + #check 2 moment capacity for major laterally supported & thick web and thin web + def moment_capacity_laterally_supported(self, V,Zp, Ze, Fy, gamma_m0, D, tw, tf_top, tf_bot, section_class) : + A_vg = (D - tf_top - tf_bot) * tw + self.V_d = ((A_vg * Fy) / (math.sqrt(3) * gamma_m0)) + if V > 0.6 * self.V_d: #high shear(Mdv calculation for high shear. Naming kept Md for compatibility) + # print("High shear condition") + self.Md = self.calc_Mdv(self, V, self.V_d, Zp, Ze, Fy, gamma_m0, D, tw, tf_top, tf_bot) + # print("Md", self.Md) + else: #low shear + # print("Low shear condition") + self.Md = IS800_2007.cl_8_2_1_2_design_bending_strength(section_class, Zp, Ze, Fy, gamma_m0, self.support_condition) + # print("Md", self.Md) + self.moment_ratio = self.load.moment/ self.Md + # print("moment", self.Md) + if self.Md >= self.load.moment: + return True + else: + return False + + #check 3 shear capacity for major laterally supported & thick web + def shear_capacity_laterally_supported_thick_web(self, Fy, gamma_m0, D, tw, tf_top, tf_bot): + A_vg = (D - tf_top - tf_bot) * tw + self.V_d = ((A_vg * Fy) / (math.sqrt(3) * gamma_m0)) + # print("V_d", self.V_d) + self.shear_ratio = self.load.shear_force / self.V_d + # print("Shear force", self.load.shear_force) + # print("shear_ratio", self.shear_ratio) + if self.V_d >= self.load.shear_force: + return True + else: + return False + + + #check 4 Web buckling for major laterally supported and unsupported & thick web + def web_buckling_laterally_supported_thick_web(self, Fy, gamma_m0, D, tw, tf_top, tf_bot,E, b1): + self.eff_depth = D - (tf_bot + tf_top) + n1 = self.eff_depth / 2 + Ac = (b1 + n1) * tw + slenderness_input = 2.5 * self.eff_depth / tw + self.fcd = IS800_2007.cl_7_1_2_1_design_compressisive_stress_plategirder(Fy, gamma_m0, slenderness_input, E) + Critical_buckling_load = round(Ac * self.fcd, 2) + # print("Critical buckling load", Critical_buckling_load) + self.web_buckling_ratio = self.load.shear_force / Critical_buckling_load + self.shear_ratio = max(self.load.shear_force / Critical_buckling_load , self.shear_ratio) + if Critical_buckling_load>= self.load.shear_force: + return True + else: + return False + + #check 5 Web crippling for major laterally supported and unsupported & thick web + def web_crippling_laterally_supported_thick_web(self, Fy, gamma_m0, tw, tf_top, b1): + n2 = 2.5 * tf_top + Critical_crippling_load = round((b1 + n2) * tw * Fy / (gamma_m0), 2) + # print("Critical crippling load", Critical_crippling_load) + self.web_crippling_ratio = self.load.shear_force / Critical_crippling_load + self.shear_ratio = max(self.load.shear_force / Critical_crippling_load , self.shear_ratio) + if Critical_crippling_load >= self.load.shear_force: + return True + else: + return False + + + #check 6 moment capacity for major laterally unsupported & thick web + + def get_K_from_warping_restraint(self,warping_condition): + """ + Return effective length factor K based on exact warping restraint description (IS 800:2007, Clause E.1). + """ + if warping_condition == "Both flanges fully restrained": + return 0.5 + elif warping_condition == "Compression flange fully restrained": + return 0.7 + elif warping_condition == "Compression flange partially restrained": + return 0.85 + elif warping_condition == "Warping not restrained in both flanges": + return 1.0 + else: + raise ValueError("Invalid warping restraint. Use one of the four standard conditions.") + def bending_check_lat_unsupported(self, beta_b_lt, plast_sec_mod_z, elast_sec_mod_z, fy, M_cr, section_class): + self.lambda_lt = IS800_2007.cl_8_2_2_1_elastic_buckling_moment(beta_b_lt, plast_sec_mod_z, elast_sec_mod_z, fy, + M_cr) + + self.phi_lt = IS800_2007.cl_8_2_2_Unsupported_beam_bending_phi_lt(self.alpha_lt, self.lambda_lt) + self.X_lt = IS800_2007.cl_8_2_2_Unsupported_beam_bending_stress_reduction_factor(self.phi_lt, self.lambda_lt) + self.fbd_lt = IS800_2007.cl_8_2_2_Unsupported_beam_bending_compressive_stress(self.X_lt, fy, self.gamma_m0) + self.Md = IS800_2007.cl_8_2_2_Unsupported_beam_bending_strength(plast_sec_mod_z, elast_sec_mod_z, self.fbd_lt, + section_class) + # print("Md", self.Md, "zp", plast_sec_mod_z, "fbd_lt", self.fbd_lt, "phi_lt", self.phi_lt, "X_lt", self.X_lt, "lambda_lt", self.lambda_lt) + return round(self.Md, 2) + + def calc_Mdv_lat_unsupported(self, V, Vd, Zp, Ze, Fy, gamma_m0, D, tw, tf_top, tf_bot, + Md): # only for major laterally supp + """ + Calculate Mdv for high shear conditions. + + Parameters: + V : Factored applied shear force + Vd : Design shear strength governed by web yielding/buckling + Zp : Plastic section modulus of the section (Z-axis) + Ze : Elastic section modulus of the section (Z-axis) + Fy : Yield strength of material + gamma_m0 : Partial safety factor for material + D : Total depth of section + tw : Thickness of the web + tf_top : Thickness of the top flange + tf_bot : Thickness of the bottom flange + + Returns: + Mdv : Design bending strength under high shear condition + """ + + # Calculating beta + beta = (2 * V / Vd - 1) ** 2 + + # Calculating Aw and Zfd + d = D - (tf_top + tf_bot) + Aw = d * tw + Zfd = Zp - (Aw * D / 4) + # print("Aw", Aw, "Zfd", Zfd) + # Calculating Mfd + Mfd = Zfd * Fy / gamma_m0 + + # Calculating Mdv + Mdv = Md - beta * (Md - Mfd) + + # Limiting value as per the provided formula + Mdv_limit = (1.2 * Ze * Fy) / gamma_m0 + # print("Mfd", Mfd, "Mdv", Mdv, "Mdv_limit", Mdv_limit) + return round(min(Mdv, Mdv_limit), 2) + + def calc_Mdv(self, V, Vd, Zp, Ze, Fy, gamma_m0, D, tw, tf_top, tf_bot): # only for major laterally supp + """ + Calculate Mdv for high shear conditions. + + Parameters: + V : Factored applied shear force + Vd : Design shear strength governed by web yielding/buckling + Zp : Plastic section modulus of the section (Z-axis) + Ze : Elastic section modulus of the section (Z-axis) + Fy : Yield strength of material + gamma_m0 : Partial safety factor for material + D : Total depth of section + tw : Thickness of the web + tf_top : Thickness of the top flange + tf_bot : Thickness of the bottom flange + + Returns: + Mdv : Design bending strength under high shear condition + """ + + # Calculating beta + beta = (2 * V / Vd - 1) ** 2 + + # Calculating Aw and Zfd + d = D - (tf_top + tf_bot) + Aw = d * tw + Zfd = Zp - (Aw * D / 4) + # print("Aw", Aw, "Zfd", Zfd) + + # Calculating Mfd + Mfd = Zfd * Fy / gamma_m0 + + # Calculating Md (Plastic Design Moment) + Md = Zp * Fy / gamma_m0 + + # Calculating Mdv + Mdv = Md - beta * (Md - Mfd) + + # Limiting value as per the provided formula + Mdv_limit = (1.2 * Ze * Fy) / gamma_m0 + # print("Mfd", Mfd / 1000000, "Mdv", Mdv / 1000000, "Mdv_limit", Mdv_limit / 1000000) + + return round(min(Mdv, Mdv_limit), 2) + + def calc_yj(self,Bf_top, tf_top, Bf_bot, tf_bot, D): + """ + Calculate yj per IS 800:2007 Clause E.3.2.2. Returns 0 for symmetric sections. + """ + if Bf_top == Bf_bot and tf_top == tf_bot: + yj = 0 # symmetric section + h = D - (tf_top + tf_bot) + Ift = (Bf_top * tf_top**3) / 12 + Ifc = (Bf_bot * tf_bot**3) / 12 + beta_f = Ifc / (Ifc + Ift) + alpha = 0.8 if beta_f > 0.5 else 1.0 + yj= alpha * (2 * beta_f - 1) * h / 2 + return yj + + def moment_capacity_laterally_unsupported(self, E, LLT, D, + tf_top, tf_bot, Bf_top, Bf_bot, tw, + LoadingCase, gamma_m0, Fy, shear_force): + if Bf_top == Bf_bot and tf_top == tf_bot: + yj = 0 + # symmetric section + h = D - (tf_top + tf_bot) + Ift = (Bf_top * tf_top ** 3) / 12 + Ifc = (Bf_bot * tf_bot ** 3) / 12 + beta_f = Ifc / (Ifc + Ift) + alpha = 0.8 if beta_f > 0.5 else 1.0 + yj= alpha * (2 * beta_f - 1) * h / 2 + + G = 0.769 * 10 ** 5 + Kw = self.get_K_from_warping_restraint(self, self.warping) + Iy = Unsymmetrical_I_Section_Properties.calc_MomentOfAreaY(self, self.total_depth, self.top_flange_width, + self.bottom_flange_width, self.web_thickness, + self.top_flange_thickness, + self.bottom_flange_thickness) + self.It = Unsymmetrical_I_Section_Properties.calc_TorsionConstantIt(self, self.total_depth, self.top_flange_width, + self.bottom_flange_width, self.web_thickness, + self.top_flange_thickness, + self.bottom_flange_thickness) + self.Iw = Unsymmetrical_I_Section_Properties.calc_WarpingConstantIw(self, self.total_depth, self.top_flange_width, + self.bottom_flange_width, self.web_thickness, + self.top_flange_thickness, + self.bottom_flange_thickness) + + # Mcr calc + yg = D / 2 + yj = self.calc_yj(self, Bf_top, tf_top, Bf_bot, tf_bot, D) + K_value = 0 + # Constants from Table 42 (IS 800:2007) + if LoadingCase == KEY_DISP_UDL_PIN_PIN_PG: + K_value == 1.0 + c1, c2, c3 = 1.132, 0.459, 0.525 + elif LoadingCase == KEY_DISP_UDL_FIX_FIX_PG: + K_value == 0.5 + c1, c2, c3 = 0.712, 0.652, 1.070 + elif LoadingCase == KEY_DISP_PL_PIN_PIN_PG: + K_value == 1.0 + c1, c2, c3 = 1.365, 0.553, 1.780 + elif LoadingCase == KEY_DISP_PL_FIX_FIX_PG: + K_value == 0.5 + c1, c2, c3 = 0.938, 0.715, 4.800 + else: + raise ValueError("Invalid Loading Case.") + + # Symmetric section (Eq 2.20) + if Bf_top == Bf_bot and tf_top == tf_bot: + term1 = (math.pi ** 2 * E * Iy) / (LLT ** 2) + term2 = (self.Iw / Iy) + term3 = (G * self.It * LLT ** 2) / (math.pi ** 2 * E * Iy) + self.M_cr = term1 * math.sqrt(term2 + term3) + else: + # Unsymmetric case (Annex E full formula) + term1 = (math.pi ** 2 * E * Iy) / (LLT ** 2) + bracket = ((K_value / Kw) ** 2 * (self.Iw / Iy) + + (G * self.It * LLT ** 2) / (math.pi ** 2 * E * Iy) + + (c2 * yg - c3 * yj) ** 2) + self.M_cr = c1 * term1 * math.sqrt(bracket) - term1 * (c2 * yg - c3 * yj) + + # print("Input moment", self.load.moment) + # print("MCR VAL", self.M_cr) + A_vg = (D - tf_top - tf_bot) * tw + self.V_d = ((A_vg * Fy) / (math.sqrt(3) * gamma_m0)) + Zp = self.plast_sec_mod_z + self.lambda_lt = IS800_2007.cl_8_2_2_1_elastic_buckling_moment(self.beta_b_lt, self.plast_sec_mod_z, self.elast_sec_mod_z, Fy, + self.M_cr) + + self.phi_lt = IS800_2007.cl_8_2_2_Unsupported_beam_bending_phi_lt(self.alpha_lt, self.lambda_lt) + self.X_lt = IS800_2007.cl_8_2_2_Unsupported_beam_bending_stress_reduction_factor(self.phi_lt, self.lambda_lt) + self.fbd_lt = IS800_2007.cl_8_2_2_Unsupported_beam_bending_compressive_stress(self.X_lt, Fy, self.gamma_m0) + self.Md = IS800_2007.cl_8_2_2_Unsupported_beam_bending_strength(self.plast_sec_mod_z, self.elast_sec_mod_z, self.fbd_lt, + self.section_class) + if shear_force > 0.6 * self.V_d: # high shear(Mdv calculation for high shear. Naming kept Md for compatibility) + self.Md = self.calc_Mdv_lat_unsupported(self, self.load.shear_force, self.V_d, self.plast_sec_mod_z, + self.elast_sec_mod_z, self.material.fy, self.gamma_m0, + self.total_depth, self.web_thickness, self.top_flange_thickness, + self.bottom_flange_thickness, self.Md) + else: # low shear + self.Md = self.bending_check_lat_unsupported(self, self.beta_b_lt, self.plast_sec_mod_z, + self.elast_sec_mod_z, + self.material.fy, self.M_cr, self.section_class) + + self.moment_ratio = self.load.moment / self.Md + # print("Ratio for moment", self.moment_ratio) + # # print("supp mdv",self.Mdv) + if self.Md >= self.load.moment: + return True + else: + return False + + #effective length calculation + def effective_length_beam(self, design_dictionary, length): + if design_dictionary[KEY_LENGTH_OVERWRITE] == 'NA': + self.effective_length = IS800_2007.cl_8_3_1_EffLen_Simply_Supported(Torsional=self.torsional_res,Warping=self.warping, + length=length,depth=(self.total_depth/1000),load=self.loading_condition) + # print(f"Working 1 {self.effective_length}") + else: + try: + if float(design_dictionary[KEY_LENGTH_OVERWRITE]) <= 0: + design_dictionary[KEY_LENGTH_OVERWRITE] = 'NA' else: - self.section_property.web_thickness += 10 + length = length * float(design_dictionary[KEY_LENGTH_OVERWRITE]) + + self.effective_length = length + # print(f"Working 2 {self.effective_length}") + except: + # print(f"Inside effective_length_beam",type(design_dictionary[KEY_LENGTH_OVERWRITE])) + logger.warning("Invalid Effective Length Parameter.") + logger.info('Effective Length Parameter is set to default: 1.0') + design_dictionary[KEY_LENGTH_OVERWRITE] = '1.0' + self.effective_length_beam(self, design_dictionary, length) + # print(f"Working 3 {self.effective_length}") + # print(f"Inside effective_length_beam",self.effective_length, design_dictionary[KEY_LENGTH_OVERWRITE]) + + def end_panel_stiffener_calc(self, + Bf_top, Bf_bot, tw, tq, fy, gamma_m0, d, + tf_top, total_depth, effective_length, tf_bot, E, eps, c + ): + """ + Calculate end panel stiffener properties. + + Parameters: + Bf_top (float): Width of flange at top (mm) + Bf_bot (float): Width of flange at bottom (mm) + tw (float): Thickness of web (mm) + tq (float): Thickness of stiffener (mm) + fy (float): Yield strength of material (MPa) + gamma_m0 (float): Partial safety factor + + + effective_depth (float): Effective depth (mm) + tf_top (float): Top flange thickness (mm) + total_depth (float): Total depth of section (mm) + effective_length (float): Effective length for slenderness (mm) + D (float): Depth of section (mm) + E (float): modulus of elasticity of steel (MPa) + + Returns: + dict: Dictionary of results including buckling resistance, bearing capacity, and torsion check. + """ + A_vg = d * tw + if self.web_philosophy == 'Thick Web without ITS': + K_v = 5.35 + else: + if c / d < 1: + K_v = 4 + 5.35 / (c / d) ** 2 + else: + K_v = 5.35 + 4 / (c / d) ** 2 + E = self.material.modulus_of_elasticity + mu = 0.3 + tau_crc = IS800_2007.cl_8_4_2_2_tau_crc_Simple_postcritical(K_v, self.material.modulus_of_elasticity, mu, d, + tw) + lambda_w = IS800_2007.cl_8_4_2_2_lambda_w_Simple_postcritical(fy, tau_crc) + tau_b = IS800_2007.cl_8_4_2_2_tau_b_Simple_postcritical(lambda_w, fy) + self.V_cr = IS800_2007.cl_8_4_2_2_Vcr_Simple_postcritical(tau_b, A_vg) + Nf = self.load.moment / d + phi, M_fr_t, M_fr_b, s_t, s_b, w_tf, sai, fv, self.V_tf = IS800_2007.cl_8_4_2_2_TensionField_unequal_Isection(c, d, tw, + fy, Bf_top, + tf_top, Bf_bot, tf_bot, + Nf, gamma_m0, + A_vg, tau_b) + V_dp = (d * tw * fy / math.sqrt(3)) + + rad = 1.0 - (self.V_cr / V_dp) + if rad < 0: + return False + + H_q = 1.25 * V_dp * math.sqrt(rad) + R_tf = H_q / 2 + A_v = d * tw + V_n = (fy * A_v) / (math.sqrt(3) * gamma_m0) + # Moment demand M_tf (kN·m) + M_tf = (H_q * d) / 10 + y = c / 2 + I = tw * (c ** 3) / 12 + M_q = (I * fy) / (gamma_m0 * y) + self.moment_ratio = max(M_tf / M_q, self.moment_ratio) + self.endshear_ratio = max(R_tf / V_n, self.endshear_ratio ) + # print('moment ratio', self.moment_ratio, 'end panel shear ratio 1', self.endshear_ratio ) + + # if V_n >= R_tf: + # if M_q >= M_tf: + Fm = M_tf / c + Fc = Fm + self.load.shear_force + bearing_area = 0.8 * Fc * self.gamma_m0 / self.material.fy + Bearing_capacity = 0 + Bearing_stiffenerforce = -1 + thickness_list= ['8', '10', '12', '14', '16', '18', '20', '22', '25', '28', '32', '36', '40', '45', '50', '56', '63', '75', '80', '90', '100', + '110', '120'] + if len(self.int_thickness_list) == 0: + return False + for self.end_stiffthickness in thickness_list: + + self.end_stiffthickness = float(self.end_stiffthickness) + Aq = 2 * self.end_stiffthickness * self.end_stiffwidth + # print('Aq',Aq) + max_outstand = 14 * self.end_stiffthickness * self.epsilon + if self.end_stiffwidth <= max_outstand: + self.end_stiffwidth = max_outstand + I_x = (((2 * self.end_stiffwidth + tw) ** 3) * self.end_stiffthickness) / 12 + I_x += (20 * tw * 2 * tw ** 3) / 12 + I_x -= (self.end_stiffthickness * tw ** 3) / 12 + + # Radius of gyration + r_x = math.sqrt(I_x / Aq) + + # Slenderness ratio + Le = self.lefactor * d + slenderness_input = Le / r_x + + # Design compressive stress from IS 800 + fcd = IS800_2007.cl_7_1_2_1_design_compressisive_stress_plategirder( + self.material.fy, self.gamma_m0, slenderness_input, self.material.modulus_of_elasticity + ) + + # Critical buckling resistance (kN) + Pd = Aq * fcd + + # print('moment ratio', self.moment_ratio, 'end panel shear ratio 2', self.endshear_ratio ) + self.Critical_buckling_resistance = Pd + n2 = 2.5 * self.bottom_flange_thickness + Fw = n2 * tw * self.material.fy / (self.gamma_m0) + Bearing_stiffenerforce = Fc - Fw + Bearing_capacity = self.material.fy * Aq / (self.gamma_m0) + # print('stiff width', self.end_stiffwidth, 'stiff thick', self.end_stiffthickness, 'D', d, 'Vcr', + # self.V_cr, 'Vdp', V_dp, rad, 'Hq', H_q, 'Rtf', R_tf, 'Av', A_v, 'Vn', V_n, 'Mtf', M_tf, 'I', I, + # 'Mq', M_q, 'Fm', Fm, 'Fc', Fc, 'bearing_area', bearing_area, 'Aq', Aq, 'max_outstand', + # max_outstand, 'I_x', I_x, 'r_x', r_x, 'slenderness_input', slenderness_input, 'fcd', fcd, 'Pd', + # Pd, 'Fw', Fw, 'Bearing_stiffenerforce', Bearing_stiffenerforce, 'Bearing_capacity', + # Bearing_capacity) + # print('fcd', fcd, 'Pd', Pd, 'FC', Fc) + self.endshear_ratio = max(Bearing_stiffenerforce / Bearing_capacity, Fc / Pd, R_tf / V_n ) + # print('moment ratio', self.moment_ratio, 'end panel shear ratio 3', self.endshear_ratio ) + + if self.endshear_ratio <= 1: + break + else: continue - def optimum_depth_thickness_flange(self, var): - if self.section_class_req == "Plastic": - self.section_property.flange_thickness = self.myround(self.section_property.flange_width / (2 * 8.4 * self.epsilon),5,'high') + var * 5 - elif self.section_class_req == "Compact": - self.section_property.flange_thickness = self.myround(self.section_property.flange_width / (2 * 9.4 * self.epsilon),5,'high') + var * 5 - else: #Semi-Compact - self.section_property.flange_thickness = math.ceil(myround(self.section_property.flange_width / (2 * 13.6 * self.epsilon),5,'high')) + var * 5 - print(self.section_property.flange_thickness, self.section_property.flange_width) - - def checks(self,type): - # print('depth & web_thickness',self.section_property.depth_web, self.section_property.web_thickness) - if type == 1: - if self.web_type_needed == "Thick": # CL 8.4.2.1 - if not self.web_siffened: - self.single_section_dictionary['Web_Shear_Buckling_validator'] = IS800_2007.cl_8_4_2_1_web_buckling_stiff(self.section_property.depth_web, self.section_property.web_thickness,self.epsilon,1) - else: - self.single_section_dictionary['Web_Shear_Buckling_validator'] = IS800_2007.cl_8_4_2_1_web_buckling_stiff(self.section_property.depth_web, self.section_property.web_thickness,self.epsilon,2, self.single_section_dictionary['Kv']) + self.shear_ratio = max(self.endshear_ratio, self.shear_ratio) + if self.endshear_ratio <= 1: + # print("end stiffener check passed") + + return True + else: + # print("Tension field end stiffener check failed: Bearing capacity insufficient") + self.end_stiffthickness = 0 + + return False + + # # Geometrical properties + # net_outstand = min(Bf_top, Bf_bot) - tq + # width_stiffener = min(max(net_outstand, 14 * tq * eps), 20 * tq * eps) + # + # # Core area and moment of inertia for buckling resistance + # A_core = (14 * tq * epsilon * 2) + (20 * tw * tw) + # Ixx = ((tq * (14 * tq * epsilon * 2) ** 3) / 12) + ((20 * tw * tw ** 3) / 12) + # r = math.sqrt(Ixx / A_core) + # # Slenderness ratio + # slenderness_input = 0.7 * effective_depth / r + # self.fcd = IS800_2007.cl_7_1_2_1_design_compressisive_stress_plategirder( + # fy, + # gamma_m0, + # slenderness_input, + # E ) + # buckling_resistance = self.fcd * A_core + # + # # Bearing capacity + # chamfered_width = 15 # mm + # Aq = 2 * (width_stiffener - chamfered_width) * tq + # bearing_capacity = (Aq * fy) / (0.8 * gamma_m0) + # + # # Torsional restraint + # ry = Unsymmetrical_I_Section_Properties.calc_RadiusOfGyrationY(self, total_depth, Bf_top, Bf_bot, tw, tf_top, tf_bot) + # slender_torsion = effective_length / ry + # + # if slender_torsion <= 50: + # alpha_s = 0.006 + # elif slender_torsion <= 100: + # alpha_s = 0.3 / slender_torsion + # else: + # alpha_s = 30 / (slender_torsion ** 2) + # + # torsion_check = 0.34 * alpha_s * (total_depth ** 3) * tf_top + # Is = (tq * (2 * width_stiffener) ** 3) / 12 + # torsion_ok = Is >= torsion_check + # + # return { + # "Buckling Resistance (N)": buckling_resistance, + # "Bearing Capacity (N)": bearing_capacity, + # "Slenderness Ratio": slenderness_input, + # "Design Compressive Strength fcd (MPa)": self.fcd, + # "Moment of Inertia Is (mm^4)": Is, + # "Torsion Check (mm^4)": torsion_check, + # "Torsion OK": torsion_ok + # } + + def deflection_from_moment_kNm_mm(self,M_kNm, L, E, I, case): + """ + Compute max mid-span deflection from bending moment, + converting M (kN·m) → N·m and L (mm) → m internally. + + Parameters + ---------- + M_kNm : float + Max bending moment in kN·m. + L_mm : float + Span length in mm. + E : float + Young’s modulus in Pa (N/m²). + I : float + Second moment of area in m^4. + case : str + One of 'simple_udl', 'fixed_udl', 'simple_point', 'fixed_point'. + + Returns + ------- + delta : float + Mid-span deflection in meters. + """ + # unit conversions + M = M_kNm # kN·m → N·m + + pref = M * L ** 2 / (E * I * 1.5) + if case == KEY_DISP_UDL_PIN_PIN_PG: + return (5 / 48) * pref + elif case == KEY_DISP_UDL_FIX_FIX_PG: + return (1 / 32) * pref + elif case == KEY_DISP_PL_PIN_PIN_PG: + return (1 / 12) * pref + elif case == KEY_DISP_PL_FIX_FIX_PG: + return (1 / 24) * pref + else: + raise ValueError( + "Unknown case. Use 'simple_udl', 'fixed_udl', 'simple_point', or 'fixed_point'." + ) + + def evaluate_deflection_kNm_mm(self, + M_kNm, L, E, case, criteria +): + """ + 1) Calculate deflection from moment (with unit conversions). + 2) Compare against span-based limits. + Returns (delta_m, results_dict, best_criterion). + """ + # 1) compute deflection in meters + I = Unsymmetrical_I_Section_Properties.calc_MomentOfAreaZ(self,self.total_depth,self.top_flange_width,self.bottom_flange_width,self.web_thickness,self.top_flange_thickness,self.bottom_flange_thickness) + delta = self.deflection_from_moment_kNm_mm(self,M_kNm, L, E, I, case) + + n = float(criteria) + allowable = L / n + # print(L, n, allowable, delta) + ok = (delta <= allowable) + self.deflection_ratio = delta / allowable + + if ok: + return True + else: + return False + # results[crit] = { + # 'allowable_m': allowable, + # 'actual_m': delta, + # 'passes': ok + # } + # if ok: + # passed.append((n, crit)) + + # # pick most stringent (smallest denom) that still passes + # best = min(passed)[1] if passed else None + + # return delta, results + + def shear_stress_unsym_I(self, V_ed, b_ft, t_ft, b_fb, t_fb, t_w, h_w): + + # Part areas [mm^2] + A_t = b_ft * t_ft + A_b = b_fb * t_fb + A_w = t_w * h_w + + # Section total depth & area + D = t_fb + h_w + t_ft + A = A_t + A_b + A_w + + # Centroid y‐coords from bottom of bottom flange [mm] + y_b = t_fb / 2 + y_w = t_fb + h_w / 2 + y_t = t_fb + h_w + t_ft / 2 + + # Neutral axis from bottom [mm] + y_na = (A_b * y_b + A_w * y_w + A_t * y_t) / A + + # Second moment I_z [mm^4] + I_b = b_fb * t_fb ** 3 / 12 + A_b * (y_b - y_na) ** 2 + I_w = t_w * h_w ** 3 / 12 + A_w * (y_w - y_na) ** 2 + I_t = b_ft * t_ft ** 3 / 12 + A_t * (y_t - y_na) ** 2 + I_z = I_b + I_w + I_t + + # First moments Q [mm^3] + Q_bot = A_b * abs(y_na - y_b) + Q_top = A_t * abs(y_t - y_na) + + # Shear flows q = V*Q / I [kN·mm^3 / mm^4 = kN/mm] + q_bot = V_ed * Q_bot / I_z + q_top = V_ed * Q_top / I_z + + return { + 'y_na_mm': y_na, 'I_z_mm4': I_z, + 'Q_top_mm3': Q_top, 'Q_bot_mm3': Q_bot, + 'q_top_kN_per_mm': q_top, + 'q_bot_kN_per_mm': q_bot, + } + + def weld_leg_from_q_with_cl10(self, + q_kN_per_mm, # shear flow [kN/mm] + ultimate_stresses, # list of MPa + fabrication='shop' + ): + """ + Compute fillet‐weld leg a [mm] from shear flow, + using f_wd from cl.10.5.7.1.1. + """ + # 1) get f_wd in MPa → convert to N/mm² + f_wd = IS800_2007.cl_10_5_7_1_1_fillet_weld_design_stress( + ultimate_stresses + ) # MPa + + # 2) convert q to N/mm + q_N_per_mm = q_kN_per_mm + + # 3) throat thickness t = q / f_wd [mm] + t_throat = q_N_per_mm / f_wd + + # 4) leg size a = t·√2 + return t_throat * math.sqrt(2) + + + def design_welds_with_strength_web_to_flange(self, + + V_ed, b_ft, t_ft, b_fb, t_fb, t_w, h_w, + + ultimate_stresses + + ): + # compute shear flows + sf = self.shear_stress_unsym_I(self, V_ed, b_ft, t_ft, b_fb, t_fb, t_w, h_w) + min_weld_legtop = IS800_2007.cl_10_5_2_3_min_weld_size(t_ft, t_w) + min_weld_legbot = IS800_2007.cl_10_5_2_3_min_weld_size(t_fb, t_w) + max_weld_legtop = IS800_2007.cl_10_5_3_1_max_weld_throat_thickness(t_ft, t_w) + max_weld_legbot = IS800_2007.cl_10_5_3_1_max_weld_throat_thickness(t_fb, t_w) + # weld legs using cl.10 strength + a_top = round_up(max(self.weld_leg_from_q_with_cl10(self, + sf['q_top_kN_per_mm'], ultimate_stresses + ), min_weld_legtop) and min(self.weld_leg_from_q_with_cl10(self, + sf['q_top_kN_per_mm'], ultimate_stresses + ), max_weld_legtop),1) + + a_bot = round_up(max(self.weld_leg_from_q_with_cl10(self, + sf['q_bot_kN_per_mm'], ultimate_stresses + ), min_weld_legbot) and min(self.weld_leg_from_q_with_cl10(self, sf['q_bot_kN_per_mm'], ultimate_stresses + ), max_weld_legbot),1) + + # end‐stiffener check (unchanged) + + return a_top, a_bot + + + def weld_for_end_stiffener(self, t_st, b_st, V_ed, V_unstf, D, t_ft, t_fb, tw, ultimate_stresses): + """ + t_st : thickness of stiffener + b_st : width of stiffener + V_ed : design shear force + V_unstf : unstiffened shear force + D : depth of section + t_ft : thickness of top flange + t_fb : thickness of bottom flange + tw : thickness of web + Automatically computes L_weld = D - t_ft - t_fb, + then returns: + q1_min = t_st^2/(5·b_st) + q2_ext = (V_ed–V_unstf)/L_weld + q_total = q1 + q2 + q_each_weld = q_total/2 + All in kN/mm. + """ + # 0) available weld length + L_weld = D - t_ft - t_fb + + # 1) min weld per side + q1 = tw ** 2 / (5 * b_st) + + # 2) stiffener shear per unit length + delta_V = max(V_ed - V_unstf, 0) + q2 = delta_V / L_weld + + # 3) total on one side + q_tot = q1 + q2 + + # 4) split into two welds (each face) + q_each = q_tot / 2 + + min_weld_legtop = IS800_2007.cl_10_5_2_3_min_weld_size(t_st, tw) + + max_weld_legtop = IS800_2007.cl_10_5_3_1_max_weld_throat_thickness(t_st, tw) + + # weld legs using cl.10 strength + weld_stiff = self.weld_leg_from_q_with_cl10(self, q_each, ultimate_stresses) + # print("weld_stiff", weld_stiff, "min_weld_legtop", min_weld_legtop, "max_weld_legtop", max_weld_legtop) + if weld_stiff < min_weld_legtop: + weld_stiff = min_weld_legtop + if weld_stiff > max_weld_legtop: + weld_stiff = max_weld_legtop + #weld_stiff = round_up(max(weld_stiff, min_weld_legtop) and min(weld_stiff, max_weld_legtop), 1) + + return weld_stiff + + + + #-------------Thin Web (Simple post critical method)------------------------# + def shear_buckling_check_simple_postcritical(self, eff_depth,D,tf_top,tf_bot,tw, V, c=0): + A_vg = eff_depth * tw + if self.web_philosophy == 'Thick Web without ITS': + K_v = 5.35 + else: + if c / eff_depth < 1: + K_v = 4 + 5.35 / (c / eff_depth) ** 2 else: - self.section_property.web_thickness = self.myround(self.section_property.depth_web / (67 * self.epsilon),10,'high')#math.ceil() - print(self.section_property.depth_web / (67 * self.epsilon),'new web_thickness', self.section_property.web_thickness) - return True - elif type == 2: - print('ratio 2', self.section_property.depth_web/self.section_property.web_thickness) - if self.servicibility_check: - return True if self.section_property.depth_web/self.section_property.web_thickness < 200 * self.epsilon else False - # TODO No transverse stiffener web connected to flanges along both longitudinal edges CL 8.6.1.1 - elif type == 3: - print('ratio 3', self.section_property.depth_web/self.section_property.web_thickness) - if self.compression_flange_buckling: - return True if self.section_property.depth_web / self.section_property.web_thickness <= 345 * self.epsilon**2 else False - elif type == 4: - ic('check 4', self.shear_strength,self.load.shear_force ) - return True if self.shear_strength > self.load.shear_force else False - - def section_classification(self): - self.web_class_list = IS800_2007.Table2_i( - (self.section_property.flange_width - self.section_property.web_thickness) / 2, - self.section_property.flange_thickness, - self.material_property.fy, self.section_property.type + K_v = 5.35 + 4 / (c / eff_depth) ** 2 + E = self.material.modulus_of_elasticity + mu = 0.3 + tau_crc = IS800_2007.cl_8_4_2_2_tau_crc_Simple_postcritical(K_v, E, mu, eff_depth, self.web_thickness) + lambda_w = IS800_2007.cl_8_4_2_2_lambda_w_Simple_postcritical(self.material.fy, tau_crc) + tau_b = IS800_2007.cl_8_4_2_2_tau_b_Simple_postcritical(lambda_w, self.material.fy) + self.V_cr = IS800_2007.cl_8_4_2_2_Vcr_Simple_postcritical(tau_b, A_vg) + print("V_cr value", self.V_cr) + #self.shear_ratio = max(self.load.shear_force / self.V_cr , self.shear_ratio) + if self.V_cr > V: + self.shear_ratio = max(self.load.shear_force / self.V_cr, self.shear_ratio) + return True + else: + return False + + + def shear_buckling_check_intermediate_stiffener( + self, + d, + tw, + c, + e, + IntStiffThickness, + IntStiffenerWidth, + V_ed, + gamma_m0, + fy, + E +): + """ + Performs global and shear buckling checks for an intermediate stiffener. + + Parameters: + d : float : depth of web panel (mm) + tw : float : thickness of web (mm) + c : float : stiffener spacing (mm) + e : float : outstand ratio factor + IntStiffThickness : float : thickness of intermediate stiffener (mm) + IntStiffenerWidth : float : width of intermediate stiffener leg (mm) + V_cr : float : critical shear buckling force (kN) + V_ed : float : design shear force on panel (kN) + gamma_m0 : float : partial safety factor for material + fy : float : yield strength of steel (MPa) + E : float : modulus of elasticity of steel (MPa) + + Returns: + bool : True if stiffener passes both global and shear buckling checks, False otherwise. + """ + A_vg = d * tw + if self.web_philosophy == 'Thick Web without ITS': + K_v = 5.35 + else: + if c / d < 1: + K_v = 4 + 5.35 / (c / d) ** 2 + else: + K_v = 5.35 + 4 / (c / d) ** 2 + mu = 0.3 + tau_crc = IS800_2007.cl_8_4_2_2_tau_crc_Simple_postcritical(K_v, E, mu, d, self.web_thickness) + lambda_w = IS800_2007.cl_8_4_2_2_lambda_w_Simple_postcritical(self.material.fy, tau_crc) + tau_b = IS800_2007.cl_8_4_2_2_tau_b_Simple_postcritical(lambda_w, self.material.fy) + self.V_cr = IS800_2007.cl_8_4_2_2_Vcr_Simple_postcritical(tau_b, A_vg) + # 1. Global buckling check of stiffener + cd_ratio = c / d + if cd_ratio >= math.sqrt(2): + I_min_global = 0.75 * d * tw**3 + + else: + I_min_global = (1.5 * d**3 * tw**3) / (c**2) + + + # Maximum allowable outstand + max_outstand = 14 * IntStiffThickness * e + + # Fail global check if inertia or outstand insufficient + if max_outstand < IntStiffenerWidth: + #print('I_s > I_min_global or max_outstand > IntStiffenerWidth') + IntStiffenerWidth= max_outstand + + # Moment of inertia of stiffener cross-section + I_s = (((2 * IntStiffenerWidth + tw) ** 3) * IntStiffThickness) / 12 + I_s -= (IntStiffThickness * tw ** 3) / 12 + + # 2. Shear buckling (axial) check of stiffener + # Effective shear force on stiffener + F_q = (V_ed - self.V_cr) / gamma_m0 + + # Provided cross-sectional area + A_s = 2 * IntStiffenerWidth * IntStiffThickness + + # Combined area for axial buckling (stiffener + bearing area) + A_x = A_s + (20 * tw * 2 * tw) + + # Moment of inertia for axial buckling + I_x = (((2 * IntStiffenerWidth + tw)**3) * IntStiffThickness) / 12 + I_x += (20 * tw * 2 * tw**3) / 12 + I_x -= (IntStiffThickness * tw**3) / 12 + + # Radius of gyration + r_x = math.sqrt(I_x / A_x) + + # Slenderness ratio + Le = self.lefactor * d + slenderness_input = Le / r_x + + # Design compressive stress from IS 800 + fcd = IS800_2007.cl_7_1_2_1_design_compressisive_stress_plategirder( + fy, gamma_m0, slenderness_input, E ) - self.flange_class_list = ['Plastic',0] - # IS800_2007.Table2_i( - # self.section_property.depth_web , - # self.section_property.web_thickness, - # self.material_property.fy, self.section_property.type - # ) - self.web_class = self.web_class_list[0] - self.flange_class = self.flange_class_list[0] - if self.flange_class == "Slender" or self.web_class == "Slender": - self.section_class_girder = "Slender" - else: - if self.flange_class == "Plastic" and self.web_class == "Plastic": - self.section_class_girder = "Plastic" - elif self.flange_class == "Plastic" and self.web_class == "Compact": - self.section_class_girder = "Compact" - elif self.flange_class == "Plastic" and self.web_class == "Semi-Compact": - self.section_class_girder = "Semi-Compact" - elif self.flange_class == "Compact" and self.web_class == "Plastic": - self.section_class_girder = "Compact" - elif self.flange_class == "Compact" and self.web_class == "Compact": - self.section_class_girder = "Compact" - elif self.flange_class == "Compact" and self.web_class == "Semi-Compact": - self.section_class_girder = "Semi-Compact" - elif self.flange_class == "Semi-Compact" and self.web_class == "Plastic": - self.section_class_girder = "Semi-Compact" - elif self.flange_class == "Semi-Compact" and self.web_class == "Compact": - self.section_class_girder = "Semi-Compact" - elif self.flange_class == "Semi-Compact" and self.web_class == "Semi-Compact": - self.section_class_girder = "Semi-Compact" - print(self.web_class_list,self.flange_class_list,self.section_class_girder) - return (('web_class',self.web_class),('flange_class',self.flange_class),('section_class_girder',self.section_class_girder),('Class Ratio',self.web_class_list[1])) - - def Shear_Strength(self): - self.V_d = IS800_2007.cl_8_4_design_shear_strength( - ic(self.section_property.shear_area), - ic(self.material_property.fy) - ) / 10 ** 3 - self.shear_strength = self.myround(self.V_d,5,'low') - def plate_girder_strength(self): - Flexure.plate_girder_strength(self) - - # self.shear_strength = self.myround(self.V_d,5,'low') - def bending_strength_girder(self): - # print('Inside bending_strength of girder ') - # web_class = IS800_2007.Table2_i( - # (self.section_property.flange_width - self.section_property.web_thickness)/2, - # self.section_property.flange_thickness, - # self.material_property.fy, self.section_property.type - # )[0] - # flange_class = IS800_2007.Table2_i( - # self.section_property.depth - 2 * self.section_property.flange_thickness, - # self.section_property.web_thickness, - # self.material_property.fy,self.section_property.type - # )[0] - # if flange_class == "Slender" or web_class == "Slender": - # self.section_class_girder = "Slender" + + # Critical buckling resistance (kN) + Pd = round(A_x * fcd , 2) + self.shear_ratio = max(self.load.shear_force / Pd , self.shear_ratio) + # print('moment ratio', self.moment_ratio, 'inter shear ratio', self.shear_ratio) + self.Critical_buckling_resistance = Pd + + # print("Intermediate stiffener shear buckling check:", 'stiff width', IntStiffenerWidth, 'stiff thick', IntStiffThickness, 'cd_ratio', cd_ratio, 'I_min_global', I_min_global, 'I_s', I_s, 'max_outstand', max_outstand, 'F_q', F_q, 'As', A_s, 'Ax', A_x, 'Ix', I_x, 'rx', r_x, 'Le', Le, 'slenderness input', slenderness_input, 'fcd', fcd, 'Pd', Pd, 'V_cr', self.V_cr, 'V_ed', V_ed, 'gamma_m0', gamma_m0, 'fy', fy, 'E', E) + + # Debug prints + # print("Design shear force on stiffener F_q:", round(F_q, 2), "kN") + # print("Critical buckling resistance Pd:", Pd, "kN") + + # Check axial capacity + # if F_q < Pd: + # print("Intermediate stiffener shear buckling check passed") + return True # else: - # if flange_class == "Plastic" and web_class == "Plastic": - # self.section_class_girder = "Plastic" - # elif flange_class == "Plastic" and web_class == "Compact": - # self.section_class_girder = "Compact" - # elif flange_class == "Plastic" and web_class == "Semi-Compact": - # self.section_class_girder = "Semi-Compact" - # elif flange_class == "Compact" and web_class == "Plastic": - # self.section_class_girder = "Compact" - # elif flange_class == "Compact" and web_class == "Compact": - # self.section_class_girder = "Compact" - # elif flange_class == "Compact" and web_class == "Semi-Compact": - # self.section_class_girder = "Semi-Compact" - # elif flange_class == "Semi-Compact" and web_class == "Plastic": - # self.section_class_girder = "Semi-Compact" - # elif flange_class == "Semi-Compact" and web_class == "Compact": - # self.section_class_girder = "Semi-Compact" - # elif flange_class == "Semi-Compact" and web_class == "Semi-Compact": - # self.section_class_girder = "Semi-Compact" - # 4 - design bending strength - I_flange = 2 * (self.section_property.flange_width * self.section_property.flange_thickness**3/12 + self.section_property.flange_width * self.section_property.flange_thickness * (self.section_property.depth/2 - self.section_property.flange_thickness/2)**2) - Zez_flange = I_flange / self.section_property.depth /2 - y_top = (self.section_property.flange_width * self.section_property.flange_thickness * (self.section_property.depth - self.section_property.flange_thickness)/2) / (self.section_property.flange_width * self.section_property.flange_thickness) - Zpz_flange = 2 * self.section_property.flange_width * self.section_property.flange_thickness * y_top - M_d = IS800_2007.cl_8_2_1_2_design_bending_strength( - self.section_class_girder, - Zpz_flange, - Zez_flange, - self.material_property.fy, - self.gamma_m0, - self.support, + # return False + + + def tension_field_end_stiffener(self, d, tw, fyw, shear_force, moment, c): + # Formula 1: H_q = 1.25·V_p·√[1 – (V_cr–V_p)/(V_tf–V_cr)] + + A_vg = d * tw + if self.web_philosophy == 'Thick Web without ITS': + K_v = 5.35 + else: + if c / d < 1: + K_v = 4 + 5.35 / (c / d) ** 2 + else: + K_v = 5.35 + 4 / (c / d) ** 2 + E = self.material.modulus_of_elasticity + mu = 0.3 + tau_crc = IS800_2007.cl_8_4_2_2_tau_crc_Simple_postcritical(K_v, self.material.modulus_of_elasticity, mu, d, tw) + lambda_w = IS800_2007.cl_8_4_2_2_lambda_w_Simple_postcritical(self.material.fy, tau_crc) + tau_b = IS800_2007.cl_8_4_2_2_tau_b_Simple_postcritical(lambda_w, self.material.fy) + self.V_cr = IS800_2007.cl_8_4_2_2_Vcr_Simple_postcritical(tau_b, A_vg) + Nf = self.load.moment / (d + (self.top_flange_thickness + self.bottom_flange_thickness) / 2) + result= IS800_2007.cl_8_4_2_2_TensionField_unequal_Isection(c, d, tw, + fyw, self.top_flange_width, + self.top_flange_thickness, self.bottom_flange_width, + self.bottom_flange_thickness, + Nf, self.gamma_m0, + A_vg, tau_b) + V_tf= result[8] + V_dp = (d * tw * fyw * math.sqrt(3)) + denom = V_tf - self.V_cr + rad = 1.0 - (self.V_cr - V_dp) / denom + if rad < 0: + return False # Avoid negative radicand under sqrt + H_q = (shear_force - self.V_cr) / denom + R_tf = H_q / 2 + A_v= d * tw + V_n= (fyw * A_v) /( math.sqrt(3) * self.gamma_m0) + # Moment demand M_tf (kN·m) + M_tf = (H_q * d) / 10 + y = c / 2 + I = tw * c ** 3 / 12 + M_q = (I * fyw) / (self.gamma_m0 * y) + self.moment_ratio = max(M_tf / M_q , self.moment_ratio) + self.endshear_ratio = max(R_tf / V_n, self.endshear_ratio) + if V_n >= R_tf: + if M_q >= M_tf: + Fm= M_tf/c + Fc= Fm + shear_force + bearing_area = 0.8 * Fc * self.gamma_m0 / self.material.fy + thickness_list = ['8', '10', '12', '14', '16', '18', '20', '22', '25', '28', '32', '36', '40', '45', + '50', '56', '63', '75', '80', '90', '100', + '110', '120'] + if len(self.int_thickness_list) == 0: + return False + for self.end_stiffthickness in thickness_list: + self.end_stiffthickness = float(self.end_stiffthickness) + Aq= 2 * self.IntStiffnerwidth* self.IntStiffThickness + Aq>= bearing_area + max_outstand = 14 * self.IntStiffThickness * self.epsilon + if self.IntStiffnerwidth > max_outstand: + self.IntStiffnerwidth = max_outstand + I_x = (((2 * self.IntStiffnerwidth + tw) ** 3) * self.IntStiffThickness) / 12 + I_x += (20 * tw * 2 * tw ** 3) / 12 + I_x -= (self.IntStiffThickness * tw ** 3) / 12 + + # Radius of gyration + r_x = math.sqrt(I_x / Aq) + + # Slenderness ratio + Le = self.lefactor * d + slenderness_input = Le / r_x + + # Design compressive stress from IS 800 + fcd = IS800_2007.cl_7_1_2_1_design_compressisive_stress_plategirder( + self.material.fy, self.gamma_m0, slenderness_input, self.material.modulus_of_elasticity + ) + + # Critical buckling resistance (kN) + Pd = round(Aq * fcd , 2) + + self.Critical_buckling_resistance = Pd + + n2= 2.5 * self.bottom_flange_thickness + Fw= n2 * tw * self.material.fy / (self.gamma_m0) + Bearing_stiffenerforce= Fc - Fw + Bearing_capacity= self.material.fy * Aq / (1.1 * self.gamma_m0) + self.endshear_ratio = max(Bearing_stiffenerforce / Bearing_capacity, Fc / Pd, R_tf / V_n) + + if self.endshear_ratio <= 1: + break + else: + continue + self.shear_ratio = max(self.endshear_ratio, self.shear_ratio) + if self.endshear_ratio <= 1: + # print("end stiffener check passed") + + return True + else: + # print("Tension field end stiffener check failed: Bearing capacity insufficient") + self.end_stiffthickness = 0 + + return False + + def shear_buckling_check_tension_field(self, eff_depth,D,tf_top,tf_bot,tw, c=0): + A_vg = (D - tf_top - tf_bot) * tw + if self.web_philosophy == 'Thick Web without ITS': + K_v = 5.35 + else: + if c / eff_depth < 1: + K_v = 4 + 5.35 / (c / eff_depth) ** 2 + else: + K_v = 5.35 + 4 / (c / eff_depth) ** 2 + E = self.material.modulus_of_elasticity + mu = 0.3 + tau_crc = IS800_2007.cl_8_4_2_2_tau_crc_Simple_postcritical(K_v, E, mu, eff_depth, self.web_thickness) + lambda_w = IS800_2007.cl_8_4_2_2_lambda_w_Simple_postcritical(self.material.fy, tau_crc) + tau_b = IS800_2007.cl_8_4_2_2_tau_b_Simple_postcritical(lambda_w, self.material.fy) + self.V_cr = IS800_2007.cl_8_4_2_2_Vcr_Simple_postcritical(tau_b, A_vg) + Nf = self.load.moment / (eff_depth + (tf_top + tf_bot) / 2) + phi, M_fr_t, M_fr_b, s_t, s_b, w_tf, sai, fv, self.V_tf = IS800_2007.cl_8_4_2_2_TensionField_unequal_Isection(c, eff_depth, self.web_thickness, + self.material.fy, self.top_flange_width, + self.top_flange_thickness, self.bottom_flange_width, self.bottom_flange_thickness, + Nf, self.gamma_m0, + A_vg, tau_b) + #print("vtf val",self.V_tf) + #print('eff depth', eff_depth, 'nf', Nf, 'tau_crc', tau_crc, 'tau_b', tau_b, 'V_cr', self.V_cr, 'phi', phi, 'M_fr_t', M_fr_t, 'M_fr_b', M_fr_b, 's_t', s_t, 's_b', s_b, 'w_tf', w_tf, 'sai', sai, 'fv', fv, 'V_tf', self.V_tf) + self.shear_ratio = max(self.load.shear_force / self.V_tf , self.shear_ratio) + if self.V_tf >= self.load.shear_force: + return True + else: + return False + + def tension_field_intermediate_stiffener( + self, + d, + tw, + c, + e, + IntStiffThickness, + IntStiffenerWidth, + V_ed, + gamma_m0, + fy, + E + ): + """ + Performs global and shear buckling checks for an intermediate stiffener. + + Parameters: + d : float : depth of web panel (mm) + tw : float : thickness of web (mm) + c : float : stiffener spacing (mm) + e : float : outstand ratio factor + IntStiffThickness : float : thickness of intermediate stiffener (mm) + IntStiffenerWidth : float : width of intermediate stiffener leg (mm) + V_cr : float : critical shear buckling force (kN) + V_ed : float : design shear force on panel (kN) + gamma_m0 : float : partial safety factor for material + fy : float : yield strength of steel (MPa) + E : float : modulus of elasticity of steel (MPa) + + Returns: + bool : True if stiffener passes both global and shear buckling checks, False otherwise. + """ + A_vg = d * tw + if self.web_philosophy == 'Thick Web without ITS': + K_v = 5.35 + else: + if c / d < 1: + K_v = 4 + 5.35 / (c / d) ** 2 + else: + K_v = 5.35 + 4 / (c / d) ** 2 + mu = 0.3 + tau_crc = IS800_2007.cl_8_4_2_2_tau_crc_Simple_postcritical(K_v, E, mu, d, self.web_thickness) + lambda_w = IS800_2007.cl_8_4_2_2_lambda_w_Simple_postcritical(self.material.fy, tau_crc) + tau_b = IS800_2007.cl_8_4_2_2_tau_b_Simple_postcritical(lambda_w, self.material.fy) + self.V_cr = IS800_2007.cl_8_4_2_2_Vcr_Simple_postcritical(tau_b, A_vg) + # 1. Global buckling check of stiffener + cd_ratio = c / d + if cd_ratio >= math.sqrt(2): + I_min_global = 0.75 * d * tw ** 3 + + else: + I_min_global = (1.5 * d ** 3 * tw ** 3) / (c ** 2) + + # Maximum allowable outstand + max_outstand = 14 * IntStiffThickness * e + + # Fail global check if inertia or outstand insufficient + if max_outstand < IntStiffenerWidth: + # print('I_s > I_min_global or max_outstand > IntStiffenerWidth') + IntStiffenerWidth = max_outstand + + # Moment of inertia of stiffener cross-section + I_s = (((2 * IntStiffenerWidth + tw) ** 3) * IntStiffThickness) / 12 + I_s -= (IntStiffThickness * tw ** 3) / 12 + + # 2. Shear buckling (axial) check of stiffener + # Effective shear force on stiffener + F_q = (V_ed - self.V_cr) / gamma_m0 + + # Provided cross-sectional area + A_s = 2 * IntStiffenerWidth * IntStiffThickness + + # Combined area for axial buckling (stiffener + bearing area) + A_x = A_s + (20 * tw * 2 * tw) + + # Moment of inertia for axial buckling + I_x = (((2 * IntStiffenerWidth + tw) ** 3) * IntStiffThickness) / 12 + I_x += (20 * tw * 2 * tw ** 3) / 12 + I_x -= (IntStiffThickness * tw ** 3) / 12 + + # Radius of gyration + r_x = math.sqrt(I_x / A_x) + + # Slenderness ratio + Le = self.lefactor * d + slenderness_input = Le / r_x + + # Design compressive stress from IS 800 + fcd = IS800_2007.cl_7_1_2_1_design_compressisive_stress_plategirder( + fy, gamma_m0, slenderness_input, E ) - if self.section_class_girder == 'Plastic' or 'Compact' : - self.beta_b_lt = 1 - else : self.beta_b_lt = Zez_flange/Zpz_flange - self.M_d = M_d - if self.design_type == KEY_DISP_DESIGN_TYPE_FLEXURE: - if self.high_shear_check: - if self.section_class_girder == "Plastic" or self.section_class_girder == "Compact": - bending_strength_section - # TODO = self.bending_strength_reduction(self, M_d) - else: - bending_strength_section = ( - self.section_property.elast_sec_mod_z - * self.material_property.fy - / self.gamma_m0 - ) + + # Critical buckling resistance (kN) + Pd = round(A_x * fcd, 2) + self.shear_ratio = max(self.load.shear_force / Pd, self.shear_ratio) + # print('moment ratio', self.moment_ratio, 'inter shear ratio', self.shear_ratio) + self.Critical_buckling_resistance = Pd + + # print("Intermediate stiffener shear buckling check:", 'stiff width', IntStiffenerWidth, 'stiff thick', + # IntStiffThickness, 'cd_ratio', cd_ratio, 'I_min_global', I_min_global, 'I_s', I_s, 'max_outstand', + # max_outstand, 'F_q', F_q, 'As', A_s, 'Ax', A_x, 'Ix', I_x, 'rx', r_x, 'Le', Le, 'slenderness input', + # slenderness_input, 'fcd', fcd, 'Pd', Pd, 'V_cr', self.V_cr, 'V_ed', V_ed, 'gamma_m0', gamma_m0, 'fy', + # fy, 'E', E) + + # Debug prints + # print("Design shear force on stiffener F_q:", round(F_q, 2), "kN") + # print("Critical buckling resistance Pd:", Pd, "kN") + + # Check axial capacity + # if F_q < Pd: + # print("Intermediate stiffener shear buckling check passed") + return True + # else: + # return False + + def design_longitudinal_stiffeners(self, d, tw, c, eps_w, second_stiffener=False): + """ + Determine whether horizontal (longitudinal) stiffeners are required in a plate girder + and compute the minimum required second moment of area Is. + + Parameters + ---------- + d : float + Clear depth of web (distance between flanges), in mm (or consistent units). + tw : float + Web thickness, in mm. + c : float + Clear distance from compression - flange angles to the neutral axis, in mm. + eps_w : float + Web slenderness parameter ε_w = √(E/Fy), unitless. + second_stiffener : bool, optional + If True, assume a stiffener at the neutral axis will be provided (enabling Eq. 2.39). + + Returns + ------- + dict + { + 'required' : bool, # Is any stiffener required? + 'slenderness' : float, # Governing slenderness ratio used + 'limit' : float, # Allowable slenderness limit + 'locations' : tuple, # (x1, x2), distances from comp. flange to stiffeners + 'I1_min' : float, # Eq. 2.40: first stiffener Is ≥ 4·c·t_w³ + 'I2_min' : float, # Eq. 2.41: second stiffener Is ≥ d2²·t_w³, where d2=2·c + 'Imin_global' : float, # Eqs. 2.42 - 2.43: overall minimum stiffener Is + 'Is_required' : float # Governing Is = max(I1_min, I2_min, Imin_global) + } + + Notes + ----- + - Uses Eq. 2.36 - 2.38 for the unstiffened web checks; if `second_stiffener=True`, uses + Eq. 2.39 (d/tw ≤ 400·ε_w) instead. + - Locations: x1 = c/5 from compression flange; x2 = 0 (neutral axis). + """ + c = float(c) + tw = float(tw) + d_na= Unsymmetrical_I_Section_Properties.calc_centroid(self, self.total_depth, self.top_flange_width, self.bottom_flange_width, self.web_thickness, self.top_flange_thickness, self.bottom_flange_thickness) + # print('d_na', d_na) + # 2) stiffener locations + self.x1 = int(round(d_na / 5.0 ,0)) # first stiffener at 1/5 of neutral axis from compression flange + self.x2 = 0.0 # second stiffener at neutral axis + + # 3) design criteria for Is + I1_min = 4.0 * c * tw ** 3 # Eq. 2.40 + d2 = 2.0 * d_na # twice clear distance to NA + I2_min = d2 ** 2 * tw ** 3 # Eq. 2.41 + + # 4) global minimum (Eqs. 2.42–2.43) + cd_ratio = c / d + if cd_ratio >= math.sqrt(2): + Imin_global = 0.75 * d * tw ** 3 + else: + Imin_global = (1.5 * (d **3 )* tw ** 3) / (c ** 2) + + Is_required_firststiff = max(I1_min, Imin_global) + Is_required_secondstiff = max(I2_min, Imin_global) + Is_provided = (self.eff_width_longitudnal * (self.LongStiffThickness ** 3)) / 12 + + # print("Req", Is_required, "Prov", Is_provided) + + if second_stiffener is False : + if Is_required_firststiff > Is_provided: + return True else: - bending_strength_section = M_d - print('Inside bending_strength 1', M_d, self.high_shear_check, bending_strength_section) - else: - # self.It = ( - # 2 - # * self.section_property.flange_width - # * self.section_property.flange_thickness**3 - # ) / 3 + ( - # (self.section_property.depth - self.section_property.flange_thickness) - # * self.section_property.web_thickness**3 - # ) / 3 - self.hf = self.section_property.depth - self.section_property.flange_thickness - # self.Iw = 0.5**2 * self.section_property.mom_inertia_y * self.hf**2 - self.fcrb = IS800_2007.cl_8_2_2_Unsupported_beam_bending_fcrb( - self.material_property.modulus_of_elasticity, - self.effective_length/self.section_property.rad_of_gy_y, - self.hf/self.section_property.flange_thickness - ) + return False + else: + + if Is_required_firststiff > Is_provided and Is_required_secondstiff > Is_provided: + return True + else: + return False + + + #PSO HELPER FUNCTIONS + ##### NEW PSO ##### + - if self.section_class_girder == "Plastic" or self.section_class_girder == "Compact": - self.beta_b_lt = 1.0 + # def initialize(self, design_dictionary): + + + # 1. Generate the “empirical” first particle + def generate_first_particle(self,L, M, fy,is_thick_web, is_symmetric,k=67): + D_empirical = L / 25 # span in mm + d_opt = ((M * k) / fy) ** (1/3) # mm + D_final = max(D_empirical, d_opt) + + bf_top = 0.3 * D_final + bf_bot = 0.3 * D_final + bf = 0.3 * D_final + + e = math.sqrt(250 / fy) + tf_top = max(bf_top / 24 , bf_top / 8.4 * e ) + tf_bot = max(bf_bot / 24 , bf_bot / 8.4 * e) + tf = max(bf / 24, bf_bot / 8.4 * e) + + + d = D_final - 2 * tf + if is_thick_web: + tw = max(d / 200, d /( 84 * e ), 8) + else: + tw = max( d / 200, d / ( 105 * e ), 8) + + + c = 200 # min panel length (if used) + t_stiff = 6 # min stiffener thickness (if used) + # Order must match your variable list below + varlst = [] + if is_symmetric: + if is_thick_web: + varlst += [tf,tw,bf,D_final] else: - self.beta_b_lt = ( - self.section_property.elast_sec_mod_z - / self.section_property.plast_sec_mod_z - ) - if self.section_property.type == "Rolled": - alpha_lt = 0.21 + varlst += [tf,tw,bf,D_final,c,t_stiff] + else: + if is_thick_web: + varlst += [tf_top,tf_bot,tw,bf_top,bf_bot,D_final] else: - alpha_lt = 0.49 - lambda_lt = IS800_2007.cl_8_2_2_1_elastic_buckling_moment_fcrb( - self.material_property.fy, self.fcrb - ) - phi_lt = IS800_2007.cl_8_2_2_Unsupported_beam_bending_phi_lt( - alpha_lt, lambda_lt - ) - X_lt = IS800_2007.cl_8_2_2_Unsupported_beam_bending_stress_reduction_factor( - phi_lt, lambda_lt - ) - fbd = IS800_2007.cl_8_2_2_Unsupported_beam_bending_compressive_stress( - X_lt, self.material_property.fy, self.gamma_m0 + varlst += [tf_top,tf_bot,tw,bf_top,bf_bot,D_final,c,t_stiff] + # print(varlst) + return varlst + + # 2. Build the list of variables + def build_variable_structure(self,is_thick_web=True, is_symmetric=True): + variables = [] + if is_symmetric: + # tf, tw, bf, D + variables += ['tf', 'tw', 'bf', 'D'] + else: + variables += ['tf_top', 'tf_bot', 'tw', 'bf_top', 'bf_bot', 'D'] + + if not is_thick_web: + variables += ['c', 't_stiff'] + + return variables + + # 3. Create bounds array + def get_bounds(self,variable_list): + bounds_map = { + 'tf': (6, 100), + 'tf_top': (6, 100), + 'tf_bot': (6, 100), + 'tw': (6, 40), + 'bf': (100, 1000), + 'bf_top': (100, 1000), + 'bf_bot': (100, 1000), + 'D': (200, 2000), + 'c': (75, 3000), + 't_stiff': (6, 40) + } + lower = [bounds_map[v][0] for v in variable_list] + upper = [bounds_map[v][1] for v in variable_list] + return (np.array(lower), np.array(upper)) + + + # 4. Assign a particle vector to your section object + def assign_particle_to_section(self,particle, variable_list, section): + for name, value in zip(variable_list, particle): + setattr(section, name, value) + + # handle symmetric naming if needed + # print("Particle",particle) + # print("Variable list",variable_list) + if 'tf' in variable_list: + section.tf_top = section.tf_bot = section.tf + section.bf_top = section.bf_bot = section.bf + + self.top_flange_thickness = section.tf_top + self.bottom_flange_thickness = section.tf_bot + self.web_thickness = section.tw + self.top_flange_width = section.bf_top + self.bottom_flange_width = section.bf_bot + self.total_depth = section.D + self.eff_depth = section.D - section.tf_top - section.tf_bot + self.IntStiffnerwidth = min(self.top_flange_width,self.bottom_flange_width) - self.web_thickness/2 - 10 + self.end_stiffwidth = self.IntStiffnerwidth + self.c = section.c + self.IntStiffThickness = section.t_stiff + + + + #### NEW PSO ### + + def evaluate_particle_cost(self, particle, variable_list, design_dictionary, is_symmetric, is_thick_web): + sec = Section() + self.assign_particle_to_section(self,particle, variable_list, sec) + self.design_check(design_dictionary) + max_ratio, slender_ok, thickness_ok = self.design_check_optimized_version(self,design_dictionary) + + area = ((self.top_flange_thickness * self.top_flange_width) + + (self.bottom_flange_thickness * self.bottom_flange_width) + + (self.web_thickness * (self.total_depth - self.top_flange_thickness - self.bottom_flange_thickness))) + volume = area * self.length # mm³ + mass = volume * 7.85e-6 # kg + P = 1e6 # penalty coefficient (tune as needed) + penalty = 0.0 + + # Shear capacity (shear_ratio > 1.0 means failure) + if self.shear_ratio > 1.0: + penalty += (self.shear_ratio - 1.0) + + # Moment capacity (moment_ratio > 1.0 means failure) + if self.moment_ratio > 1.0: + penalty += (self.moment_ratio - 1.0) + + # Web buckling & crippling (shearchecks==False means any web failure) + if not self.shearchecks: + penalty += 1.0 + + # Deflection serviceability + if not self.defl_check: + penalty += 1.0 + + # (Optional) any other flags: e.g. slenderness or plate-thickness, + # but those are already implicit in design_check for PSO—no need to repeat. + + # 5) Return penalized objective + return mass + P * penalty + + + def optimized_method(self, design_dictionary, is_thick_web, is_symmetric): + + + variable_list = self.build_variable_structure(self,is_thick_web, is_symmetric) + lb, ub = self.get_bounds(self,variable_list) + lb = np.array(lb) + ub = np.array(ub) + + # 1) Compute normalized bounds [0…1] + lb_norm = np.zeros_like(lb) + ub_norm = np.ones_like(ub) + + # 2) Denormalize helper: map u∈[0,1]^n → x∈[lb,ub] + def denormalize(u): + return lb + u * (ub - lb) + + # 3) Wrap your existing constraint to accept u + def cons_norm(u): + x = denormalize(u) + return constraint(x) # calls your original constraint + + # 4) Wrap your existing obj_fn_single to accept u + def obj_norm(u): + x = denormalize(u) + return obj_fn_single(x) + + # 5) Generate & normalize your initial swarm + init_real = self.generate_first_particle( + self, self.length, self.load.moment, self.material.fy, + is_thick_web, is_symmetric + ) + init_norm = (init_real - lb) / (ub - lb) + + # ───────────── END ADD ───────────── + + + def constraint(particle): + sec = Section() + self.assign_particle_to_section(self,particle, variable_list, sec) + + # 2) Rebuild design inputs so checks use this particle’s geometry + design = dict(design_dictionary) + for var in variable_list: + design[var] = getattr(sec, var) + + # 3) Run your optimized capacity/deflection/slenderness check + max_ratio, slender_ok, thickness_ok = self.design_check_optimized_version(self,design) + + # 4) Grab the other ratios set as attributes + + μ_shear = getattr(self, 'shear_ratio', float('inf')) + μ_moment = getattr(self, 'moment_ratio', float('inf')) + μ_defl = getattr(self, 'deflection_ratio', float('inf')) + + # 5) Compute ε = sqrt(E/Fy) for IS800:2007 + E, Fy = self.material.modulus_of_elasticity, self.material.fy + ε = math.sqrt(E / Fy) + # 6) Extract the 4 key geometric values + depth = sec.D + + tw = sec.tw + bf_top = sec.bf_top + tf_top = sec.tf_top + bf_bot = sec.bf_bot + tf_bot = sec.tf_bot + eff_depth = sec.D - sec.tf_top - sec.tf_bot + + # 7) Compute semi-compact margins: + # flange: b_f/t_f <= 13.6·ε → (13.6 ε·t_f – b_f) ≥ 0 + # web: d/t_w <= 126·ε → (126 ε·t_w – d) ≥ 0 + + m_web = (126.0 * ε) * tw - depth + m_fl_top = max((13.6 * ε) * tf_top - bf_top, 3 * m_web) + m_fl_bot = max((13.6 * ε) * tf_bot - bf_bot, 3 * m_web) + + # 8) Build a fixed-length list of margins (negative = violate) + margins = [ + 1.0 - max_ratio, # moment capacity + m_fl_top, # top-flange slenderness + m_fl_bot, # bot-flange slenderness + m_web, # web slenderness + (1.0 if thickness_ok else -1.0), # plate thickness limits + 1.0 - μ_shear, # shear ratio + 1.0 - μ_moment, # moment ratio + 1.0 - μ_defl # deflection ratio + ] + + # (Optional) debug print to see which constraint is worst + worst = min(range(len(margins)), key=lambda i: margins[i]) + # print(f" constraint: worst margin #{worst} = {margins[worst]:.3f}") + + return margins + + def obj_fn(x): + results = [] + for particle in x: + sec = Section() + self.assign_particle_to_section(self,particle, variable_list, sec) + area = ((self.top_flange_thickness * self.top_flange_width) + + (self.bottom_flange_thickness * self.bottom_flange_width) + + (self.web_thickness * (self.total_depth - self.top_flange_thickness - self.bottom_flange_thickness))) + volume = area * self.length # mm³ + mass = volume * 7.85e-6 # kg + results.append(mass) + return np.array(results) + + # def obj_fn_single(x): + # sec = Section() + # self.assign_particle_to_section(self,x, variable_list, sec) + # area = ((self.top_flange_thickness * self.top_flange_width) + + # (self.bottom_flange_thickness * self.bottom_flange_width) + + # (self.web_thickness * (self.total_depth - self.top_flange_thickness - self.bottom_flange_thickness))) + # volume = area * self.length # mm³ + # mass = volume * 7.85e-6 # kg + # + # if self.c is None or self.t_stiff is None: + # mass_stiff = 0 + # else: + # # Number of stiffeners = length/c minus one at each end + # n_stiff = max(self.length / sec.c - 1, 0) + # # Volume of all stiffeners (mm³): thickness × width × effective depth × count + # vol_stiff = n_stiff * 2 * (min(self.top_flange_width,self.bottom_flange_width) - self.web_thickness/2 - 10) * self.t_stiff * (self.total_depth - self.top_flange_thickness - self.bottom_flange_thickness) + # mass_stiff = vol_stiff * 7.85e-6 + # mass += mass_stiff + # + # return mass + def obj_fn_single(x): + sec = Section() + self.assign_particle_to_section(self,x, variable_list, sec) + area = (sec.bf_top * sec.tf_top + + sec.bf_bot * sec.tf_bot + + sec.tw * (sec.D - sec.tf_top - sec.tf_bot)) + + volume = area * self.length # mm³ + mass = volume * 7.85e-6 # kg + + if sec.c is None or sec.t_stiff is None: + mass_stiff = 0.0 + else: + # how many stiffeners fit (minus one at each end) + n_stiff = max(self.length / sec.c - 1, 0) + + # approximate stiffener cross-section: + # 2 stiffeners per bay, width as the smaller flange minus half the web minus 10 mm clearance, + # height as the clear web depth + width_stiff = min(sec.bf_top, sec.bf_bot) - sec.tw / 2 - 10 + height_stiff = sec.D - sec.tf_top - sec.tf_bot + + vol_stiff = n_stiff * 2 * width_stiff * sec.t_stiff * height_stiff # mm³ + mass_stiff = vol_stiff * 7.85e-6 # kg + + # 4) Return total + return mass + mass_stiff + + results = [] + for run in range(5): + # Call PSO as usual + best_u, best_cost = pso( + obj_norm, + lb_norm, ub_norm, + f_ieqcons=cons_norm, + swarmsize=20, + maxiter=80, + debug=False # (set True if you want debug output ) - bending_strength_section = IS800_2007.cl_8_2_2_Unsupported_beam_bending_strength( - self.section_property.plast_sec_mod_z, - self.section_property.elast_sec_mod_z, - fcd=fbd, - section_class=self.section_class_girder - ) - - - # self.beta_b_lt = beta_b - self.alpha_lt = alpha_lt - # self.lambda_lt = lambda_lt - self.phi_lt = phi_lt - self.X_lt = X_lt - self.fbd_lt = fbd - self.lateral_tb = self.fcrb * 10**-6 - print('Inside bending_strength 2.1', fbd, self.section_property.plast_sec_mod_z ) - if self.high_shear_check: - if self.section_class_girder == "Plastic" or self.section_class_girder == "Compact": - bending_strength_section = self.bending_strength_reduction(self,Md=bending_strength_section - ) - else: - bending_strength_section = ( - self.beta_b_lt - * self.section_property.plast_sec_mod_z - * fbd - ) - print('Inside bending_strength 2',It,self.hf,self.Iw,self.fcrb ,self.beta_b_lt,alpha_lt,lambda_lt,phi_lt,X_lt,fbd,bending_strength_section) - self.bending_strength_section_reduced = bending_strength_section - return bending_strength_section - - def plate_girder_strength(self): - Flexure.plate_girder_strength(self) - def plate_girder_strength2(self): - Flexure.plate_girder_strength2(self) - def myround(x, base,type): - if type == 'high': - return base * math.ceil(x / base) - else: - return base * round(x / base) - - - def section_check_validator(self,var1,var2,var3): - if var1 == var2: - self.section_list = [True] - self.Girder_SectionProperty(self, self.designed_dict,False) # var3 = design_dictionary - check_list = [] - while var1 and (len(check_list)== 0 or all(check_list)): - self.Shear_Strength(self) - ic(check_list.append( self.checks(self,4))) - - var1 = var2 - break - - def results(self, design_dictionary): - - # sorting results from the dataset - # if len(self.input_section_list) > 1: - # results based on UR - self.common_result(self,self.section_list,"NA") + best_pos = denormalize(best_u) + results.append((best_pos, best_cost)) + + best_pos, best_cost = min(results, key=lambda x: x[1]) + #best_pos, best_cost = pso(obj_fn_single, lb, ub, f_ieqcons=constraint, swarmsize=100, maxiter=500, debug=True, init_pos=self.generate_first_particle(self,self.length, self.load.moment, self.material.fy, is_thick_web, is_symmetric)) + margins = constraint(best_pos) + best_section = Section() + self.assign_particle_to_section(self,best_pos, variable_list, best_section) + logger.info("PSO calculation successfully completed") + # print("Best cost:", best_cost) + best_design_var = dict(zip(variable_list, best_pos)) + # print("Best design variables:", best_design_var) + def ceil_to_nearest(x, multiple): + return float(math.ceil(x / multiple) * multiple) + if is_symmetric: + self.bottom_flange_thickness = self.top_flange_thickness = float(best_design_var['tf']) + for i in self.bottom_flange_thickness_list: + if float(i) > self.bottom_flange_thickness: + self.bottom_flange_thickness = float(i) + self.top_flange_thickness = float(i) + break + self.web_thickness = float(best_design_var['tw']) + for i in self.web_thickness_list: + if float(i) > self.web_thickness: + self.web_thickness = float(i) + break + + self.top_flange_width = self.bottom_flange_width = round(float(best_design_var['bf']),0) + self.top_flange_width = self.bottom_flange_width = ceil_to_nearest(self.top_flange_width,10) + self.total_depth = round(float(best_design_var['D']),0) + self.total_depth = ceil_to_nearest(self.total_depth,25) + + + # self.IntStiffThickness = float(best_design_var['']) + # for i in self.int_thickness_list: + # if float(i) > se + else: + self.bottom_flange_thickness = float(best_design_var['tf_bot']) + for i in self.bottom_flange_thickness_list: + if float(i) > self.bottom_flange_thickness: + self.bottom_flange_thickness = float(i) + break + self.top_flange_thickness = float(best_design_var['tf_top']) + for i in self.top_flange_thickness_list: + if float(i) > self.top_flange_thickness: + self.top_flange_thickness = float(i) + break + self.web_thickness = float(best_design_var['tw']) + for i in self.web_thickness_list: + if float(i) > self.web_thickness: + self.web_thickness = float(i) + break + + self.bottom_flange_width = round(float(best_design_var['bf_bot']),0) + self.bottom_flange_width = ceil_to_nearest(self.bottom_flange_width,10) + self.top_flange_width = round(float(best_design_var['bf_top']),0) + self.top_flange_width = ceil_to_nearest(self.top_flange_width,10) + self.total_depth = round(float(best_design_var['D']),0) + self.total_depth = ceil_to_nearest(self.total_depth,25) + + + if not is_thick_web: + self.IntStiffThickness = float(best_design_var['t_stiff']) + for i in self.int_thickness_list: + if float(i) > self.IntStiffThickness: + self.IntStiffThickness = float(i) + break + + self.c = round(float(best_design_var['c']),0) + self.c = ceil_to_nearest(self.c,10) + + # logger.info("NEW PSO RUNNING") + logger.info(f"Optimized values : Flange width top and bottom {self.top_flange_width} {self.bottom_flange_width} flange thickness top and bottom {self.top_flange_thickness} { self.bottom_flange_thickness} web_thickness {self.web_thickness} total depth { self.total_depth} C value {self.c} thickness stiffener { self.IntStiffThickness}") + self.design_check(self,design_dictionary) + # self.final_format(self,design_dictionary) self.design_status = True - return 0 - if self.optimization_parameter == "Utilization Ratio": - filter_UR = filter( - lambda x: x <= min(self.allowable_utilization_ratio, 1.0), - self.optimum_section_ur - ) - self.optimum_section_ur = list(filter_UR) - - self.optimum_section_ur.sort() - # print(f"self.optimum_section_ur{self.optimum_section_ur}") - # print(f"self.result_UR{self.result_UR}") - - # selecting the section with most optimum UR - if len(self.optimum_section_ur) == 0: # no design was successful - logger.warning( - "The sections selected by the solver from the defined list of sections did not satisfy the Utilization Ratio (UR) " - "criteria" - ) - logger.error( - "The solver did not find any adequate section from the defined list." - ) - logger.info( - "Re-define the list of sections or check the Design Preferences option and re-design." - ) - self.design_status = False - # self.design_status_list.append(self.design_status) + + + + # 5. Objective function + def objective_function(self,x, variable_list,design_dictionary,is_symmetric,is_thick_web): + """ + x: array of shape (n_particles, n_dimensions) + returns: 1D array of costs + """ + costs = [] + for particle in x: + sec = Section() + self.assign_particle_to_section(self,particle, variable_list, sec) + cost = self.run_design_checks(self,sec,design_dictionary,is_symmetric,is_thick_web) + costs.append(cost) + return np.array(costs) + + def run_design_checks(self,section,design_dictionary,is_symmetric,is_thick_web): + """ + Perform your area calculation + penalties here, + return a scalar cost. + """ + + if is_symmetric: + if is_thick_web: + weight = (2 * section.bf * section.tf) + (section.tw * (section.D - 2*section.tf)) * self.length * 7850 else: - self.result_UR = self.optimum_section_ur[ - -1 - ] # optimum section which passes the UR check - print(f"self.result_UR{self.result_UR}") - self.design_status = True - # self.common_result( - # self, - # list_result=self.optimum_section_ur_results, - # result_type=self.result_UR, - # ) - - else: # results based on cost - self.optimum_section_cost.sort() - - # selecting the section with most optimum cost - self.result_cost = self.optimum_section_cost[0] - self.design_status = True - - self.design_status_list.append(self.design_status) - for status in self.design_status_list: - print('status list', status) - if status is False: - self.design_status = False - break + weight = (2 * section.bf * section.tf) + (section.tw * (section.D - 2*section.tf)) * self.length * 7850 + ((self.length / section.c) - 1) * section.t_stiff * self.IntStiffnerwidth * self.eff_depth *7850 + else: + if is_thick_web: + + weight = ((section.bf_top * section.tf_top) + (section.bf_bot * section.tf_bot) + (section.tw * (section.D - section.tf_top - section.tf_bot)) ) * self.length * 7850 else: - self.design_status = True - def common_result(self, list_result, result_type, flag=1): - # self.result_designation = list_result[result_type]["Designation"] - ic() - # TODO take dictionary of most optmised output and add here - self.result_tf = self.section_property.flange_thickness - self.result_tw = self.section_property.web_thickness - self.result_dw = self.section_property.depth_web - self.result_bf = self.section_property.flange_width - self.shear_strength = self.single_section_dictionary['Shear_Strength'] + weight = ((section.bf_top * section.tf_top) + (section.bf_bot * section.tf_bot) + (section.tw * (section.D - section.tf_top - section.tf_bot)) ) * self.length * 7850 + ((self.length / section.c) - 1) * section.t_stiff * self.IntStiffnerwidth * self.eff_depth *7850 + + + + # placeholder penalty + penalty = 0 + maxiratio, slendercheck, thicknesscheck = self.design_check_optimized_version(self,design_dictionary) + + if slendercheck == False: + penalty += 1e10 + if thicknesscheck == False: + penalty += 1e10 + penalty += abs(1-maxiratio) * 1e6 + + return weight + penalty + + + + def design_check(self,design_dictionary): + self.design_flag = False + self.design_flag2 = False + self.shearflag1 = False + self.shearflag2 = False + self.shearflag3 = False + self.shearchecks = False + self.momentchecks = False + self.defl_check = False + self.long_check = False + self.design_flag = self.section_classification(self, design_dictionary) + if self.design_flag == False: + logger.error("slender section not allowed") + + else: + self.beta_value(self, design_dictionary,self.section_class) + + if self.web_philosophy == 'Thick Web without ITS': + self.design_flag2 = self.min_web_thickness_thick_web(self,self.eff_depth,self.web_thickness,self.epsilon,"no_stiffener",0) + + if self.design_flag2 == True: + + #shear check + if self.shear_capacity_laterally_supported_thick_web(self,self.material.fy,self.gamma_m0,self.total_depth,self.web_thickness,self.top_flange_thickness,self.bottom_flange_thickness): + self.shearflag1 = True + logger.info("Shear Check passed") + + else: + self.shearflag1 = False + logger.error("Shear Check failed") + + + #web buckling check + if self.web_buckling_laterally_supported_thick_web(self,self.material.fy,self.gamma_m0,self.total_depth,self.web_thickness,self.top_flange_thickness,self.bottom_flange_thickness,self.material.modulus_of_elasticity,self.b1): + self.shearflag2 = True + logger.info("Web Buckling Check passed") + else: + self.shearflag2 = False + logger.error("Web Buckling Check failed") + + #web crippling check + if self.web_crippling_laterally_supported_thick_web(self,self.material.fy,self.gamma_m0,self.web_thickness,self.top_flange_thickness,self.b1): + self.shearflag3 = True + logger.info("Web Crippling Check passed") + else: + self.shearflag3 = False + logger.error("Web Crippling Check failed") + + if self.shearflag1 == True and self.shearflag2 == True and self.shearflag3 == True: + self.shearchecks = True + else: + self.shearchecks = False + + #support type supp or unsupp + if self.support_type == 'Major Laterally Supported': + + #moment check supp + if self.moment_capacity_laterally_supported(self,self.load.shear_force,self.plast_sec_mod_z,self.elast_sec_mod_z,self.material.fy,self.gamma_m0,self.total_depth,self.web_thickness,self.top_flange_thickness,self.bottom_flange_thickness,self.section_class): + self.momentchecks = True + logger.info("Moment Check passed") + else: + self.momentchecks = False + logger.error("Moment Check failed") + + else: #unsupp + + #moment check unspp + if self.moment_capacity_laterally_unsupported(self,self.material.modulus_of_elasticity,self.effective_length,self.total_depth,self.top_flange_thickness,self.bottom_flange_thickness,self.top_flange_width,self.bottom_flange_width,self.web_thickness,self.loading_case,self.gamma_m0,self.material.fy,self.load.shear_force): + # print("M", self.Md) + self.momentchecks = True + logger.info("Moment Check passed") + else: + self.momentchecks = False + # print("M", self.Md) + logger.error("Moment Check failed") + else: + logger.error("Increase the web thickness") + + else: #thin web condition + self.shear_ratio= 0 + if self.long_Stiffner == 'Yes and 1 stiffener': + self.stiffener_type = "transverse_and_one_longitudinal_compression" + elif self.long_Stiffner == 'Yes and 2 stiffeners': + self.stiffener_type = "transverse_and_two_longitudinal_neutral" + else: + self.stiffener_type = "transverse_only" + if self.stiffener_type != "transverse_only": + second_stiffener = False + if self.stiffener_type == "transverse_and_two_longitudinal_neutral": + second_stiffener = True + if self.design_longitudinal_stiffeners(self, self.eff_depth, self.web_thickness, self.c,self.epsilon, second_stiffener): + logger.info("Longitudinal Stiffener Check passed") + else: + logger.error("Longitudinal Stiffener Check failed") - try: - self.result_shear = self.shear_strength - self.result_bending = "NA" - except: - self.result_shear = "NA" - self.result_bending = "NA" - - def list_changer(self, change, list,list_name, check = True): - list_name.extend([ - "Designation"]) - list.extend( - [self.result_tf, - self.result_tw, - self.result_dw, - self.result_bf]) - list_name.extend([ - "Mfd", - "Beta_reduced", - 'M_d' - ]) - - ### start writing save_design from here! - def save_design(self, popup_summary): + if self.c == 'NA': + logger.error("c value not provided") + self.c = 0 + else: + self.c = float(self.c) + # print("c value",self.c) + self.design_flag2 = self.min_web_thickness_thick_web(self,self.eff_depth,self.web_thickness,self.epsilon,self.stiffener_type,self.c) + if self.design_flag2 == True: + self.x= design_dictionary[KEY_ShearBucklingOption] + # print("shear buckling option",self.x) + + if design_dictionary[KEY_ShearBucklingOption] == 'Simple Post Critical': + #shear check + if self.shear_buckling_check_simple_postcritical(self,self.eff_depth,self.total_depth,self.top_flange_thickness,self.bottom_flange_thickness,self.web_thickness,self.load.shear_force,self.c): + self.shearflag1 = True + logger.info("Shear Check passed") + else: + logger.info("Shear Check Failed, add end stiffeners") + if self.end_panel_stiffener_calc(self, self.top_flange_width, self.bottom_flange_width, + self.web_thickness, self.end_stiffthickness, + self.material.fy, self.gamma_m0, self.eff_depth, + self.top_flange_thickness, self.total_depth, + self.effective_length, self.bottom_flange_thickness, + self.material.modulus_of_elasticity, self.epsilon, self.c): + logger.info("End Panel Stiffener Check passed") + else: + logger.error("End Panel Stiffener Check failed") + + if self.shear_buckling_check_intermediate_stiffener(self,self.eff_depth,self.web_thickness,self.c,self.epsilon,self.IntStiffThickness,self.IntStiffnerwidth,self.load.shear_force,self.gamma_m0,self.material.fy,self.material.modulus_of_elasticity): + self.shearflag2 = True + logger.info("Shear Buckling Check passed with intermediate stiffeners") + else: + self.shearflag2 = False + logger.error("Shear Buckling Check failed with intermediate stiffeners, increase stiffener thickness") + + else: #tension field + + if self.shear_buckling_check_tension_field(self,self.eff_depth,self.total_depth,self.top_flange_thickness,self.bottom_flange_thickness,self.web_thickness,self.c): + self.shearflag1 = True + logger.info("Shear Buckling Check passed") + else: + + logger.error("Shear Buckling Check failed, provide end panel stiffeners") + if self.tension_field_end_stiffener(self, self.eff_depth, self.web_thickness, self.material.fy, + self.load.shear_force, self.load.moment, + self.c): + self.shearflag1 = True + logger.info("Tension Field Check passed with stiffeners") + else: + self.shearflag1 = False + logger.error("Tension Field Check failed, increase stiffener thickness") + + if self.tension_field_intermediate_stiffener(self,self.eff_depth, self.web_thickness, self.c, self.epsilon, self.IntStiffThickness, self.IntStiffnerwidth, self.load.shear_force, self.gamma_m0, self.material.fy, self.material.modulus_of_elasticity): + self.shearflag2 = True + logger.info("Shear Buckling Check passed with intermediate stiffeners") + else: + self.shearflag2 = False + logger.error("Shear Buckling Check failed, increase stiffener thickness") + + if self.shearflag1 == True and self.shearflag2 == True: + self.shearchecks = True + else: + self.shearchecks = False + + + if self.support_type == 'Major Laterally Supported': + #moment check supp + if self.moment_capacity_laterally_supported(self,self.load.shear_force,self.plast_sec_mod_z,self.elast_sec_mod_z,self.material.fy,self.gamma_m0,self.total_depth,self.web_thickness,self.top_flange_thickness,self.bottom_flange_thickness,self.section_class): + self.momentchecks = True + logger.info("Moment Check passed") + else: + self.momentchecks = False + logger.error("Moment Check failed") + + else: #unsupp + + #moment check unspp + if self.moment_capacity_laterally_unsupported(self,self.material.modulus_of_elasticity,self.effective_length,self.total_depth,self.top_flange_thickness,self.bottom_flange_thickness,self.top_flange_width,self.bottom_flange_width,self.web_thickness,self.loading_case,self.gamma_m0,self.material.fy,self.load.shear_force): + self.momentchecks = True + logger.info("Moment Check passed") + else: + self.momentchecks = False + logger.error("Moment Check failed") + + #end panel stiffener checks + # if self.end_panel_stiffener_calc(self, self.top_flange_width, self.bottom_flange_width, self.web_thickness, self.intstiffener_thk, self.material.fy, self.gamma_m0, self.eff_depth, self.top_flange_thickness, self.total_depth, self.effective_length, self.bottom_flange_thickness, self.material.modulus_of_elasticity, self.epsilon): + # if self.end_panel_stiffener_calc(self, self.top_flange_width, self.bottom_flange_width, self.web_thickness, self.end_stiffthickness, self.material.fy, self.gamma_m0, self.eff_depth, self.top_flange_thickness, self.total_depth, self.effective_length, self.bottom_flange_thickness, self.material.modulus_of_elasticity, self.epsilon, self.c): + # logger.info("End Panel Stiffener Check passed") + # else: + # logger.error("End Panel Stiffener Check failed") + + + + + #deflection checks + if self.evaluate_deflection_kNm_mm(self,self.load.moment, self.length, self.material.modulus_of_elasticity, self.loading_case, self.deflection_criteria): + self.defl_check = True + logger.info("Deflection Check passed") + else: + self.defl_check = False + logger.error("Deflection Check failed") + + #in pso check for self.moment_checks and self.shearchecks + + #for customized + if self.design_flag == True and self.design_flag2 == True and self.defl_check == True: + pass + self.final_format(self,design_dictionary) + + def design_check_optimized_version(self,design_dictionary): + self.design_flag = False + self.design_flag2 = False + self.shearflag1 = False + self.shearflag2 = False + self.shearflag3 = False + self.shearchecks = False + self.momentchecks = False + self.defl_check = False + self.long_check = False + self.design_flag = self.section_classification(self, design_dictionary) + #print('DEISGN FLAG',self.design_flag) + if self.design_flag == False: + pass + # logger.error("slender section not allowed") + + else: + self.beta_value(self, design_dictionary,self.section_class) + + if self.web_philosophy == 'Thick Web without ITS': + # print('THICK WEB') + self.design_flag2 = self.min_web_thickness_thick_web(self,self.eff_depth,self.web_thickness,self.epsilon,"no_stiffener",0) + + if self.design_flag2 == True: + + #shear check + if self.shear_capacity_laterally_supported_thick_web(self,self.material.fy,self.gamma_m0,self.total_depth,self.web_thickness,self.top_flange_thickness,self.bottom_flange_thickness): + self.shearflag1 = True + # logger.info("Shear Check passed") + + else: + self.shearflag1 = False + # logger.error("Shear Check failed") + + + #web buckling check + if self.web_buckling_laterally_supported_thick_web(self,self.material.fy,self.gamma_m0,self.total_depth,self.web_thickness,self.top_flange_thickness,self.bottom_flange_thickness,self.material.modulus_of_elasticity,self.b1): + self.shearflag2 = True + # logger.info("Web Buckling Check passed") + else: + self.shearflag2 = False + # logger.error("Web Buckling Check failed") + + #web crippling check + if self.web_crippling_laterally_supported_thick_web(self,self.material.fy,self.gamma_m0,self.web_thickness,self.top_flange_thickness,self.b1): + self.shearflag3 = False + # logger.info("Web Crippling Check passed") + else: + self.shearflag3 = False + # logger.error("Web Crippling Check failed") + + if self.shearflag1 == True and self.shearflag2 == True and self.shearflag3 == True: + self.shearchecks = True + else: + self.shearchecks = False + + #support type supp or unsupp + if self.support_type == 'Major Laterally Supported': + + #moment check supp + if self.moment_capacity_laterally_supported(self,self.load.shear_force,self.plast_sec_mod_z,self.elast_sec_mod_z,self.material.fy,self.gamma_m0,self.total_depth,self.web_thickness,self.top_flange_thickness,self.bottom_flange_thickness,self.section_class): + self.momentchecks = True + # logger.info("Moment Check passed") + else: + self.momentchecks = False + # logger.error("Moment Check failed") + + else: #unsupp + + #moment check unspp + if self.moment_capacity_laterally_unsupported(self,self.material.modulus_of_elasticity,self.effective_length,self.total_depth,self.top_flange_thickness,self.bottom_flange_thickness,self.top_flange_width,self.bottom_flange_width,self.web_thickness,self.loading_case,self.gamma_m0,self.material.fy,self.load.shear_force): + self.momentchecks = True + # logger.info("Moment Check passed") + else: + self.momentchecks = False + # logger.error("Moment Check failed") + else: + # logger.error("Increase the web thickness") + pass + + else: #thin web condition + self.shear_ratio = 0 + if self.long_Stiffner == 'Yes and 1 stiffener': + self.stiffener_type = "transverse_and_one_longitudinal_compression" + elif self.long_Stiffner == 'Yes and 2 stiffeners': + self.stiffener_type = "transverse_and_two_longitudinal_neutral" + else: + self.stiffener_type = "transverse_only" + if self.stiffener_type != "transverse_only": + second_stiffener = False + if self.stiffener_type == "transverse_and_two_longitudinal_neutral": + second_stiffener = True + if self.design_longitudinal_stiffeners(self, self.eff_depth, self.web_thickness, self.c, + self.epsilon, second_stiffener): + #logger.info("Longitudinal Stiffener Check passed") + self.long_check = True + else: + #logger.error("Longitudinal Stiffener Check failed") + self.long_check = False + + if self.c == 'NA': + # logger.error("c value not provided") + self.c = 0 + else: + self.c = float(self.c) + self.design_flag2 = self.min_web_thickness_thick_web(self,self.eff_depth,self.web_thickness,self.epsilon,self.stiffener_type,self.c) + # print('DESIGN FLAG2',self.design_flag2) + if self.design_flag2 == True: + + if design_dictionary[KEY_ShearBucklingOption] == 'Simple Post Critical': + #shear check + if self.shear_buckling_check_simple_postcritical(self,self.eff_depth,self.total_depth,self.top_flange_thickness,self.bottom_flange_thickness,self.web_thickness,self.load.shear_force,self.c): + self.shearflag1 = True + + # logger.info("Shear Check passed") + else: + + if self.end_panel_stiffener_calc(self, self.top_flange_width, self.bottom_flange_width, + self.web_thickness, self.end_stiffthickness, + self.material.fy, self.gamma_m0, self.eff_depth, + self.top_flange_thickness, self.total_depth, + self.effective_length, self.bottom_flange_thickness, + self.material.modulus_of_elasticity, self.epsilon, self.c): + self.shearflag1 = True + else: + + self.shearflag1 = False + # logger.error("End Panel Stiffener Check failed") + + if self.shear_buckling_check_intermediate_stiffener(self,self.eff_depth,self.web_thickness,self.c,self.epsilon,self.IntStiffThickness,self.IntStiffnerwidth,self.load.shear_force,self.gamma_m0,self.material.fy,self.material.modulus_of_elasticity): + self.shearflag2 = True + + # logger.info("Shear Buckling Check passed"). + else: + + self.shearflag2 = False + # logger.error("Shear Buckling Check failed") + + else: #tension field + + if self.shear_buckling_check_tension_field(self,self.eff_depth,self.total_depth,self.top_flange_thickness,self.bottom_flange_thickness,self.web_thickness,self.c): + self.shearflag1 = True + # logger.info("Shear Buckling Check passed") + else: + if self.tension_field_end_stiffener(self, self.eff_depth, self.web_thickness, self.material.fy, + self.load.shear_force, self.load.moment, + self.c): + self.shearflag1 = True + else: + self.shearflag1 = False + # logger.error("Tension Field Check failed, increase stiffener thickness") + if self.tension_field_intermediate_stiffener(self, self.eff_depth, self.web_thickness, self.c, + self.epsilon, self.IntStiffThickness, + self.IntStiffnerwidth, self.load.shear_force, + self.gamma_m0, self.material.fy, + self.material.modulus_of_elasticity): + self.shearflag2 = True + else: + self.shearflag2 = False + + if self.shearflag1 == True and self.shearflag2 == True: + self.shearchecks = True + else: + self.shearchecks = False - self.report_input = \ - {#KEY_MAIN_MODULE: self.mainmodule, - KEY_MODULE: self.module, #"Axial load on column " - } + # support type supp or unsupp + if self.support_type == 'Major Laterally Supported': + #moment check supp + if self.moment_capacity_laterally_supported(self,self.load.shear_force,self.plast_sec_mod_z,self.elast_sec_mod_z,self.material.fy,self.gamma_m0,self.total_depth,self.web_thickness,self.top_flange_thickness,self.bottom_flange_thickness,self.section_class): + self.momentchecks = True + + # logger.info("Moment Check passed") + else: + self.momentchecks = False + + # logger.error("Moment Check failed") + + else: #unsupp + + #moment check unspp + if self.moment_capacity_laterally_unsupported(self,self.material.modulus_of_elasticity,self.effective_length,self.total_depth,self.top_flange_thickness,self.bottom_flange_thickness,self.top_flange_width,self.bottom_flange_width,self.web_thickness,self.loading_case,self.gamma_m0,self.material.fy,self.load.shear_force): + self.momentchecks = True + + # logger.info("Moment Check passed") + else: + self.momentchecks = False + + # logger.error("Moment Check failed") + + + + + + else: + # logger.error("Increase the web thickness") + pass - print(sys.path[0]) - rel_path = str(sys.path[0]) - rel_path = os.path.abspath(".") # TEMP - rel_path = rel_path.replace("\\", "/") - fname_no_ext = popup_summary['filename'] - CreateLatex.save_latex(CreateLatex(), self.report_input, self.report_check, popup_summary, fname_no_ext, - rel_path, [], '', module=self.module) # + + + #deflection checks + if self.evaluate_deflection_kNm_mm(self,self.load.moment, self.length, self.material.modulus_of_elasticity, self.loading_case, self.deflection_criteria): + self.defl_check = True + # logger.info("Deflection Check passed") + else: + self.defl_check = False + # logger.error("Deflection Check failed")d + + #in pso check for self.moment_checks and self.shearchecks + + #for customized + # print(f"RATIOS moment {self.moment_ratio} shear {self.shear_ratio} deflection {self.deflection_ratio}") + return max(self.moment_ratio,self.shear_ratio,self.deflection_ratio),self.design_flag,self.design_flag2 + + + def optimized_method_working(self,design_dictionary,is_thick_web, is_symmetric): + # is_thick_web = False + # is_symmetric = False + # if self.web_philosophy == 'Thick Web without ITS': + # is_thick_web = True + # else: + # is_thick_web = False + # if design_dictionary[KEY_IS_IT_SYMMETRIC] == 'Symmetric Girder': + # is_symmetric = True + # else: + # is_symmetric = False + variable_list = self.build_variable_structure(self,is_thick_web, is_symmetric) + lb, ub = self.get_bounds(self,variable_list) + optimizer = GlobalBestPSO( + n_particles=50, + dimensions=len(variable_list), + options={'c1': 1.5, 'c2': 1.5, 'w': 0.4}, + bounds=(lb, ub) + ) + + fp = self.generate_first_particle(self,float(self.length) * 1000, float(self.load.moment), float(self.material.fy),is_thick_web,is_symmetric) + optimizer.swarm.position[0] = np.clip(fp, lb, ub) + + + best_cost, best_pos = optimizer.optimize( + objective_func=lambda swarm: self.objective_function(self,swarm, variable_list,design_dictionary,is_symmetric,is_thick_web), + iters=100 + ) + + logger.info("PSO calculation successfully completed") + # print("Best cost:", best_cost) + best_design_var = dict(zip(variable_list, best_pos)) + # print("Best design variables:", best_design_var) + def ceil_to_nearest(x, multiple): + return float(math.ceil(x / multiple) * multiple) + if is_symmetric: + self.bottom_flange_thickness = self.top_flange_thickness = float(best_design_var['tf']) + for i in self.bottom_flange_thickness_list: + if float(i) > self.bottom_flange_thickness: + self.bottom_flange_thickness = float(i) + self.top_flange_thickness = float(i) + break + self.web_thickness = float(best_design_var['tw']) + for i in self.web_thickness_list: + if float(i) > self.web_thickness: + self.web_thickness = float(i) + break + + self.top_flange_width = self.bottom_flange_width = round(float(best_design_var['bf']),0) + self.top_flange_width = self.bottom_flange_width = ceil_to_nearest(self.top_flange_width,25) + self.total_depth = round(float(best_design_var['D']),0) + self.total_depth = ceil_to_nearest(self.total_depth,25) + + + # self.IntStiffThickness = float(best_design_var['']) + # for i in self.int_thickness_list: + # if float(i) > se + else: + self.bottom_flange_thickness = float(best_design_var['tf_bot']) + for i in self.bottom_flange_thickness_list: + if float(i) > self.bottom_flange_thickness: + self.bottom_flange_thickness = float(i) + break + self.top_flange_thickness = float(best_design_var['tf_top']) + for i in self.top_flange_thickness_list: + if float(i) > self.top_flange_thickness: + self.top_flange_thickness = float(i) + break + self.web_thickness = float(best_design_var['tw']) + for i in self.web_thickness_list: + if float(i) > self.web_thickness: + self.web_thickness = float(i) + break + + self.bottom_flange_width = round(float(best_design_var['bf_bot']),0) + self.bottom_flange_width = ceil_to_nearest(self.bottom_flange_width,25) + self.top_flange_width = round(float(best_design_var['bf_top']),0) + self.top_flange_width = ceil_to_nearest(self.top_flange_width,25) + self.total_depth = round(float(best_design_var['D']),0) + self.total_depth = ceil_to_nearest(self.total_depth,25) + + + if not is_thick_web: + self.IntStiffThickness = float(best_design_var['t_stiff']) + for i in self.int_thickness_list: + if float(i) > self.IntStiffThickness: + self.IntStiffThickness = float(i) + break + + self.c = round(float(best_design_var['c']),0) + self.c = ceil_to_nearest(self.c,25) + # print('vdfgbdfhb') + + logger.info(f"Optimized values : Flange width top and bottom {self.top_flange_width} {self.bottom_flange_width} flange thickness top and bottom {self.top_flange_thickness} { self.bottom_flange_thickness} web_thickness {self.web_thickness} total depth { self.total_depth} C value {self.c} thickness stiffener { self.IntStiffThickness}") + + self.design_check(self,design_dictionary) + + + + # # logger.info(f"Web Thickness: {self.web_thickness}, Flange Thickness Top: {self.top_flange_thickness}, Flange Width Top: {self.top_flange_width}, Total Depth: {self.total_depth}") + + + + + + + + + + + def final_format(self,design_dictionary): + + self.result_designation = (str(int(self.total_depth)) + " x " +str(int(self.web_thickness)) + " x " +str(int(self.bottom_flange_width)) + " x " +str(int(self.bottom_flange_thickness)) + " x " +str(int(self.top_flange_width)) + " x " +str(int(self.top_flange_thickness))) + if self.moment_ratio == None: + self.moment_ratio = 0 + if self.shear_ratio == None: + self.shear_ratio = 0 + # if self.deflection_ratio == None: + # self.deflection_ratio = 0 + # if self.web_buckling_ratio == None: + # self.web_buckling_ratio = 0 + # if self.web_crippling_ratio == None: + # self.web_crippling_ratio = 0 + # print("RATIOS",'moment ratio', self.moment_ratio, 'shear ratio', self.shear_ratio, 'deflection ratio', self.deflection_ratio) + # print(self.moment_ratio, self.shear_ratio) + self.result_UR = max(self.moment_ratio,self.shear_ratio, self.deflection_ratio) + self.section_classification_val = self.section_class + if self.beta_b_lt == None: + self.beta_b_lt = 0 + self.betab = round(self.beta_b_lt,2) + self.effectivearea = Unsymmetrical_I_Section_Properties.calc_area(self,self.total_depth, self.top_flange_width, self.bottom_flange_width, self.web_thickness, self.top_flange_thickness, self.bottom_flange_thickness)/100 + if self.Md == None: + self.Md = 0 + + if self.M_cr == None: + self.M_cr = 0 + if self.V_cr == None: + self.V_cr = 0 + if self.It == None: + self.It = 0 + if self.Iw == None: + self.Iw = 0 + + if self.shear_type == 'Low': + self.design_moment = round(self.Md/1000000,1) + else: + self.design_moment = round(self.Md/1000000,1) + if self.support_type == 'Major Laterally Unsupported': + self.critical_moment = round(self.M_cr/1000000,1) + self.torsion_cnst = round(self.It/10000,1) + self.warping_cnst = round(self.Iw/1000000,1) + self.intstiffener_thk = self.IntStiffThickness + self.longstiffener_thk = self.LongStiffThickness + self.longstiffener_no = 0 + if self.long_Stiffner == 'Yes and 1 stiffener': + self.longstiffener_no = 1 + elif self.long_Stiffner == 'Yes and 2 stiffeners': + self.longstiffener_no = 2 + self.intstiffener_spacing = self.c + self.end_panel_stiffener_thickness = self.end_stiffthickness + self.atop= 0 + self.abot= 0 + self.weld_stiff= None + self.atop, self.abot= self.design_welds_with_strength_web_to_flange(self, self.load.shear_force, self.top_flange_width, self.top_flange_thickness, self.bottom_flange_width, self.bottom_flange_thickness, self.web_thickness, self.eff_depth, [self.material.fu]) + self.weld_stiff = self.weld_for_end_stiffener(self, self.end_stiffthickness, self.end_stiffwidth, self.load.shear_force, self.V_d, self.total_depth, self.top_flange_thickness, self.bottom_flange_thickness, self.web_thickness, [self.material.fu]) + self.design_status = True + + def save_design(self, popup_summary): + # print("\n\n\n\n Enterend save design") + logger.info(" :=========Start Of design Saving Button pressed===========") + +class Section: + def __init__(self): + self.tf = self.tw = self.bf = self.D = self.tf_top = self.tf_bot = self.bf_top = self.bf_bot = self.c = self.t_stiff = None + # ... add other properties as needed + + #-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + #-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + + +def pso(func, lb, ub, ieqcons=[], f_ieqcons=None, args=(), kwargs={}, + swarmsize=600, omega=0.5, phip=0.5, phig=0.5, maxiter=1000, + minstep=1e-8, minfunc=1e-8, debug=False): + assert len(lb) == len(ub) + lb = np.array(lb) + ub = np.array(ub) + vhigh = np.abs(ub - lb) + vlow = -vhigh + + obj = lambda x: func(x, *args, **kwargs) + if f_ieqcons is None: + cons = (lambda x: np.array([0])) if not len(ieqcons) \ + else (lambda x: np.array([y(x, *args, **kwargs) for y in ieqcons])) + else: + cons = lambda x: np.array(f_ieqcons(x, *args, **kwargs)) + + def is_feasible(x, eps=1e-12): + cons_val = cons(x) + # print(f'Constraint values: {cons_val}') + return np.all(cons_val >= -eps) # strictly >=0; small epsilon for numeric tolerance + + # Helper: generate a feasible position + def random_feasible_point(): + for _ in range(10000): + candidate = lb + np.random.rand(len(lb)) * (ub - lb) + if is_feasible(candidate): + return candidate + raise RuntimeError("Cannot find feasible initial particle!") + + # Initialize + S, D = swarmsize, len(lb) + x = np.zeros((S, D)) + v = np.zeros_like(x) + p = np.zeros_like(x) + fp = np.full(S, np.inf) + g = None + fg = np.inf + + # Feasible initialization + for i in range(S): + x[i, :] = random_feasible_point() + p[i, :] = x[i, :].copy() + fp[i] = obj(p[i, :]) + if i == 0 or (fp[i] < fg and is_feasible(p[i, :])): + g = p[i, :].copy() + fg = fp[i] + v[i, :] = vlow + np.random.rand(D) * (vhigh - vlow) + + # Main loop + it = 1 + while it <= maxiter: + rp = np.random.uniform(size=(S, D)) + rg = np.random.uniform(size=(S, D)) + for i in range(S): + v[i, :] = omega * v[i, :] + phip * rp[i, :] * (p[i, :] - x[i, :]) + phig * rg[i, :] * (g - x[i, :]) + x[i, :] = x[i, :] + v[i, :] + + # Project to bounds + x[i, :] = np.clip(x[i, :], lb, ub) + + # Ensure feasibility + if not is_feasible(x[i, :]): + # Option 1: resample until feasible + x[i, :] = random_feasible_point() + # Option 2 (alternative): reflect or repair (optional) + + fx = obj(x[i, :]) + + # Personal best update + if is_feasible(x[i, :]) and (fx < fp[i] or not is_feasible(p[i, :])): + p[i, :] = x[i, :].copy() + fp[i] = fx + + # Global best update + if fx < fg or not is_feasible(g): + if debug: + # print(f'New best for swarm at iteration {it}: {x[i, :]} {fx}') + pass + tmp = x[i, :].copy() + stepsize = np.sqrt(np.sum((g - tmp) ** 2)) if g is not None else np.inf + if np.abs(fg - fx) <= minfunc: + # print(f'Stopping search: Swarm best objective change less than {minfunc}') + return tmp, fx + elif stepsize <= minstep: + # print(f'Stopping search: Swarm best position change less than {minstep}') + return tmp, fx + else: + g = tmp.copy() + fg = fx + if debug: + # print(f'Best after iteration {it}: {g} {fg}') + pass + it += 1 + + # print(f'Stopping search: maximum iterations reached --> {maxiter}') + if not is_feasible(g): + # print("However, the optimization couldn't find a feasible design. Sorry") + pass + return g, fg \ No newline at end of file diff --git a/src/osdag/design_type/tension_member/tension_bolted.py b/src/osdag/design_type/tension_member/tension_bolted.py index a8e21089f..0376cea9b 100644 --- a/src/osdag/design_type/tension_member/tension_bolted.py +++ b/src/osdag/design_type/tension_member/tension_bolted.py @@ -590,7 +590,7 @@ def output_values(self, flag): t6 = (KEY_SLENDER, KEY_DISP_SLENDER, TYPE_TEXTBOX, self.section_size_1.slenderness if flag else '', True) out_list.append(t6) - + t7 = (KEY_EFFICIENCY, KEY_DISP_EFFICIENCY, TYPE_TEXTBOX, self.efficiency if flag else '', True) out_list.append(t7) @@ -1651,7 +1651,7 @@ def member_check(self,design_dictionary): self.section_size_1.tension_capacity_calc(self.section_size_1.tension_yielding_capacity,self.section_size_1.tension_rupture_capacity,self.section_size_1.block_shear_capacity_axial) self.member_recheck(self, design_dictionary) - def member_recheck(self,design_dictionary): + def member_recheck(self,design_dictionary): "Comparing applied force and tension capacity and if falsed, it return to initial member selection which selects member of higher area" diff --git a/src/osdag/gui/UI_DESIGN_PREFERENCE.py b/src/osdag/gui/UI_DESIGN_PREFERENCE.py index c695c3e49..2e70e80b6 100644 --- a/src/osdag/gui/UI_DESIGN_PREFERENCE.py +++ b/src/osdag/gui/UI_DESIGN_PREFERENCE.py @@ -1684,4 +1684,4 @@ def close_designPref(self): # def closeEvent(self, QCloseEvent): # self.save_designPref_para() - # QCloseEvent.accept() + # QCloseEvent.accept() \ No newline at end of file diff --git a/src/osdag/gui/popup_customized_design_pref.py b/src/osdag/gui/popup_customized_design_pref.py new file mode 100644 index 000000000..8046a2319 --- /dev/null +++ b/src/osdag/gui/popup_customized_design_pref.py @@ -0,0 +1,173 @@ + +from PyQt5 import QtCore, QtWidgets +from PyQt5.QtWidgets import QDialog, QListWidget, QListWidgetItem +from PyQt5.QtWidgets import ( + QDialog, QLabel, QLineEdit, QPushButton, QFormLayout, + QApplication, QMessageBox +) +from PyQt5.QtGui import QFont +from PyQt5.QtCore import Qt +import re +import sys +scale = 1 # For resizing components +class My_ListWidget(QListWidget): + def addItems(self, Iterable, p_str=None): + super().addItems(Iterable) + self.sortItems() + + def addItem(self, *__args): + super().addItem(My_ListWidgetItem(__args[0])) + self.sortItems() + +class My_ListWidgetItem(QListWidgetItem): + def __lt__(self, other): + try: + self_text = str(re.sub("[^0-9.]", "", self.text())) + other_text = str(re.sub("[^0-9.]", "", other.text())) + return float(self_text) < float(other_text) + except Exception: + return super().__lt__(other) + +class PopupDialog(QDialog): + def __init__(self, disabled_values=[], note="", parent=None): + super().__init__(parent) + self.disabled_values = disabled_values + self.note = note + self.setWindowTitle("Customized") + self.resize(int(scale*540), int(scale*470)) + self.init_ui() + self.set_styles() + + def init_ui(self): + self.label = QtWidgets.QLabel("Available:", self) + self.label.setGeometry(QtCore.QRect(20, 20, 150, 30)) + + self.label_2 = QtWidgets.QLabel("Selected:", self) + self.label_2.setGeometry(QtCore.QRect(int(scale * 320), 20, 150, 30)) + + self.listWidget = My_ListWidget(self) + self.listWidget.setGeometry(QtCore.QRect(20, 50, int(scale*180), int(scale*300))) + self.listWidget.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) + self.listWidget.itemDoubleClicked.connect(self.move_to_selected) + + self.listWidget_2 = My_ListWidget(self) + self.listWidget_2.setGeometry(QtCore.QRect(int(scale*320), 50, int(scale*180), int(scale*300))) + self.listWidget_2.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) + self.listWidget_2.itemDoubleClicked.connect(self.move_to_available) + + self.pushButton = QtWidgets.QPushButton(">>", self) + self.pushButton.setGeometry(QtCore.QRect(int(scale*225), int(scale*140), int(scale*70), int(scale*30))) + + self.pushButton_2 = QtWidgets.QPushButton(">", self) + self.pushButton_2.setGeometry(QtCore.QRect(int(scale*225), int(scale*180), int(scale*70), int(scale*30))) + + self.pushButton_3 = QtWidgets.QPushButton("<", self) + self.pushButton_3.setGeometry(QtCore.QRect(int(scale*225), int(scale*220), int(scale*70), int(scale*30))) + + self.pushButton_4 = QtWidgets.QPushButton("<<", self) + self.pushButton_4.setGeometry(QtCore.QRect(int(scale*225), int(scale*260), int(scale*70), int(scale*30))) + + self.pushButton_5 = QtWidgets.QPushButton("Submit", self) + self.pushButton_5.setGeometry(QtCore.QRect(int(scale*190), int(scale*400), int(scale*140), int(scale*35))) + self.pushButton_5.setDefault(True) + + self.pushButton.clicked.connect(self.move_all_to_selected) + self.pushButton_2.clicked.connect(self.move_selected_to_selected) + self.pushButton_3.clicked.connect(self.move_selected_to_available) + self.pushButton_4.clicked.connect(self.move_all_to_available) + self.pushButton_5.clicked.connect(self.accept) + + self.listWidget.itemSelectionChanged.connect(self.update_buttons_status) + self.listWidget_2.itemSelectionChanged.connect(self.update_buttons_status) + + self.update_buttons_status() + + def update_buttons_status(self): + self.pushButton_2.setDisabled(not bool(self.listWidget.selectedItems())) + self.pushButton_3.setDisabled(not bool(self.listWidget_2.selectedItems())) + + def move_selected_to_selected(self): + for item in self.listWidget.selectedItems(): + self.listWidget_2.addItem(item.text()) + for item in self.listWidget.selectedItems(): + self.listWidget.takeItem(self.listWidget.row(item)) + + def move_selected_to_available(self): + for item in self.listWidget_2.selectedItems(): + self.listWidget.addItem(item.text()) + for item in self.listWidget_2.selectedItems(): + self.listWidget_2.takeItem(self.listWidget_2.row(item)) + + def move_all_to_selected(self): + while self.listWidget.count() > 0: + self.listWidget_2.addItem(self.listWidget.takeItem(0).text()) + + def move_all_to_available(self): + while self.listWidget_2.count() > 0: + self.listWidget.addItem(self.listWidget_2.takeItem(0).text()) + + def move_to_selected(self, item): + self.listWidget_2.addItem(item.text()) + self.listWidget.takeItem(self.listWidget.row(item)) + + def move_to_available(self, item): + self.listWidget.addItem(item.text()) + self.listWidget_2.takeItem(self.listWidget_2.row(item)) + + def get_selected_items(self): + return [self.listWidget_2.item(i).text() for i in range(self.listWidget_2.count())] + + def set_styles(self): + brown = "#925a5b" + grey = "#8e8e8e" + white = "#ffffff" + + button_style = f""" + QPushButton {{ + background-color: {brown}; + color: {white}; + border-radius: 6px; + font-size: 22px; + padding: 6px 18px; + border: none; + }} + QPushButton:disabled {{ + background-color: {grey}; + color: {white}; + }} + """ + for btn in [self.pushButton, self.pushButton_2, self.pushButton_3, self.pushButton_4, self.pushButton_5]: + btn.setStyleSheet(button_style) + + list_item_style = """ + QListWidget::item { + font-size: 24px; + color: black; + margin: 2px 0px; + } + """ + scrollbar_style = f""" + QScrollBar:vertical {{ + border: none; + background: #f5f5f5; + width: 12px; + border-radius: 6px; + }} + QScrollBar::handle:vertical {{ + background: {grey}; + min-height: 20px; + border-radius: 6px; + }} + QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {{ + background: none; + height: 0px; + }} + QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {{ + background: none; + }} + QScrollBar:horizontal {{ + height: 0px; + }} + """ + self.listWidget.setStyleSheet(list_item_style + scrollbar_style) + self.listWidget_2.setStyleSheet(list_item_style + scrollbar_style) \ No newline at end of file diff --git a/src/osdag/gui/popup_display_pg.py b/src/osdag/gui/popup_display_pg.py new file mode 100644 index 000000000..03f4b21ec --- /dev/null +++ b/src/osdag/gui/popup_display_pg.py @@ -0,0 +1,45 @@ +from PyQt5.QtWidgets import ( + QDialog, QVBoxLayout, QLabel, QApplication +) +from PyQt5.QtGui import QFont +from PyQt5.QtCore import Qt +import sys + + +class AvailableThicknessDialog(QDialog): + def __init__(self, thickness_list): + super().__init__() + self.setWindowTitle("Available Thicknesses") + self.setFixedSize(1000, 200) # Wider dialog box + self.init_ui(thickness_list) + self.set_styles() + + def init_ui(self, thickness_list): + layout = QVBoxLayout() + + message = f"Available thicknesses by default - {thickness_list}" + self.label = QLabel(message) + self.label.setWordWrap(True) + self.label.setFont(QFont("Segoe UI", 12)) + self.label.setAlignment(Qt.AlignLeft | Qt.AlignTop) + + layout.addWidget(self.label) + self.setLayout(layout) + + def set_styles(self): + self.setStyleSheet(""" + QDialog { + background-color: white; + } + QLabel { + font-size: 12pt; + color: #333; + padding: 10px; + } + """) +if __name__ == "__main__": + app = QApplication(sys.argv) + default_thicknesses = ['8', '10', '12', '14', '16', '18', '20', '22', '25', '28', '32', '36', '40', '45', '50', '56', '63', '75', '80', '90', '100', + '110', '120'] + dialog = AvailableThicknessDialog(default_thicknesses) + dialog.exec_() diff --git a/src/osdag/gui/popup_input_bounds_read.py b/src/osdag/gui/popup_input_bounds_read.py new file mode 100644 index 000000000..20a993fcb --- /dev/null +++ b/src/osdag/gui/popup_input_bounds_read.py @@ -0,0 +1,88 @@ +from PyQt5.QtWidgets import ( + QDialog, QLineEdit, QFormLayout, QLabel, QMessageBox +) +from PyQt5.QtGui import QFont +from PyQt5.QtCore import Qt + + +class RangeInputDialogRead(QDialog): + def __init__(self): + super().__init__() + self.setWindowTitle("Custom Range Input") + self.setFixedSize(350, 230) # Increased height to accommodate larger inputs + self.set_styles() + + self.values = [] + + self.lower_input = QLineEdit() + self.upper_input = QLineEdit() + self.step_input = QLineEdit() + + # Set font and height for better clarity + for widget in [self.lower_input, self.upper_input, self.step_input]: + widget.setFont(QFont("Segoe UI", 13)) # Larger font + widget.setFixedHeight(44) # Taller input box + + form_layout = QFormLayout() + form_layout.setLabelAlignment(Qt.AlignRight) + form_layout.setFormAlignment(Qt.AlignCenter) + + lower_label = QLabel("Lower Bound:") + upper_label = QLabel("Upper Bound:") + step_label = QLabel("Step:") + + for label in [lower_label, upper_label, step_label]: + label.setFont(QFont("Segoe UI", 11)) + + form_layout.addRow(lower_label, self.lower_input) + form_layout.addRow(upper_label, self.upper_input) + form_layout.addRow(step_label, self.step_input) + + self.setLayout(form_layout) + + def set_styles(self): + self.setStyleSheet(""" + QDialog { + background-color: white; + } + QLabel { + font-size: 11pt; + } + QLineEdit { + font-size: 13pt; + padding: 6px 10px; + border: 1px solid #aaa; + border-radius: 4px; + } + """) + + def show_error(self, message): + QMessageBox.warning(self, "Input Error", message) + + def get_values(self): + return self.values + + def set_read_only_values(self, lower, upper, step): + """Populates the fields with given values and makes them uneditable.""" + self.lower_input.setText(str(lower)) + self.upper_input.setText(str(upper)) + self.step_input.setText(str(step)) + + self.lower_input.setReadOnly(True) + self.upper_input.setReadOnly(True) + self.step_input.setReadOnly(True) + + def set_custom_title(self, title): + """Sets a custom title for the dialog window.""" + self.setWindowTitle(title) + + +if __name__ == "__main__": + import sys + from PyQt5.QtWidgets import QApplication + + app = QApplication(sys.argv) + dialog = RangeInputDialogRead() + dialog.set_custom_title("Display Sensor Range") + dialog.set_read_only_values(10.0, 100, 10) + dialog.exec_() \ No newline at end of file diff --git a/src/osdag/gui/popup_input_bounds_read_write.py b/src/osdag/gui/popup_input_bounds_read_write.py new file mode 100644 index 000000000..4180d6750 --- /dev/null +++ b/src/osdag/gui/popup_input_bounds_read_write.py @@ -0,0 +1,113 @@ +from PyQt5.QtWidgets import ( + QDialog, QLabel, QLineEdit, QPushButton, QFormLayout, + QApplication, QMessageBox +) +from PyQt5.QtGui import QFont +from PyQt5.QtCore import Qt +import sys + +class RangeInputDialog(QDialog): + def __init__(self): + super().__init__() + self.setWindowTitle("Custom Range Input") + self.setFixedSize(350, 200) + self.set_styles() + + self.values = [] + + self.lower_input = QLineEdit() + self.upper_input = QLineEdit() + self.step_input = QLineEdit() + + for widget in [self.lower_input, self.upper_input, self.step_input]: + widget.setFont(QFont("Segoe UI", 11)) # Slightly larger font + widget.setFixedHeight(32) # Increased height + + # Form layout + form_layout = QFormLayout() + form_layout.setLabelAlignment(Qt.AlignRight) + form_layout.setFormAlignment(Qt.AlignCenter) + + lower_label = QLabel("Lower Bound:") + upper_label = QLabel("Upper Bound:") + step_label = QLabel("Step:") + + for label in [lower_label, upper_label, step_label]: + label.setFont(QFont("Segoe UI", 10)) + + form_layout.addRow(lower_label, self.lower_input) + form_layout.addRow(upper_label, self.upper_input) + form_layout.addRow(step_label, self.step_input) + + self.submit_button = QPushButton("Add") + self.submit_button.setFont(QFont("Segoe UI", 10, QFont.Bold)) + self.submit_button.clicked.connect(self.validate_and_submit) + + form_layout.addRow(self.submit_button) + self.setLayout(form_layout) + + def set_styles(self): + self.setStyleSheet(""" + QDialog { + background-color: white; + } + QLabel { + font-size: 10pt; + } + QLineEdit { + font-size: 11pt; + padding: 4px 6px; + border: 1px solid #aaa; + border-radius: 3px; + } + QPushButton { + background-color: #814c4c; + color: white; + font-size: 10pt; + font-weight: bold; + height: 28px; + border-radius: 4px; + } + QPushButton:hover { + background-color: #a05c5c; + } + """) + + def validate_and_submit(self): + lower_text = self.lower_input.text().strip() + upper_text = self.upper_input.text().strip() + step_text = self.step_input.text().strip() + + if not lower_text or not upper_text or not step_text: + self.show_error("All fields must be filled.") + return + + try: + lower = float(lower_text) + upper = float(upper_text) + step = float(step_text) + + if step <= 0: + self.show_error("Step must be greater than 0.") + return + + self.values = [lower, upper, step] + self.accept() + + except ValueError: + self.show_error("Please enter valid numeric values.") + + def show_error(self, message): + QMessageBox.warning(self, "Input Error", message) + + def get_values(self): + return self.values + + +# Run for test +if __name__ == "__main__": + app = QApplication(sys.argv) + dialog = RangeInputDialog() + if dialog.exec_() == QDialog.Accepted: + print("Returned values:", dialog.get_values()) + sys.exit(app.exec_()) diff --git a/src/osdag/gui/ui_template.py b/src/osdag/gui/ui_template.py index 305371666..8b529ae2d 100644 --- a/src/osdag/gui/ui_template.py +++ b/src/osdag/gui/ui_template.py @@ -33,6 +33,7 @@ from OCC.Core.StlAPI import StlAPI_Writer from OCC.Core import BRepTools from OCC.Core import IGESControl +from .popup_input_bounds_read_write import RangeInputDialog from ..cad.cad3dconnection import cadconnection from ..design_type.connection.fin_plate_connection import FinPlateConnection from ..design_type.connection.column_cover_plate import ColumnCoverPlate @@ -46,6 +47,8 @@ from ..design_type.connection.column_end_plate import ColumnEndPlate from ..design_type.connection.column_cover_plate_weld import ColumnCoverPlateWeld from ..design_type.connection.base_plate_connection import BasePlateConnection +from ..design_type.connection.lap_joint_bolted import LapJointBolted +from ..design_type.plate_girder.weldedPlateGirder import PlateGirderWelded from ..design_type.tension_member.tension_bolted import Tension_bolted from ..design_type.tension_member.tension_welded import Tension_welded from ..design_type.connection.beam_column_end_plate import BeamColumnEndPlate @@ -57,6 +60,10 @@ from ..gusset_connection import GussetConnection import logging import subprocess +from .popup_input_bounds_read import RangeInputDialogRead +from .popup_display_pg import AvailableThicknessDialog +from .popup_input_bounds_read_write import RangeInputDialog +from .popup_customized_design_pref import PopupDialog from ..get_DPI_scale import scale,height,width from ..cad.cad3dconnection import cadconnection from pynput.mouse import Button, Controller @@ -175,6 +182,7 @@ def closeEvent(self, event): event.ignore() class Window(QMainWindow): + input_button_values_dictionary = {} closed = QtCore.pyqtSignal() def center(self): frameGm = self.frameGeometry() @@ -537,6 +545,7 @@ def setupUi(self, MainWindow, main,folder): self.inputDock.setObjectName("inputDock") self.dockWidgetContents = QtWidgets.QWidget() self.dockWidgetContents.setObjectName("dockWidgetContents") + button_list = [] # palette = QtGui.QPalette() # brush = QtGui.QBrush(QtGui.QColor(0, 0, 127)) @@ -582,7 +591,7 @@ def setupUi(self, MainWindow, main,folder): for option in option_list: lable = option[1] type = option[2] - if type not in [TYPE_TITLE, TYPE_IMAGE, TYPE_MODULE, TYPE_IMAGE_COMPRESSION]: + if type not in [TYPE_TITLE, TYPE_IMAGE, TYPE_MODULE, TYPE_IMAGE_COMPRESSION,TYPE_IMAGE_BIGGER]: l = QtWidgets.QLabel(self.dockWidgetContents) l.setObjectName(option[0] + "_label") l.setText(_translate("MainWindow", "

" + lable + "

")) @@ -742,6 +751,25 @@ def setupUi(self, MainWindow, main,folder): l.setFixedSize(l.size()) in_layout2.addWidget(l, j, 2, 1, 1) + + if type == TYPE_IN_BUTTON: + # fields = 0 + v = option[3] + b = QtWidgets.QPushButton(self.dockWidgetContents) + b.setObjectName(option[0]) + #b.setFixedSize(b.size()) + b.resize(b.sizeHint().width(), b.sizeHint().height()+100) + b.setText(v[0]) + b.setDisabled(False) + b.setVisible(True if option[4] else False) + # fields += 1 + # self.output_title_fields[current_key][1] = fields + #b.setFixedSize(b.size()) + button_list.append(option) + in_layout2.addWidget(b, j, 2, 1, 1) + maxi_width_right = max(maxi_width_right, b.sizeHint().width()) + #b.clicked.connect(lambda: self.output_button_dialog(main, out_list)) + if type == TYPE_IMAGE: im = QtWidgets.QLabel(self.dockWidgetContents) im.setGeometry(QtCore.QRect(190, 10 + i, 100, 100)) @@ -752,6 +780,17 @@ def setupUi(self, MainWindow, main,folder): i = i + 30 im.setFixedSize(im.size()) in_layout2.addWidget(im, j, 2, 1, 1) + + if type == TYPE_IMAGE_BIGGER: + im = QtWidgets.QLabel(self.dockWidgetContents) + im.setGeometry(QtCore.QRect(190, 10 + i, 420, 400)) + im.setObjectName(option[0]) + im.setScaledContents(True) + pixmap = QPixmap(option[3]) + im.setPixmap(pixmap) + i = i + 30 + im.setFixedSize(im.size()) + in_layout2.addWidget(im, j, 1, 1, 1) if type == TYPE_IMAGE_COMPRESSION: imc = QtWidgets.QLabel(self.dockWidgetContents) @@ -783,6 +822,11 @@ def setupUi(self, MainWindow, main,folder): maxi_width = max(maxi_width, int(scale*350)) # In case there is no widget self.inputDock.setFixedWidth(maxi_width) self.in_widget.setFixedWidth(maxi_width) + if button_list: + for button_key in button_list: + button = self.dockWidgetContents.findChild(QtWidgets.QWidget, button_key[0]) + print("\n\n\n button_key", button_key) + self.inp_button_connect(main, button_list, button) for option in option_list: key = self.dockWidgetContents.findChild(QtWidgets.QWidget, option[0]) @@ -1360,6 +1404,14 @@ def setupUi(self, MainWindow, main,folder): last_design_dictionary = yaml.safe_load(last_design) print(f'last_design_dictionary {last_design_dictionary}') if isinstance(last_design_dictionary, dict): + + for k,val in self.input_button_values_dictionary.items(): + print("\n\n\n VALUES ", k, val) + if k not in last_design_dictionary.keys(): + last_design_dictionary[k] = val + else: + last_design_dictionary[k] = val + print("\n \n LAST DESIGN DICTIONARY", last_design_dictionary) self.setDictToUserInputs(last_design_dictionary, option_list, data, new_list) if "out_titles_status" in last_design_dictionary.keys(): title_status = last_design_dictionary["out_titles_status"] @@ -1558,6 +1610,29 @@ def change(self, k1, new, data, main): elif typ == TYPE_CUSTOM_SECTION: if val: self.import_custom_section() + # elif typ == TYPE_CUSTOM_BOUNDS: + # k2.clear() + # if val == 'Default Bounds': + # # dialog = RangeInputDialogRead() + # # dialog.set_custom_title("Display Sensor Range") + # # dialog.set_read_only_values(10.0, 100, 10) + # # dialog.exec_() + # # for values in dialog.get_values(): + # for values in ["10.0", "100", "10"]: + # k2.addItem(values) + # k2.setCurrentIndex(0) + # elif val == 'Custom Bounds': + # dialog = RangeInputDialog() + # if dialog.exec_() == QDialog.Accepted: + # print("Returned values:", dialog.get_values()) + # for values in dialog.get_values(): + # k2.addItem(str(values)) + # k2.setCurrentIndex(0) + # else: + # k2.clear() + # for values in val: + # k2.addItem(str(values)) + # k2.setCurrentIndex(0) elif typ == TYPE_LABEL: k2.setText(val) @@ -1865,6 +1940,10 @@ def return_class(self,name): return Flexure_Cantilever elif name == KEY_DISP_FLEXURE3: return Flexure_Misc + elif name == KEY_DISP_LAPJOINTBOLTED: + return LapJointBolted + elif name == KEY_DISP_PLATE_GIRDER_WELDED: #im working here + return PlateGirderWelded else: return GussetConnection # Function for getting inputs from a file @@ -2104,7 +2183,7 @@ def common_function_for_save_and_design(self, main, data, trigger_type): KEY_DISP_ENDPLATE, KEY_DISP_BASE_PLATE, KEY_DISP_SEATED_ANGLE, KEY_DISP_TENSION_BOLTED, KEY_DISP_TENSION_WELDED, KEY_DISP_COLUMNCOVERPLATE, KEY_DISP_COLUMNCOVERPLATEWELD, KEY_DISP_COLUMNENDPLATE, KEY_DISP_BCENDPLATE, KEY_DISP_BB_EP_SPLICE, - KEY_DISP_COMPRESSION_COLUMN,KEY_DISP_FLEXURE,KEY_DISP_FLEXURE2,KEY_DISP_COMPRESSION_Strut]: # , KEY_DISP_FLEXURE + KEY_DISP_COMPRESSION_COLUMN,KEY_DISP_FLEXURE,KEY_DISP_FLEXURE2,KEY_DISP_COMPRESSION_Strut,KEY_DISP_LAPJOINTBOLTED,KEY_DISP_PLATE_GIRDER_WELDED]: # , KEY_DISP_FLEXURE # print(self.display, self.folder, main.module, main.mainmodule) print("common start") print(f"main object type: {type(main)}") @@ -2171,6 +2250,22 @@ def osdag_header(self): shutil.copyfile(image_path, os.path.join(str(self.folder), "images_html", "OsdagHeader.png")) shutil.copyfile(image_path2, os.path.join(str(self.folder), "images_html", "ColumnsBeams.png")) + def inp_button_connect(self, main, button_list, b): + # Connect button's clicked signal to call handler using lambda + print("\n\n\n\n BUTTON TYPE DETAILS",button_list, b, b.objectName()) + b.clicked.connect(lambda: self.inp_button_call(main, button_list, b)) + + def inp_button_call(self, main, button_list, button): + # Loop through button list to find the button match + for v in button_list: + if v[0] == button.objectName(): + dialog = RangeInputDialog() + if dialog.exec_() == QDialog.Accepted: + values = dialog.get_values() + print("Returned values:", values) + # You can handle values here or emit a signal if needed + self.input_button_values_dictionary[button.objectName()] = values + def output_button_connect(self, main, button_list, b): b.clicked.connect(lambda: self.output_button_dialog(main, button_list, b)) @@ -3022,4 +3117,4 @@ def showEvent(self, event): ui = Ui_ModuleWindow() ui.setupUi(MainWindow) MainWindow.show() - sys.exit(app.exec_()) + sys.exit(app.exec_()) \ No newline at end of file diff --git a/src/osdag/gui/ui_template_for_mac.py b/src/osdag/gui/ui_template_for_mac.py index 81c6ecce8..062a1e68b 100644 --- a/src/osdag/gui/ui_template_for_mac.py +++ b/src/osdag/gui/ui_template_for_mac.py @@ -703,6 +703,9 @@ def setupUi(self, MainWindow, main,folder): i = i + 30 im.setFixedSize(im.size()) in_layout2.addWidget(im, j, 2, 1, 1) + + + if type == TYPE_IMAGE_COMPRESSION: imc = QtWidgets.QLabel(self.dockWidgetContents) diff --git a/src/osdag/is800_2007exp.py b/src/osdag/is800_2007exp.py index cd9ce2712..e2dbee3eb 100755 --- a/src/osdag/is800_2007exp.py +++ b/src/osdag/is800_2007exp.py @@ -184,6 +184,74 @@ def Table2_hollow_tube(diameter, thickness, f_y, load='Axial Compression', secti "gamma_mr": {KEY_DP_FAB_SHOP: 1.25, KEY_DP_FAB_FIELD: 1.25}, "gamma_mw": {KEY_DP_FAB_SHOP: 1.25, KEY_DP_FAB_FIELD: 1.50} } + + # ------------------------------------------------------------ + # 5.6.1 Deflection + # ------------------------------------------------------------- + @staticmethod + def cl_5_6_1_vertical_deflection_table_6(structure_type,design_load,member_type,supporting_type): + if structure_type in ['Highway Bridge','Railway Bridge']: + if member_type == 'Simple Span': + if design_load == 'Live load': + return VALUES_MAX_DEFL[0] + elif design_load == 'Dead load': + return VALUES_MAX_DEFL[1] + else: + return 'NA' + + else: + if design_load == 'Live load': + return VALUES_MAX_DEFL[2] + elif design_load == 'Dead load': + return VALUES_MAX_DEFL[1] + else: + return 'NA' + + elif structure_type == 'Other Building': + if design_load == 'Live load': + if member_type == 'Floor and roof': + if supporting_type == 'Elements not susceptible to cracking': + return VALUES_MAX_DEFL[3] + else: + return VALUES_MAX_DEFL[4] + else: + if supporting_type == 'Elements not susceptible to cracking': + return VALUES_MAX_DEFL[5] + else: + return VALUES_MAX_DEFL[6] + else: + return 'NA' + else: + if member_type == 'Purlin and Girts' and design_load == 'Live load': + if supporting_type == 'Elastic cladding': + return VALUES_MAX_DEFL[5] + else: + return VALUES_MAX_DEFL[6] + elif member_type == 'Simple span' and design_load == 'Live load': + if supporting_type == 'Elastic cladding': + return VALUES_MAX_DEFL[7] + else: + return VALUES_MAX_DEFL[3] + elif member_type == 'Cantilever span' and design_load == 'Live load': + if supporting_type == 'Elastic cladding': + return VALUES_MAX_DEFL[8] + else: + return VALUES_MAX_DEFL[5] + elif member_type == 'Rafter Supporting' and design_load == 'Live load': + if supporting_type == 'Profiled Metal sheeting': + return VALUES_MAX_DEFL[6] + else: + return VALUES_MAX_DEFL[7] + elif member_type == 'Gantry' and design_load == 'Live load': + if design_load == 'Crane Load(Manual operation)': + return VALUES_MAX_DEFL[9] + elif design_load == 'Crane load(Electric operation up to 50t)': + return VALUES_MAX_DEFL[10] + else: + return VALUES_MAX_DEFL[11] + else: + return 'NA' + # ========================================================================== """ SECTION 6 DESIGN OF TENSION MEMBERS """ diff --git a/src/osdag/osdagMainPage.py b/src/osdag/osdagMainPage.py index a46c9b8a5..926f20182 100644 --- a/src/osdag/osdagMainPage.py +++ b/src/osdag/osdagMainPage.py @@ -148,6 +148,10 @@ from .design_type.connection.base_plate_connection import BasePlateConnection from .design_type.connection.truss_connection_bolted import TrussConnectionBolted +from .design_type.connection.lap_joint_bolted import LapJointBolted +from .design_type.connection.lap_joint_welded import LapJointWelded +from .design_type.connection.butt_joint_bolted import ButtJointBolted +from .design_type.connection.butt_joint_welded import ButtJointWelded from .design_type.connection.beam_cover_plate import BeamCoverPlate from .design_type.connection.beam_cover_plate_weld import BeamCoverPlateWeld from .design_type.connection.column_cover_plate_weld import ColumnCoverPlateWeld @@ -167,7 +171,7 @@ from .design_type.flexural_member.flexure import Flexure from .design_type.flexural_member.flexure_cantilever import Flexure_Cantilever from .design_type.flexural_member.flexure_othersupp import Flexure_Misc -# from .design_type.plate_girder.weldedPlateGirder import PlateGirderWelded +from .design_type.plate_girder.weldedPlateGirder import PlateGirderWelded # from .cad.cad_common import call_3DBeam from .APP_CRASH.Appcrash import api as appcrash import configparser @@ -261,7 +265,13 @@ def __init__(self): self.ui.myStackedWidget.currentChanged.connect(self.current_changed) self.Under_Development='UNDER DEVELOPMENT' self.Modules={ - 'Connection' : { + 'Connection' : {'Simple Connection' : [ + ('Lap Joint Bolted',str(files("osdag.data.ResourceFiles.images").joinpath("LapJointBolted.png")),'Lap_Joint_Bolted'), + ('Lap Joint Welded',str(files("osdag.data.ResourceFiles.images").joinpath("LapJointWelded.png")),'Lap_Joint_Welded'), + ('Butt Joint Bolted',str(files("osdag.data.ResourceFiles.images").joinpath("ButtJointBolted.png")),'Butt_Joint_Bolted'), + ('Butt Joint Welded',str(files("osdag.data.ResourceFiles.images").joinpath("ButtJointWelded.png")),'Butt_Joint_Welded'), + self.show_simple_connection, + ], 'Shear Connection' : [ ('Fin Plate',str(files("osdag.data.ResourceFiles.images").joinpath("finplate.png")),'Fin_Plate'), ('Cleat Angle',str(files("osdag.data.ResourceFiles.images").joinpath("cleatAngle.png")),'Cleat_Angle'), @@ -528,7 +538,26 @@ def ButtonConnection(self,Button,Modules,ModuleName): Button.ui.LP_Button.clicked.connect(lambda : self.ui.myStackedWidget.setCurrentIndex(Modules.index(ModuleName)+1)) #################################### Module Launchers ########################################## + @pyqtSlot() + def show_simple_connection(self): + if self.findChild(QRadioButton, 'Lap_Joint_Bolted').isChecked(): + module_class =LapJointBolted # Import from simple_connection.py + elif self.findChild(QRadioButton, 'Lap_Joint_Welded').isChecked(): + module_class = LapJointWelded # You might adjust parameters if needed + elif self.findChild(QRadioButton, 'Butt_Joint_Bolted').isChecked(): + module_class = ButtJointBolted + elif self.findChild(QRadioButton, 'Butt_Joint_Welded').isChecked(): + module_class = ButtJointWelded + else: + QMessageBox.about(self, "INFO", "Please select an appropriate variant") + return + # Launch the module's UI window using the corresponding design class. + self.hide() + self.ui2 = Ui_ModuleWindow(module_class, ' ') + self.ui2.show() + self.ui2.closed.connect(self.show) + @pyqtSlot() def show_shear_connection(self): button_name_window_type_pairs = \ @@ -726,6 +755,7 @@ def show_girder_design(self): self.ui2 = Ui_ModuleWindow(PlateGirderWelded, ' ') self.ui2.show() self.ui2.closed.connect(self.show) + return ################################# Help Actions ############################################ diff --git a/src/osdag/utils/common/Unsymmetrical_Section_Properties.py b/src/osdag/utils/common/Unsymmetrical_Section_Properties.py new file mode 100644 index 000000000..ea101d8fd --- /dev/null +++ b/src/osdag/utils/common/Unsymmetrical_Section_Properties.py @@ -0,0 +1,175 @@ +import math +class Unsymmetrical_I_Section_Properties: + """ + Parameters: + D : Total depth of the section + B_top : Width of the top flange + B_bot : Width of the bottom flange + t_w : Thickness of the web + t_f_top : Thickness of the top flange + t_f_bot : Thickness of the bottom flange + + """ + + + def calc_mass(self, D, B_top, B_bot, t_w, t_f_top, t_f_bot): + A = Unsymmetrical_I_Section_Properties.calc_area(self,D, B_top, B_bot, t_w, t_f_top, t_f_bot) + M = (7850 * A) / 1000000 # Convert to kg from mm^2 + return round(M, 2) + + + def calc_area(self, D, B_top, B_bot, t_w, t_f_top, t_f_bot): + A = (B_top * t_f_top + B_bot * t_f_bot + (D - t_f_top - t_f_bot) * t_w) + return round(A, 2) + + + def calc_centroid(self, D, B_top, B_bot, t_w, t_f_top, t_f_bot): + A_top = B_top * t_f_top + A_bot = B_bot * t_f_bot + A_web = (D - t_f_top - t_f_bot) * t_w + + y_top = D - t_f_top / 2 + y_bot = t_f_bot / 2 + y_web = t_f_bot + (D - t_f_top - t_f_bot) / 2 + + y_neutral = (A_top * y_top + A_bot * y_bot + A_web * y_web) / (A_top + A_bot + A_web) + return y_neutral + + + def calc_MomentOfAreaZ(self, D, B_top, B_bot, t_w, t_f_top, t_f_bot): + y_neutral = Unsymmetrical_I_Section_Properties.calc_centroid(self,D, B_top, B_bot, t_w, t_f_top, t_f_bot) + + I_top = (B_top * t_f_top ** 3) / 12 + B_top * t_f_top * (D - t_f_top / 2 - y_neutral) ** 2 + I_bot = (B_bot * t_f_bot ** 3) / 12 + B_bot * t_f_bot * (y_neutral - t_f_bot / 2) ** 2 + I_web = (t_w * (D - t_f_top - t_f_bot) ** 3) / 12 + t_w * (D - t_f_top - t_f_bot) * ( + y_neutral - (t_f_bot + (D - t_f_top - t_f_bot) / 2)) ** 2 + + I_zz = (I_top + I_bot + I_web) + return round(I_zz, 2) + + + def calc_MomentOfAreaY(self, D, B_top, B_bot, t_w, t_f_top, t_f_bot): + I_top = (t_f_top * B_top ** 3) / 12 + I_bot = (t_f_bot * B_bot ** 3) / 12 + I_web = ((D - t_f_top - t_f_bot) * t_w ** 3) / 12 + + I_yy = (I_top + I_bot + I_web) + return round(I_yy, 2) + + + def calc_ElasticModulusZz(self, D, B_top, B_bot, t_w, t_f_top, t_f_bot): + I_zz = Unsymmetrical_I_Section_Properties.calc_MomentOfAreaZ(self,D, B_top, B_bot, t_w, t_f_top, t_f_bot) + y_neutral = Unsymmetrical_I_Section_Properties.calc_centroid(self,D, B_top, B_bot, t_w, t_f_top, t_f_bot) + Z_ez_top = I_zz / (D - y_neutral) + Z_ez_bot = I_zz / y_neutral + return round(min(Z_ez_top, Z_ez_bot), 2) + + + def calc_ElasticModulusZy(self, D, B_top, B_bot, t_w, t_f_top, t_f_bot): + I_yy = Unsymmetrical_I_Section_Properties.calc_MomentOfAreaY(self,D, B_top, B_bot, t_w, t_f_top, t_f_bot) + B_max = max(B_top, B_bot) + Z_ey = (I_yy * 2 ) / B_max + return round(Z_ey, 2) + + + def calc_PlasticModulusZ(self, D, bf_top, bf_bot, tw, tf_top, tf_bot, eps): + """ + Plastic section modulus Zp about strong axis for unequal flanges: + + D : total section depth between outer flange faces (mm) + bf_top : top flange width (mm) + bf_bot : bottom flange width (mm) + tw : web thickness (mm) + tf_top : top flange thickness (mm) + tf_bot : bottom flange thickness (mm) + """ + # clear web height between flange faces + h_w = D - tf_top - tf_bot + # thin-web check + if h_w/tw > 67 * eps: + print("Thin web condition, using rectangular section properties", h_w/tw) + A_top = bf_top * tf_top + A_bot = bf_bot * tf_bot + A = A_top + A_bot + + # Centroid location from top fiber + # top rectangle centroid at tf_top/2, bottom at D - tf_bot/2 + c = (A_top * (tf_top / 2) + A_bot * (D - tf_bot / 2)) / A + c1 = D - c + + # Distances from each rectangle's centroid to the composite centroid + y_top_centroid = abs((tf_top / 2) - c) + y_bot_centroid = abs((D - tf_bot / 2) - c) + + # Second moment of area of each rectangle about its own centroid + I_top = (bf_top * tf_top ** 3) / 12.0 + I_bot = (bf_bot * tf_bot ** 3) / 12.0 + + # Parallel-axis theorem + I = I_top + A_top * y_top_centroid ** 2 + I_bot + A_bot * y_bot_centroid ** 2 + + # Section moduli + Zp = I / c + return round(Zp, 2) + + else: + + A_u = bf_top * tf_top + A_d = bf_bot * tf_bot + A_w = h_w * tw + A = A_u + A_d + A_w + if h_w / tw <= 67.0 * eps: + y = (A_u * tf_top/2 + A_d * (D - tf_bot/2))/(A_u + A_d) + y1 = D - y + + # centroids measured from bottom face + y_d = tf_bot / 2.0 + y_w = tf_bot + h_w / 2.0 + y_u = tf_bot + h_w + tf_top / 2.0 + # plastic neutral axis from bottom face + if A_d < A / 2.0 and A_u < A / 2.0: + y_pna = tf_bot + (A - 2 * A_d) / (2 * tw) + elif A_d >= A / 2.0: + y_pna = A / (2 * bf_bot) + else: + y_pna = D - A / (2 * bf_top) + # compute Zp as sum of Ai * distance from plastic axis + Zp = ( + (bf_bot * y_pna ** 2 - (bf_bot - tw) * (y_pna - tf_bot) ** 2) + + (bf_top * (D - y_pna) ** 2 - (bf_top - tw) * (D - tf_top - y_pna) ** 2) + ) / 2.0 + return round(Zp, 2) + + def calc_PlasticModulusY(self, D, B_top, B_bot, t_w, t_f_top, t_f_bot): + Zpy = (t_f_top * B_top ** 2 / 4 + t_f_bot * B_bot ** 2 / 4 + (D - t_f_top - t_f_bot) * t_w ** 2 / 4) + return round(Zpy, 2) + + def calc_TorsionConstantIt(self, D, B_top, B_bot, t_w, t_f_top, t_f_bot): + h = D - ((t_f_top + t_f_bot)/2) + It = (1 / 3) * ( B_top * t_f_top ** 3 + B_bot * t_f_bot ** 3 + h * t_w ** 3 ) + return round(It, 2) + + def calc_WarpingConstantIw(self, D, B_top, B_bot, t_w, t_f_top, t_f_bot): + h = D - ((t_f_top + t_f_bot)/2) + numerator_Iw = (h ** 2) * t_f_top * t_f_bot * (B_top ** 3) * (B_bot ** 3) + denominator_Iw = 12 * (t_f_top * B_top ** 3 + t_f_bot * B_bot ** 3) + Iw = numerator_Iw / denominator_Iw + return round(Iw, 2) + + def calc_RadiusOfGyrationZ(self, D, B_top, B_bot, t_w, t_f_top, t_f_bot): + """ + Radius of gyration about z-axis (major axis) + """ + I_zz = self.calc_MomentOfAreaZ(D, B_top, B_bot, t_w, t_f_top, t_f_bot) + A = self.calc_area(D, B_top, B_bot, t_w, t_f_top, t_f_bot) + r_z = math.sqrt(I_zz / A) + return round(r_z, 2) + + def calc_RadiusOfGyrationY(self, D, B_top, B_bot, t_w, t_f_top, t_f_bot): + """ + Radius of gyration about y-axis (minor axis) + """ + I_yy = self.calc_MomentOfAreaY(D, B_top, B_bot, t_w, t_f_top, t_f_bot) + A = self.calc_area(D, B_top, B_bot, t_w, t_f_top, t_f_bot) + r_y = math.sqrt(I_yy / A) + return round(r_y, 2) \ No newline at end of file diff --git a/src/osdag/utils/common/is800_2007.py b/src/osdag/utils/common/is800_2007.py index 95ff64492..8eee5c195 100644 --- a/src/osdag/utils/common/is800_2007.py +++ b/src/osdag/utils/common/is800_2007.py @@ -6,6 +6,7 @@ """ import math from ...Common import * +import pandas as pd # from ...Common import KEY_DP_FAB_SHOP @@ -496,6 +497,40 @@ def cl_3_8_max_slenderness_ratio(Type = 1): "gamma_mr": {KEY_DP_FAB_SHOP: 1.25, KEY_DP_FAB_FIELD: 1.25}, "gamma_mw": {KEY_DP_FAB_SHOP: 1.25, KEY_DP_FAB_FIELD: 1.50} } + + # ------------------------------------------------------------ + # 5.6.1 Deflection + # ------------------------------------------------------------- + +# cl_5_6_1_vertical_deflection_Table_6 = { + +# Type of structure Load Type Member Supporting Deflection Limit +# Industrial building Live Load Purlins and Girts Elastic cladding Span/150 +# Industrial building Live Load Purlins and Girts Brittle cladding Span/180 +# Industrial building Live Load Simple span Elastic cladding Span/240 +# Industrial building Live Load Simple span Brittle cladding Span/300 +# Industrial building Live Load Cantilever span Elastic cladding Span/120 +# Industrial building Live Load Cantilever span Brittle cladding Span/150 +# Industrial building Live Load Rafter supporting Profiled Metal Sheeting Span/180 +# Industrial building Live Load Rafter supporting Plastered Sheeting Span/240 +# Industrial building Crane Load(Manual operation) Gantry Crane Span/500 +# Industrial building Crane load(Electric operation up to 50t) Gantry Crane Span/750 +# Industrial building Crane load(Electric operation over 50t) Gantry Crane Span/1000 +# Other buildings Live Load Floor and Roof Elements not susceptible to cracking Span/300 +# Other buildings Live Load Floor and Roof Element susceptible to cracking Span/360 +# Other buildings Live Load Cantilever Span Elements not susceptible to cracking Span/150 +# Other buildings Live Load Cantilever Span Element susceptible to cracking Span/180 +# Highway Bridges Live Load Simple span NA Span/600 +# Railway Bridges Live Load Simple span NA Span/600 +# Highway Bridges Dead Load Simple span NA Span/800 +# Railway Bridges Dead Load Simple span NA Span/800 +# Highway Bridges Live Load Cantilever span NA Span/400 +# Railway Bridges Live Load Cantilever span NA Span/400 +# Highway Bridges Dead Load Cantilever span NA Span/800 +# Railway Bridges Dead Load Cantilever span NA Span/800 + + + # } # ========================================================================== """ SECTION 6 DESIGN OF TENSION MEMBERS """ @@ -805,6 +840,39 @@ def cl_7_1_2_2_buckling_class_of_crosssections(b, h, t_f, cross_section='Rolled } return buckling_class + + @staticmethod + def cl_7_1_2_1_design_compressisive_stress_plategirder(f_y, gamma_mo, effective_slenderness_ratio, + modulus_of_elasticity): + """ + Args: + f_y:Yield stress (float) + gamma_mo:Effective length of member (float) + effective_slenderness_ratio:Euler buckling class (float) + imperfection_factor + modulus_of_elasticity + + Returns: + list of euler_buckling_stress, nondimensional_effective_slenderness_ratio, phi, stress_reduction_factor, design_compressive_stress_fr .design_compressive_stress, design_compressive_stress_min + Note: + Reference: IS 800 pg34 + @author:Rutvik Joshi + """ + # 2.4 - Euler buckling stress + imperfection_factor = 0.49 + euler_buckling_stress = (math.pi ** 2 * modulus_of_elasticity) / effective_slenderness_ratio ** 2 + nondimensional_effective_slenderness_ratio = math.sqrt(f_y / euler_buckling_stress) + phi = 0.5 * (1 + imperfection_factor * ( + nondimensional_effective_slenderness_ratio - 0.2) + nondimensional_effective_slenderness_ratio ** 2) + # 2.6 - Design compressive stress + stress_reduction_factor = 1 / (phi + math.sqrt(phi ** 2 - nondimensional_effective_slenderness_ratio ** 2)) + design_compressive_stress_fr = f_y * stress_reduction_factor / gamma_mo + design_compressive_stress_max = f_y / gamma_mo + design_compressive_stress = min(design_compressive_stress_fr, design_compressive_stress_max) + print(f"euler_buckling_stress {euler_buckling_stress} , nondimensional_effective_slenderness_ratio {nondimensional_effective_slenderness_ratio} , phi {phi} , stress_reduction_factor {stress_reduction_factor} , design_compressive_stress_fr {design_compressive_stress_fr} , design_compressive_stress_max {design_compressive_stress_max} , design_compressive_stress {design_compressive_stress}") + return design_compressive_stress + + @staticmethod def cl_7_5_1_2_equivalent_slenderness_ratio_of_truss_compression_members_loaded_one_leg(length, r_min, b1, b2, t, f_y, bolt_no = 2, fixity = 'Fixed'): @@ -1286,7 +1354,10 @@ def cl_8_4_2_2_TensionField( c, d, tw, fyw, bf,tf, fyf,Nf, gamma_mo, A_v,tau_b,V Author: Rutvik Joshi ''' - phi = math.atan(d/c) * 180/math.pi + if c == 0: + phi = 90 + else: + phi = math.atan(d/c) * 180/math.pi M_fr = 0.25 * bf * tf**2 * fyf*(1-(Nf/(bf * tf * fyf / gamma_mo))**2) print('phi',phi,'\n Nf',Nf,M_fr,'M_fr',phi*math.pi/180) s = 2 * math.sqrt(M_fr / (fyw * tw)) / math.sin(phi*math.pi/180) @@ -1304,6 +1375,77 @@ def cl_8_4_2_2_TensionField( c, d, tw, fyw, bf,tf, fyf,Nf, gamma_mo, A_v,tau_b,V V_tf == V_p print('phi',phi,'\n M_fr',M_fr,'\n s',s, '\n c',c, '\n w_tf', w_tf, '\n sai',sai,'\n fv',fv,'\n V_tf',V_tf,'\n V_p',V_p) return phi,M_fr,s, w_tf,sai,fv,V_tf + + @staticmethod + def cl_8_4_2_2_TensionField_unequal_Isection( + c, d, tw, fyw, + bf_top, tf_top, bf_bot, tf_bot, + Nf, gamma_m0, A_v, tau_b +): + """ + Tension‐field method per IS 800:2007 Cl. 8.4.2.2 for unequal flanges. + + Parameters: + c : float : panel width (mm) + d : float : web depth (mm) + tw : float : web thickness (mm) + fyw : float : web yield stress (N/mm²) + bf_top : float : top flange width (mm) + tf_top : float : top flange thickness (mm) + bf_bot : float : bottom flange width (mm) + tf_bot : float : bottom flange thickness (mm) + Nf : float : axial force in each flange (kN → N·mm units consistent) + gamma_m0: float : partial safety factor + A_v : float : gross web area = d*tw (mm²) + tau_b : float : post‐buckling shear stress of web (N/mm²) + V_p : float : plastic shear strength V_np (kN) + + Returns: + tuple: (phi, Mfr_top, Mfr_bot, s_top, s_bot, w_tf, psi, fv, V_tf) + """ + + # 1) Tension‐field angle φ + if c == 0: + phi = 90.0 + else: + phi = math.degrees(math.atan((d / c) / 1.5)) + + # 2) Reduced plastic moment of each flange + def Mfr(bf, tf): + Mp = 0.25 * bf * tf**2 * fyw + ratio = Nf / (bf * tf * fyw / gamma_m0) + if ratio >= 1: + return 0 + else: + return Mp * (1 - ratio**2) + + Mfr_t = Mfr(bf_top, tf_top) + Mfr_b = Mfr(bf_bot, tf_bot) + + # 3) s‐values for each flange, limited to c + + sinφ = math.sin(math.radians(phi)) + if sinφ == 0: + s_t= 0 + s_b= 0 + else: + s_t = min(2 * math.sqrt(Mfr_t / (fyw * tw)) / sinφ, c) + s_b = min(2 * math.sqrt(Mfr_b / (fyw * tw)) / sinφ, c) + + + # 4) Width of the tension field w_tf + w_tf = d * math.cos(math.radians(phi)) - (c - s_t - s_b) * sinφ + + # 5) Field yield strength f_v + psi = 1.5 * tau_b * math.sin(2 * math.radians(phi)) + fv = math.sqrt(fyw**2 - 3 * tau_b**2 + psi**2) - psi + + # 6) Nominal shear resistance V_tf (kN) + V_tf = (A_v * tau_b + 0.9 * w_tf * tw * fv * sinφ) + V_p = d * tw * fyw / (math.sqrt(3) * gamma_m0) # Plastic shear strength + V_tf = min(V_tf, V_p) + + return phi, Mfr_t, Mfr_b, s_t, s_b, w_tf, psi, fv, V_tf @staticmethod def cl_8_5_1_EndPanel(c, d, tw, fyw, bf, tf, fyf, Nf, gamma_mo, A_v, tau_b, V_p): @@ -1331,6 +1473,138 @@ def cl_8_5_1_EndPanel(c, d, tw, fyw, bf, tf, fyf, Nf, gamma_mo, A_v, tau_b, V_p) else: V_tf == V_p return phi, M_fr, s, w_tf, sai, fv, V_tf + + + @staticmethod + def cl_8_6_1_1_plate_girder_minimum_web_a(D,tw,epsilon,tf_top,tf_bot): + d = D - (tf_top + tf_bot) + if d/tw < 200 * epsilon: + return True + else: + return False + + @staticmethod + def cl_8_6_1_1_and_8_6_1_2_web_thickness_check(d, tw, eps, stiffener_type, c=None): + """ + Check minimum web thickness requirements as per IS 800:2007 Cl. 8.6.1.1 & 8.6.1.2 + + Parameters: + d (float): Depth of web (mm) + tw (float): Thickness of web (mm) + eps (float): ε = sqrt(250/fy) where fy is yield strength of steel (N/mm^2) + stiffener_type (str): Type of stiffening provided. Options: + - "no_stiffener" + - "transverse_only" + - "transverse_and_two_longitudinal_neutral" + - "transverse_and_one_longitudinal_compression" + c (float): Spacing of transverse stiffeners (mm), required for some types + + Returns: + dict: Dictionary with result of the web thickness check. + """ + + results = {} + print(stiffener_type) + if stiffener_type == "no_stiffener" or c > 3 * d: + ratio = d / tw + print("Web Ratio:", ratio) + limit_serv = 200 * eps + limit_buckling = 345 * (eps ** 2) + limit = min(limit_serv, limit_buckling) + results["Limit"] = limit + if ratio <= limit: + return True + else: + return False + + elif stiffener_type == "transverse_only": + if c is None: + + return False #{"Error": "Spacing 'c' is required for 'transverse_only' stiffeners."} + print("c:", c, "d:", d, "tw:", tw, "eps:", eps) + if 3 * d >= c and c >= 1.5 * d: + ratio_serv = d / tw + ratio_buckling = d / tw + limit_serv = 200 * eps + limit_buckling = 345 * (eps ** 2) + elif 1.5 * d > c and c >= d: + ratio_serv = d / tw + ratio_buckling = d / tw + limit_serv = 200 * eps + limit_buckling = 345 * eps + elif 0.74 * d <= c and c < d: + ratio_serv = c / tw + ratio_buckling = d / tw + limit_serv = 200 * eps + limit_buckling = 345 * eps + elif c < 0.74 * d: + ratio_serv = d / tw + ratio_buckling = d / tw + limit_serv = 270 * eps + limit_buckling = 345 * eps + else: + print('Transverse only') + return False #{"Error": "Invalid range for spacing 'c'."} + + + if ratio_serv <= limit_serv and ratio_buckling <= limit_buckling: + return True + else: + return False + + elif stiffener_type == "transverse_and_two_longitudinal_neutral": + if c >= 1.5 * d : + ratio = d / tw + limit_serv = 400 * eps + limit_buckling = 345 * (eps ** 2) + limit = min(limit_serv, limit_buckling) + + else: + ratio = d / tw + limit_serv = 400 * eps + limit_buckling = 345 * eps + limit = min(limit_serv, limit_buckling) + + if ratio <= limit: + return True + else: + return False + + elif stiffener_type == "transverse_and_one_longitudinal_compression": + if c is None: + return False #{"Error": "Spacing 'c' is required for compression flange restraint."} + + if 2.4 * d >= c and c >= 1.5 * d: + ratio_serv = d / tw + ratio_buckling = d / tw + limit_serv = 250 * eps + limit_buckling = 345 * (eps ** 2) + elif 1.5 * d > c and c >= d: + ratio_serv = d / tw + ratio_buckling = d / tw + limit_serv = 250 * eps + limit_buckling = 345 * eps + elif 0.74 * d <= c and c < d: + ratio_serv = c / tw + ratio_buckling = d / tw + limit_serv = 250 * eps + limit_buckling = 345 * eps + elif c < 0.74 * d: + ratio_serv = d / tw + ratio_buckling = d / tw + limit_serv = 340 * eps + limit_buckling = 345 * eps + else: + return False #{"Error": "Invalid range for spacing 'c'."} + + if ratio_serv <= limit_serv and ratio_buckling <= limit_buckling: + return True + else: + return False + + else: + return False #{"Error": "Invalid stiffener_type provided."} + # ========================================================================== """ SECTION 9 MEMBER SUBJECTED TO COMBINED FORCES """ @@ -1367,6 +1641,16 @@ def cl_8_7_1_3_stiff_bearing_length(shear_force, web_thickness, flange_thickness # ========================================================================== """ SECTION 9 MEMBER SUBJECTED TO COMBINED FORCES """ + + # ------------------------------------------------------------- + # 10.1 General + # ------------------------------------------------------------- + + + + + + # ========================================================================== """ SECTION 10 CONNECTIONS """