Source code for Pabq.common_tools.design_of_joints

import Pabq.common_tools.steel_design as sd
import logging
import numpy as np
import sys


[docs]class TjointRHS(sd.Part): """ Properties and calculations of a theoretical (ideal geometry) polygonal column. """
[docs] def __init__( self, geometry=None, cs_props=None, material=None, struct_props=None, bc_loads=None ): if sys.version_info[0] < 3: sd.Part.__init__( self, geometry, cs_props, material, struct_props, bc_loads ) else: super().__init__( geometry, cs_props, material, struct_props, bc_loads )
[docs] @classmethod def from_geometry( cls, column, beam, weld=None, material_col=None, material_beam=None, n_prc_col=None, n_prc_beam=None, length_c=None, length_b=None, production_type=None ): # Set the default for the type of production of the profile. if production_type is None: production_type = "cold formed" elif production_type == ("cold formed" or "hot rolled"): production_type = production_type else: logging.error( "Invalid production type for the RHS. Has to be either 'cold " "formed' or 'hot rolled'.") # Fetch the dimensions of the column profile width_c = column[0] height_c = column[1] thick_c = column[2] # Create a cs object for the column logging.info("") logging.info( "Create the column member and calculate cs properties") logging.info(">>>>>>") logging.info("n_prc_col: %.3f " % n_prc_col) cs_col = sd.CsRHS.from_n_prc( width_c, height_c, thick_c, material=material_col, n_prc=n_prc_col, ) logging.info("<<<<<<") # Fetch the dimensions of the beam profile width_b = beam[0] height_b = beam[1] thick_b = beam[2] # Create a cs object for the beam logging.info("") logging.info( "Create the beam member and calculate cs properties") logging.info(">>>>>>") logging.info("n_prc_beam: %.3f " % n_prc_beam) cs_beam = sd.CsRHS.from_n_prc( width_b, height_b, thick_b, material=material_beam, n_prc=n_prc_beam, ) logging.info("<<<<<<") logging.info("") logging.info("Calculating the join resistance.") # Calculate the beta ratio of the joint. beta = width_b/width_c logging.info( "Beta: %.3f" % beta ) # Calculate the flexural buckling resistance of the column. logging.info( "Flexural buckling of the column." ) if production_type == "cold formed": b_curve = "c" else: b_curve = "a0" n_b_rd = sd.n_b_rd( length_c, cs_col.area, cs_col.moi_1, material_col.f_y_nominal, b_curve, kapa_bc=1., gamma_m1=1. ) logging.info( "N_b_Rd_col: %.3f" % n_b_rd ) # Gather useful info in shorter variables w_pl_b = cs_beam.w_pl f_yield_b = material_col.f_y_nominal f_yield_c = material_beam.f_y_nominal # Beam's moment resistance m_pl_rd_beam = cs_beam.m_n_rd # Calculation of the joint as per EN1993-1-8 tb. 7.14 # Safety factor logging.info( "Resistance calculations for the joint." ) logging.info( ( "Calculation of the joint as per EN1993-1-8 tb." "7.14\n----------------------------" ) ) # NOTE: I use gamma_m5 = 1, no safety factor included. This is ok with # the real measured values. I have to change it if I consider nominal # values gamma_m5 = 1. # beam (brace) failure b_eff_beam = 10*f_yield_b*thick_c**2*width_b/( width_c*f_yield_b*thick_b ) if b_eff_beam > width_b: b_eff_beam = width_b logging.info("Beam effective width, b_eff: %.3f" % b_eff_beam) # Beam failure m_ip_bf_rd = f_yield_b*( w_pl_b - ( 1 - b_eff_beam/width_b )*width_b*height_b*thick_b )/gamma_m5 logging.info("Beam failure, M_ip_bf_Rd: %.3f" % m_ip_bf_rd) # f_y_k for T-joints is equal to f_y of the column (chord) f_y_k = f_yield_c # Column (chord) side wall crushing m_ip_cw_rd = 0.5*f_y_k*thick_c*( height_b + 5*thick_c )**2/gamma_m5 logging.info( "Column wall crushing, M_ip_cw_Rd: %.3f" % m_ip_cw_rd ) # Joint resistance, minimum of the previous two. m_ip_rd = min(m_ip_bf_rd, m_ip_cw_rd) logging.info( "Joint's moment resistance, M_ip_Rd: %.3f" % m_ip_rd ) # Calculations for the joint as per prEN1993-1-8. The differencies are # a) the introduction of the column(chord) stress factor Qf and # b) the interpolation between "chord face failure" and "Chord side # wall failure" for values of beta between 0.85 and 1 logging.info( ( "Calculation of the joint as per prEN1993-1-8 tb." "9.16\n----------------------------" ) ) # Calculate the buckling stress f_b. It is not necessary since this # calculation is included in the calculation of M_ip. It is performed # only so that it can be stored in the object for easy access. # NOTE: buckling curve "c" is used. Is this correct? in prEN3-1-8 says # "relevant buckling curve". b_curve = "c" f_b = cls.calc_f_b( height_c, thick_c, material_col.e_modulus, f_yield_c, b_curve ) # beam (brace) failure. m_ip_bf_rd_draft = cls.calc_m_ip_bf_rd_draft( material_beam, thick_c, width_b, width_c, thick_b, w_pl_b, height_b, gamma_m5 ) logging.info( "[prEN] Beam(brace) failure, M_ip_bf_Rd: %.3f" % m_ip_bf_rd_draft ) # Column (chord) side wall failure for n=1 m_ip_cw_rd_draft = cls.calc_m_ip_cw_rd_draft( 1., n_prc_col, material_col, thick_c, height_c, height_b, "c", gamma_m5 ) logging.info( "[prEN] Column wall crushing for beta=1, M_ip_cw_Rd: %.3f" % m_ip_cw_rd_draft ) # Calculate the chord face failure for beta=0.85 # NOTE: Watch out for the sign of n_prc. Throughout the code, I # didn't pay attention to the sign of n_prc, which implies that the # acting load (compression) is just positive. Here the sign is # important so I just made it negative, assuming that all the # considered cases are under compression. m_ip_cf85_rd_draft = cls.calc_m_ip_cf_rd_draft( 0.85, -n_prc_col, thick_c, height_b, width_c, material_col, gamma_m5 ) logging.info( "[prEN] Chord face failure for beta=0.85, M_ip_cf_Rd: %.3f" % m_ip_cf85_rd_draft ) # Take the minimum between the brace failure and the chord face # failure modes for beta=1 m_ip_cfbf85_rd_draft = min(m_ip_cf85_rd_draft, m_ip_bf_rd_draft) logging.info( "[prEN] Minimum of bf and cf for beta=0.85, M_ip_cfbf_Rd: %.3f" % m_ip_cfbf85_rd_draft ) # Linear interpolation between the min of [bf, cf] modes for # beta=0.85 and the chord side wall crushing for beta=1. m_ip_cw_rd_draft = ( (beta - 0.85)*(m_ip_cw_rd_draft - m_ip_cfbf85_rd_draft)/0.15 ) + m_ip_cfbf85_rd_draft logging.info( "[prEN] M_ip_cw_Rd for the actual beta: %.3f" % m_ip_cw_rd_draft ) # Calculate the moment resistance of the joint by picking the minimum # resistance value between the two previous modes. m_ip_rd_draft = min(m_ip_bf_rd_draft, m_ip_cw_rd_draft) logging.info( "Joint's resistance (smallest of M_ip_bf_rd_draft and " "M_ip_cw_rd_draft), M_ip_Rd:" " %.3f" % m_ip_rd_draft ) # Calculate the column resistance based on the requested utilisation # ratio and the moment resistance of the joint. It is assumed that the # entire moment bearing capacity of the joint is utilised # (M_ip,rd_draft = M_ip,0,Ed). This calculation is only valid for # symmetric joint configuration as it assumes that the beam moment, # M_ip,1, is distributed equally to the upper and lower part of the # column, M_ip,0 = 0.5*M_ip,1. Calculation dictated by 9.2.1(3) of # prEN1993-1-8 (eq 9.1). n_m_rd_col_jj = cs_col.area*( n_prc_col*material_col.f_y_nominal - 0.5*m_ip_rd_draft/cs_col.w_pl ) logging.info( "Axial resistance of the column accounting for the interaction " "with the bending of the joint, N_m_Rd_col_jj: %.3f" % n_m_rd_col_jj ) ## Get the smallest moment resistance between the calculations of the ## column member and the joint (acc. to the new draft version #if cs_col.m_n_rd < m_ip_rd_draft/2.: # m_n_rd_col = cs_col.m_n_rd # logging.info( # "Resistance of the column member is critical (the joint has" # "sufficient moment resistance" # ) #else: # m_n_rd_col = m_ip_rd_draft/2. # logging.info( # "Resistance of the joint is critical (the column has " # "sufficient moment resistance as calculated for the " # "axial/bending interaction." # ) m_prc_j_el = (m_ip_rd/2.)/cs_col.m_el_rd m_prc_j_pl = (m_ip_rd/2.)/cs_col.m_pl_rd m_prc_j_el_draft = (m_ip_rd_draft/2.)/cs_col.m_el_rd m_prc_j_pl_draft = (m_ip_rd_draft/2.)/cs_col.m_pl_rd # Calculate the maximum utilisation ratio that can be achieved in the # column, normalised both to the plastic and the elastic moment # resistance of the column. m_prc_m_el = cs_col.m_n_rd/cs_col.m_el_rd m_prc_m_pl = cs_col.m_n_rd/cs_col.m_pl_rd # Calculate the utilisation ratio of the joint normalised to the # joint's moment resistance for the case of no axial load in the column # (this calculation regards only to prEN). To perform the following # calculation, a new joint is built with n_prc=0. if not (n_prc_col == 0.): zero_axial_joint = TjointRHS.from_geometry( column, beam, weld=weld, material_col=material_col, material_beam=material_beam, n_prc_col=0., n_prc_beam=n_prc_beam, length_c=length_c, length_b=length_b, production_type=production_type ) m_prc_jj_draft = m_ip_rd_draft/zero_axial_joint.struct_props[ "m_ip_rd_draft" ] else: m_prc_jj_draft = 1. struct_props = { "n_b_rd": n_b_rd, "n_m_rd_col_jj": n_m_rd_col_jj, "b_eff_beam": b_eff_beam, "f_b": f_b, "n_prc_col": n_prc_col, "m_ip_bf_rd": m_ip_bf_rd, "m_ip_cw_rd": m_ip_cw_rd, "m_ip_rd": m_ip_rd, "m_ip_bf_rd_draft": m_ip_bf_rd_draft, "m_ip_cw_rd_draft": m_ip_cw_rd_draft, "m_ip_cf85_rd_draft": m_ip_cf85_rd_draft, "m_ip_cfbf85_rd_draft": m_ip_cfbf85_rd_draft, "m_ip_cw_rd_draft": m_ip_cw_rd_draft, "m_ip_rd_draft": m_ip_rd_draft, "m_prc_j_el": m_prc_j_el, "m_prc_j_el_draft": m_prc_j_el_draft, "m_prc_j_pl": m_prc_j_pl, "m_prc_j_pl_draft": m_prc_j_pl_draft, "m_prc_jj_draft": m_prc_jj_draft, "m_prc_m_el": m_prc_m_el, "m_prc_m_pl": m_prc_m_pl } geometry = { "beta": beta, "width_c": width_c, "height_c": height_c, "thick_c": thick_c, "length_c": length_c, "width_b": width_b, "height_b": height_b, "thick_b": thick_b, "length_b": length_b } return( cls( geometry=geometry, cs_props={ "column": cs_col, "beam": cs_beam, }, material={ "column": material_col, "beam": material_beam, }, struct_props=struct_props, bc_loads=None ) )
[docs] @classmethod def from_slend_beta( cls, nd_width_col, c_width, nd_width_beam, beta, n_prc_col=None, n_prc_beam=None, material_col=None, material_beam=None, length_c=None, length_b=None ): epsilon_col = material_col.epsilon epsilon_beam = material_beam.epsilon b_width = c_width * beta # Square profiles are considered b_height = b_width c_height = c_width # An iterative procedure is needed to calculate the thickness # because the flat width depends on the corner radius which depends # on the thickness. c_thick = c_width/(epsilon_col*nd_width_col + 2.*2.) c_thick_new = 0 logging.debug("Initial thickness: %.3f" % c_thick) tol = 1e-6 while abs(c_thick-c_thick_new) > tol: c_thick_new = c_thick r_out = sd.CsRHS.radius_from_thickness(c_thick_new) c_thick = (c_width - 2*r_out[0])/(epsilon_col*nd_width_col) logging.debug("New thickness: %.3f" % c_thick) b_thick = b_width/(epsilon_beam*nd_width_beam + 2.*2.) b_thick_new = 0 logging.debug("Initial thickness: %.3f" % b_thick) tol = 1e-6 while abs(b_thick-b_thick_new) > tol: b_thick_new = b_thick r_out = sd.CsRHS.radius_from_thickness(b_thick_new) b_thick = (b_width - 2*r_out[0])/(epsilon_beam*nd_width_beam) logging.debug("New thickness: %.3f" % b_thick) column = (c_width, c_height, c_thick) beam = (b_width, b_height, b_thick) joint = cls.from_geometry( column, beam, weld=None, material_col=material_col, material_beam=material_beam, n_prc_col=n_prc_col, n_prc_beam=n_prc_beam, length_c=length_c, length_b=length_b ) return(joint)
[docs] @classmethod def from_slend_beta_m_prc_jj( cls, nd_width_col, c_width, nd_width_beam, beta, m_prc_col, n_prc_beam=None, material_col=None, material_beam=None, length_c=None, length_b=None ): """ Alternative constructor for a T-joint for a given utilisation ratio of the joint moment resistance, normalised against the moment resistance of the same joint configuration for zero axial compression of the column. """ # If the requested bending utilisation of the joint is below 0.4, then # the column can reach an axial compressive utilisation of 1 and no # iterations need to be performed. if m_prc_col < 0.4: logging.debug( "The requested bending utilization of the joint is below 0.4, " "the axial bearing capacity off the column can be fully" "utilised." ) joint = cls.from_slend_beta( nd_width_col, c_width, nd_width_beam, beta, n_prc_col=1., n_prc_beam=n_prc_beam, material_col=material_col, material_beam=material_beam, length_c=length_c, length_b=length_b ) return(joint) # An initial estimation of the axial utilization. n_prc = 1 - m_prc_col # Initial approximation values m_diff_prev = 1 n_prc_step = n_prc/10. tol = 0.00001 while np.abs(n_prc_step) > tol: joint = cls.from_slend_beta( nd_width_col, c_width, nd_width_beam, beta, n_prc_col=n_prc, n_prc_beam=n_prc_beam, material_col=material_col, material_beam=material_beam, length_c=length_c, length_b=length_b ) m_diff_current = joint.struct_props["m_prc_jj_draft"] - m_prc_col if m_diff_current > 0: sign = 1 else: sign = -1 if not(np.sign(m_diff_prev) == np.sign(m_diff_current)): n_prc_step = 0.5*n_prc_step m_diff_prev = m_diff_current while (n_prc + sign*n_prc_step)>1.: n_prc_step = 0.5*n_prc_step n_prc = n_prc + sign*n_prc_step return(joint)
[docs] @classmethod def from_slend_beta_m_prc_j( cls, nd_width_col, c_width, nd_width_beam, beta, m_prc_col, n_prc_beam=None, material_col=None, material_beam=None, length_c=None, length_b=None ): """ NOTE: This method is obsolete and should not be used. I keep it only for legacy reasons. The method calculated a joints based on the utilisation ratio normalised for the column resistance. Instead, It was decided that it makes more sense to calculate the utilisation ratio normalised for the moment resistance of the joint with zero axial load. """ n_prc = 1 - m_prc_col m_prc_diff = 1 tol = 0.00001 while np.abs(m_prc_diff) > tol: joint = cls.from_slend_beta( nd_width_col, c_width, nd_width_beam, beta, n_prc_col=n_prc, n_prc_beam=n_prc_beam, material_col=material_col, material_beam=material_beam, length_c=length_c, length_b=length_b ) # After creating a "joint" with a given axial utilisation, n_prc, # the resulted moment utilisation is calculated to be checked # against the requested value. The moment utilisation is different # for elastic or plastic design and is derived by the minimum of # the joint or member moment resistance. if joint.cs_props["column"].cs_class < 3: m_prc_current = min( joint.struct_props["m_prc_j_pl_draft"], joint.struct_props["m_prc_m_pl"] ) elif joint.cs_props["column"].cs_class == 3: m_prc_current = min( joint.struct_props["m_prc_j_el_draft"], joint.struct_props["m_prc_m_el"] ) else: logging.warning( "The cross-section is in class 4 and the calculation of " "m_prc is wrong because of incomplete coding in the " "steel_design.py module." ) logging.debug("m_prc_current: %.3f" % m_prc_current) #print(m_prc_current) # Difference between the calculated moment resistance of the joint # for the current value of axial utilisation of the column and the # applied moment, M_Ed_beam. The moment difference is multiplied by # 0.5 to get the equivalent moment difference in the column (value # used for the approximation). m_prc_diff = m_prc_col - m_prc_current logging.info("m_diff: %.3f" % m_prc_diff) #print(m_prc_diff) # Axial load difference of the column resitance from the member # interaction formulas, equivalent to the moment difference. if joint.cs_props["column"].cs_class < 3: a_w = ( joint.cs_props["column"].area -\ 2*joint.cs_props["column"].width*\ joint.cs_props["column"].thick )/joint.cs_props["column"].area n_diff = m_prc_diff*(0.5*a_w - 1) else: n_diff = 1 + m_prc_diff/joint.cs_props["column"].w_el logging.info("Convergence residual: %.3f\n" % n_diff) #print(n_diff) n_prc = n_prc + n_diff #print(n_prc) if n_prc < 0: logging.error( "The requested utilisation of the column cannot be " "achieved because it is limited by the resistance of the " "joint." ) return logging.info("New n_prc: %.3f\n" % n_prc) #else: # logging.info("Joint's moment resistance not critical") # break return(joint)
[docs] @staticmethod def calc_c_f(material): """ Calculate the material factor Q_f acc. to the proposals of prEN1993-1-8 tb.9.1. """ f_yield = material.f_y_nominal f_ultimate = material.f_u_nominal # NOTE: the following condition is my interpretation of the newly added # sentence "should not exceed 0.80 fu" which is just before table 9.1 # of prEN3-1-8 if f_yield > 0.8*f_ultimate: f_yield = 0.8*f_ultimate if f_yield <= 355.: c_f = 1 elif f_yield > 355. and f_yield <= 460.: c_f = 0.9 elif f_yield > 460. and f_yield <= 700.: c_f = 0.8 else: logging.error("Invalid yield stress") return c_f
[docs] @staticmethod def calc_f_b(h_c, t_c, e_modulus, f_yield, b_curve): logging.debug( "[prEN] h_c, t_c, epsilon, f_yield: %.3f, %.3f, %.3f, %.3f, " % (h_c, t_c, e_modulus, f_yield) ) lambda_web = 3.46*((h_c/t_c - 2)/(np.pi*np.sqrt(e_modulus/f_yield))) logging.debug( "[prEN] Lamda web: %.3f" % lambda_web ) chi = sd.chi_flex(lambda_web, b_curve) logging.debug( "[prEN] Chi web: %.3f" % chi ) f_b = chi*f_yield return(f_b)
[docs] @staticmethod def calc_q_f(beta, n_prc): if n_prc<0: c_1 = 0.6 - 0.5*beta else: c_1 = 0.1 logging.debug("n_prc, c_1:, %.8f, %.8f" % (n_prc, c_1)) q_f = (1 - np.abs(n_prc))**c_1 if q_f < 0.4: q_f = 0.4 return(q_f)
[docs] @staticmethod def calc_m_ip_cw_rd_draft( beta, n_prc, material, t_c, h_c, h_b, b_curve, gamma_m5 ): f_yield = material.f_y_nominal #f_ultimate = material.f_u_nominal e_modulus = material.e_modulus q_f = TjointRHS.calc_q_f(beta, n_prc) c_f = TjointRHS.calc_c_f(material) f_b = TjointRHS.calc_f_b(h_c, t_c, e_modulus, f_yield, b_curve) logging.debug( "beta, q_f, c_f, f_b, t_c, h_b, h_c: %.6f %.6f, %.6f, %.6f, %.6f, %.6f, %.6f" % (beta, q_f, c_f, f_b, t_c, h_b, h_c) ) m_ip_cw_rd_draft = 0.5*c_f*f_b*t_c*(h_b+ 5*t_c)**2*q_f/gamma_m5 return m_ip_cw_rd_draft
[docs] @staticmethod def calc_m_ip_cf_rd_draft( beta, n_prc, t_c, h_b, b_c, material, gamma_m5 ): f_yield = material.f_y_nominal f_ultimate = material.f_u_nominal eta = h_b/b_c q_f = TjointRHS.calc_q_f(beta, n_prc) c_f = TjointRHS.calc_c_f(material) m_ip_cf_rd_draft = c_f*f_yield*t_c**2*h_b*( 1./(2*eta) + 2./(np.sqrt(1. - beta)) + eta/(1. - beta) )*q_f/gamma_m5 return m_ip_cf_rd_draft
[docs] @staticmethod def calc_m_ip_bf_rd_draft( material, t_c, b_b, b_c, t_b, w_pl_b, h_b, gamma_m5 ): # beam (brace) failure. c_f = TjointRHS.calc_c_f(material) f_yield = material.f_y_nominal b_eff = ( 10*f_yield*t_c**2*b_b )/( b_c*f_yield*t_b ) if b_eff > b_b: b_eff = b_b logging.info( "Beam effective width (identical to EN), b_eff: %.3f" % b_eff ) m_ip_bf_rd_draft = c_f*f_yield * ( w_pl_b - ( 1 - b_eff/b_b )*b_b*(h_b - t_b)*t_b )/gamma_m5 return m_ip_bf_rd_draft
[docs]def test(): #column = ( 100., 100., 4.) #beam = (100., 100., 4.) n_prc_col = 1. n_prc_beam = 0. # Material from measured values #material_col = sd.Material(210000., 0.3, 405.) material_col = sd.Material(210000., 0.3, 405.) material_col.f_u_nominal = 510. material_beam = sd.Material(210000., 0.3, 435.) material_beam.f_u_nominal = 510. # Loop through n_prc values. sp = TjointRHS.from_slend_beta_m_prc_jj( 29.1059637732585, 100.1, 20.611, 0.9, 0.9, n_prc_beam=0, material_col=material_col, material_beam=material_beam, length_c=1102. ) return(sp)