def bolt_design(self): """Calculate bolt capacities, distances and layout. Args: Returns: """ self.root_clearance_sa = 1.5 * self.bolt_diameter self.root_clearance_col = 1.5 * self.bolt_diameter self.bolt_hole_clearance_value = self.bolt_hole_clearance( self.bolt_hole_type, self.bolt_diameter) self.bolt_hole_diameter = self.bolt_diameter + self.bolt_hole_clearance_value self.thickness_governing_min = min(self.column_f_t, self.angle_t) self.calculate_distances(self.bolt_diameter, self.bolt_hole_diameter, self.min_edge_multiplier, self.thickness_governing_min, self.is_environ_corrosive) self.max_spacing = min(self.max_spacing, 32 * self.thickness_governing_min) self.edge_dist = self.min_edge_dist self.end_dist = self.min_end_dist self.pitch = self.min_pitch self.edge_dist = ConnectionCalculations.round_up_5(self.edge_dist) self.end_dist = ConnectionCalculations.round_up_5(self.end_dist) self.calculate_kb() # Bolt capacity if self.is_hsfg is False: self.bolt_shear_capacity = ConnectionCalculations.bolt_shear( bolt_diameter=self.bolt_diameter, number_of_bolts=1, bolt_fu=self.bolt_fu) self.bolt_bearing_capacity = ConnectionCalculations.bolt_bearing( bolt_diameter=self.bolt_diameter, number_of_bolts=1, thickness_plate=self.thickness_governing_min, k_b=self.k_b, plate_fu=self.beam_fu) self.bolt_value = min(self.bolt_shear_capacity, self.bolt_bearing_capacity) elif self.is_hsfg: self.bolt_shear_capacity = ConnectionCalculations.bolt_shear_hsfg( self.bolt_diameter, self.bolt_fu, self.mu_f, self.n_e, self.bolt_hole_type) self.bolt_bearing_capacity = 0.000 self.bolt_value = self.bolt_shear_capacity # Check for long joints is not applicable for seated angle connection self.bolts_required = int( math.ceil(float(self.shear_force) / self.bolt_value))
def top_angle_section(self): """Identify appropriate top angle size based on beam depth. Args: Returns: top_angle(string): top angle section Note: Assumptions: Calculating top angle dimensions based on thumb rules: top_angle_side = beam_depth/4 top_angle_thickness = top_angle_side/10 Select the nearest available equal angle as the top angle. Equal angles satisfying both these thumb rules are selected for this function from steel tables """ # minimum length of leg of top angle is twice edge distance + angle thickness. # as the side length is rounded up in the next step, ignoring angle thickness while calculating # minimum length of side top_angle_side_minimum = 2 * self.min_edge_multiplier * self.bolt_hole_diameter # twice edge distance top_angle_side = max(float(self.beam_d) / 4, top_angle_side_minimum) # round up to nearest 5 mm. '+2' for conservative round up. top_angle_side = ConnectionCalculations.round_up_5(top_angle_side + 2) try: top_angle = { 20: "20 20 X 3", # does not satisfy min edge dist req for 12 mm bolt 25: "25 25 X 3", # does not satisfy min edge dist req for 12 mm bolt 30: "30 30 X 3", # does not satisfy min edge dist req for 12 mm bolt 35: "35 35 X 4", # does not satisfy min edge dist req for 12 mm bolt 40: "40 40 X 4", 45: "45 45 X 5", 50: "50 50 X 5", 55: "55 55 X 6", 60: "60 60 X 6", 65: "65 65 X 6", 70: "70 70 X 7", 75: "75 75 X 8", 80: "80 80 X 8", 90: "90 90 X 10", 100: "100 100 X 10" }[top_angle_side] except KeyError: top_angle = " cannot compute" return top_angle
def seat_angle_connection(self, input_dict): """ Perform design and detailing checks based for seated angle connection. Args: input_dict (dictionary) Returns: output_dict (dictionary) Note: Algorithm: 1) Initialise variables to use 2) Bolt Design (layout and spacing) 3) Determine length of outstanding leg of seated angle 4) Determine shear strength of outstanding leg and compare with capacity """ self.sa_params(input_dict) self.clear_col_space = self.column_d - 2 * self.column_f_t - 2 * self.column_R1 - 2 * self.root_clearance_col if self.connectivity == "Column web-Beam flange" and self.beam_b > self.clear_col_space: self.safe = False logger.error(": Compatibility failure") logger.warning(": Beam width (%s mm) is greater than the clear space available" + \ " between column flanges (%s mm)" % self.clear_col_space, self.beam_b) logger.info(": Select compatible beam and column sizes") self.bolt_design() if self.top_angle_recommended != self.top_angle: logger.warning( ": Based on thumb rules, a top angle of size %s is sufficient to provide stability to %s ", self.top_angle_recommended, self.beam_section) self.top_angle_end_dist_column = ( float(self.top_angle_A) - self.top_angle_t - self.top_angle_R1 - self.top_angle_R2) / 2 + self.top_angle_R2 self.top_angle_end_dist_beam = ( float(self.top_angle_B) - self.top_angle_t - self.top_angle_R1 - self.top_angle_R2) / 2 + self.top_angle_R2 self.seat_angle_end_dist_beam = (float(self.angle_B) - self.angle_t - self.angle_R1 - self.angle_R2) / 2 + self.angle_R2 self.top_angle_end_dist_column = ConnectionCalculations.round_up_5( self.top_angle_end_dist_column) self.top_angle_end_dist_beam = ConnectionCalculations.round_up_5( self.top_angle_end_dist_beam) self.seat_angle_end_dist_beam = ConnectionCalculations.round_up_5( self.seat_angle_end_dist_beam) if self.top_angle_end_dist_column < self.min_end_dist: self.safe = False logger.error(": Detailing failure for the top angle") logger.warning( ": Minimum end distance for the selected bolt is %2.2f mm [cl. 10.2.2] " % self.min_end_dist) logger.info( ": Select bolt with lower grade/diameter to reduce minimum end distances" ) logger.info(": or increase leg A of the top angle") if self.top_angle_end_dist_beam < self.min_end_dist: self.safe = False logger.error(": Detailing failure for the top angle") logger.warning( ": Minimum end distance for the selected bolt is %2.2f mm [cl. 10.2.2] " % self.min_end_dist) logger.info( ": Select bolts with a lower grade/diameter to reduce the minimum end distances required" ) logger.info(": or Increase leg B of the top angle") if self.seat_angle_end_dist_beam < self.min_end_dist: self.safe = False logger.error(": Detailing failure for the seat angle") logger.warning( ": Minimum end distance for the selected bolt is %2.2f mm [cl. 10.2.2] " % self.min_end_dist) logger.info( ": Select bolts with a lower grade/diameter to reduce the minimum end distances required" ) logger.info(": or increase leg B of the seat angle") # To avoid bolts intersecting the column web in CFBF connectivity: if self.connectivity == "Column flange-Beam flange": if self.bolts_required == 3: self.bolts_required = 4 elif self.bolts_required == 5: self.bolts_required = 8 logger.info(": 5 bolts are required but 8 are being provided") logger.info(": Select bolts with a higher grade/diameter") elif self.bolts_required == 6: self.bolts_required = 8 logger.info(": 6 bolts are required but 8 are being provided") logger.info( ": It is recommended to increase the bolt grade or bolt diameter" ) elif self.bolts_required == 7: self.bolts_required = 8 logger.info(": 7 bolts are required but 8 are being provided") logger.info( ": It is recommended to increase the bolt grade or bolt diameter" ) self.bolt_group_capacity = round(self.bolts_required * self.bolt_value, 1) if self.connectivity == "Column web-Beam flange": limiting_angle_length = self.column_d - 2 * self.column_f_t - 2 * self.column_R1 - self.root_clearance_col self.angle_l = int( math.ceil(min(self.beam_b, limiting_angle_length))) elif self.connectivity == "Column flange-Beam flange": self.angle_l = int(math.ceil(min(self.beam_b, self.column_b))) if self.angle_t < 6: logger.warning( ": Minimum thickness of 6 mm is recommended for the seat angle" ) logger.warning(": Please revise the seat angle section") # Determine single or double line of bolts length_avail = (self.angle_l - 2 * self.edge_dist) # Determine gauge for two bolts (to be used for top angle) self.gauge_two_bolt = length_avail self.num_rows = 1 self.num_cols = max(self.bolts_required, 2) self.gauge = round(int(math.ceil(length_avail / (self.num_cols - 1))), 3) if self.gauge < self.min_gauge: self.num_rows = 2 if self.bolts_required % 2 == 1: self.bolts_provided = self.bolts_required + 1 else: self.bolts_provided = self.bolts_required self.num_cols = self.bolts_provided / 2 if self.num_cols == 1: self.safe = False logger.error(": Detailing failure") logger.warning( ": Minimum gauge distance for selected bolt is %2.2f mm [cl. 10.2.2] " % self.min_gauge) logger.warning( ": Minimum edge distance for selected bolt is %2.2f mm [cl. 10.2.4.2]" % self.min_edge_dist) logger.warning( ": Available length of the seat angle is %2.2f mm " % self.angle_l) logger.warning( ": 2 bolts of the selected diameter cannot fit in the available length of the seat angle" ) logger.info( ": Select bolts with a lower grade/diameter to reduce minimum gauge and edge distances required)" ) else: self.gauge = int(math.ceil(length_avail / (self.num_cols - 1))) if self.gauge < self.min_gauge: self.safe = False logger.error(": Detailing failure") logger.error( ": Bolt gauge %2.0f mm is less than the minimum gauge distance [cl. 10.2.2]" % self.gauge) logger.warning( ": Bolt gauge should be more than %2.2f mm " % self.min_gauge) logger.warning( ": Maximum gauge distance allowed is %2.2f mm " % self.max_spacing) logger.info( ": Select bolts with a higher grade/diameter to reduce the number of bolts)" ) if self.gauge > self.max_spacing: """ Assumption: keeping minimum edge distance the same and increasing the number of bolts, to meet the max spacing requirement. 1) set gauge = max spacing 2) get approx (conservative) number of bolts per line based on this gauge 3) use the revised number of bolts per line to get revised gauge distance The engineer can choose to use a different logic by keeping the number of bolts same, and increasing the edge distance. # gauge = max_spacing # edge_distance = (angle_l - (bolts_per_line-1)*gauge)/2 """ self.gauge = int(math.ceil(self.max_spacing)) self.num_cols = int(math.ceil((length_avail / self.gauge) + 1)) self.gauge = round( int(math.ceil(length_avail / (self.num_cols - 1))), 3) # End-user-developers may uncomment the below lines for an additional compatibility check # if self.connectivity == "Column flange-Beam flange": # if self.gauge < self.column_w_t + 2*self.column_R1: # self.safe = False # logger.error(": Detailing failure") # logger.warning(": Bolt passes through the column root") # logger.info(": Increase the bolt gauge by reducing the number of bolts") if self.min_pitch > self.max_pitch: """ Assumption: This unlikely case could occur when the minimum pitch (which is governed by the bolt diameter), is greater than the maximum pitch (which is governed by thickness of connected member(s)). It is recommended to decrease the bolt diameter or increase the thickness of the connected members. """ self.safe = False logger.error( ": Calculated minimum pitch is greater than calculated (rounded) maximum pitch" ) logger.warning(": Bolt pitch should be more than %2.2f mm " % self.min_pitch) logger.warning(": Bolt pitch should be less than %2.2f mm " % self.max_pitch) logger.info(": Select bolts with a smaller diameter OR") logger.info( ": Select a connected member with a greater thickness.)") self.bolts_provided = self.num_cols * self.num_rows self.bolt_group_capacity = round(self.bolts_provided * self.bolt_value, 1) if self.num_rows == 1: self.pitch = 0 elif self.num_rows == 2: self.pitch = self.min_pitch self.end_dist = self.angle_A - self.angle_t - self.angle_R1 - self.root_clearance_sa - self.pitch self.end_dist = ConnectionCalculations.round_down_5(self.end_dist) self.pitch = (self.angle_A - self.angle_t - self.angle_R1 - self.root_clearance_sa - self.end_dist) * \ (self.num_rows - 1) if self.end_dist < self.min_end_dist: self.safe = False logger.error(": Detailing error") logger.error( ": Calculated bolt end distance is smaller than the minimum end distance" ) logger.warning(": End distance should be more than %2.2f mm " % self.min_end_dist) logger.info(": Select bolts with a smaller diameter OR") logger.info(": Select a seat angle with longer vertical leg.") root_3 = math.sqrt(3) # Approximate shear capacity of beam, Vd = A_v*F_yw/root_3/gamma_m0 cl. 8.4.1 self.beam_shear_strength = round( self.beam_d * self.beam_w_t * float(self.beam_fy) / root_3 / self.gamma_m0 / 1000, 1) if self.beam_shear_strength < float(self.shear_force): self.safe = False logger.error( ": Shear capacity of the supported beam is not sufficient [cl. 8.4.1]" ) logger.warning( ": Shear capacity of the supported beam should be at least %2.2f kN" % float(self.shear_force)) logger.warning(": Beam design is outside the scope of this module") # length of bearing required at the root line of beam (b) = R*gamma_m0/t_w*f_yw # Rearranged equation from cl. 8.7.4 bearing_length = round((float(self.shear_force) * 1000) * self.gamma_m0 / self.beam_w_t / self.angle_fy, 3) # logger.info(": Length of the bearing required at the root line of beam = " + str(bearing_length)) # Required length of outstanding leg = bearing length + beam_col_clear_gap - beam_flange_thickness # (-beam_flange_thickness) comes from the 45 degree dispersion, but is conservatively not taken into account # while calculating the outstanding_leg_length self.outstanding_leg_length_required = bearing_length + self.beam_col_clear_gap if self.outstanding_leg_length_required > self.angle_B: self.safe = False logger.error( ": Length of the outstanding leg of the seat angle is less than the required bearing length [cl. 8.7.4]" ) logger.warning( ": Outstanding leg length should be more than %2.2f mm" % self.outstanding_leg_length_required) logger.info(": Select seated angle with longer outstanding leg") """ comparing 0.6*shear strength (0.6*V_d) vs shear force V for calling moment capacity routine Shear capacity check cl. 8.4.1 Shear capacity of the outstanding leg of cleat = A_v * f_yw / root_3 / gamma_m0 = w*t*fy/gamma_m0/root_3 """ self.outstanding_leg_shear_capacity = round( self.angle_l * self.angle_t * self.angle_fy * 0.001 / root_3 * self.gamma_m0, 1) # kN if self.outstanding_leg_shear_capacity < self.shear_force: self.safe = False required_angle_thickness_shear = math.ceil( self.shear_force * self.angle_t / self.outstanding_leg_shear_capacity) logger.error( ": Shear capacity of outstanding leg of seated angle is insufficient [cl. 8.4.1]" ) logger.warning( ": Shear capacity of outstanding leg of seated angle is %2.2f kN" % float(self.outstanding_leg_shear_capacity)) logger.warning( ": Shear capacity should be more than factored shear force %2.2f kN" % float(self.shear_force)) logger.info( ": Select a seat angle with thickness greater than %2.1f mm" % required_angle_thickness_shear) # based on 45 degree dispersion cl. 8.7.1.3, stiff bearing length (b1) is calculated as # (stiff) bearing length on cleat (b1) = b - T_f (beam flange thickness) - r_b (root radius of beam flange) b1 = max(bearing_length - self.beam_f_t - self.beam_R1, bearing_length / 2) # Distance from the end of bearing on cleat to root angle OR A TO B in Fig 5.31 in Subramanian's book b2 = max(b1 + self.beam_col_clear_gap - self.angle_t - self.angle_R1, 0) """Check moment capacity of outstanding leg Assumption: 1) load is uniform over the stiff bearing length (b1) 2) Moment (demand) is calculated at root of angle (at location B) due to load on the right of location B Shear force is compared against 0.6*shear capacity of outstanding leg to use appropriate moment capacity equation """ if b1 > 0.1: self.moment_at_root_angle = round( float(self.shear_force) * (b2 / b1) * (b2 / 2), 1) if self.shear_force * self.shear_force < 1 or b2 == 0 or b1 < 0.1 or self.moment_at_root_angle < 0: self.safe = False logger.warning( ": Calculated moment demand on the angle leg is %s " % self.moment_at_root_angle) logger.debug( ": The algorithm used to calculate this moment could give erroneous values due to one or " + "more of the following:") logger.debug(": a) Very low value of shear force ") logger.debug( ": b) Large seat angle section and a low value of the gap between beam and column" ) logger.debug( ": c) Large beam section and a low value of the shear force") logger.debug(": Please verify the results manually ") self.moment_at_root_angle = 0.0 """ Assumption 1) beta_b (in the equation in cl. 8.2.1.2) = 1.0 as the outstanding leg is plastic section 2) using Z_e (Elastic section modulus) for moment capacity """ self.leg_moment_d = (self.angle_fy / self.gamma_m0) * ( self.angle_l * self.angle_t**2 / 6) / 1000 if float( self.shear_force) <= 0.6 * self.outstanding_leg_shear_capacity: angle_moment_capacity_clause = "cl. 8.2.1.2" self.is_shear_high = False # to avoid irreversible deformation (in case of cantilever), # under service-ability loads, moment_d shall be less than 1.5*Z_e*f_y/gamma_m0 leg_moment_d_limiting = 1.5 * (self.angle_fy / self.gamma_m0) * ( self.angle_l * self.angle_t**2 / 6) / 1000 angle_outst_leg_mcapacity = min(self.leg_moment_d, leg_moment_d_limiting) else: self.is_shear_high = True angle_moment_capacity_clause = "cl. 8.2.1.3" """ cl. 8.2.1.3 if shear force > 0.6 * shear strength of outstanding leg: The moment capacity of the outstanding leg is calculated as, M_d = M_dv (as defined in cl. 9.2) cl. 9.2.2 for plastic section Assumption : M_fd=0 as the shear resiting area and moment resisting area are the same, for the cross section of the outstanding leg Thus, M_dv = min ((1-beta)*M_d, 1.2*Z_e*f_y/gamma_m0) where, beta = ((2V/V_d) - 1)^2 """ leg_moment_d_limiting = 1.2 * (self.angle_fy / self.gamma_m0) * ( self.angle_l * self.angle_t**2 / 6) / 1000 beta_moment = ((2 * float(self.shear_force) / self.outstanding_leg_shear_capacity) - 1)**2 angle_outst_leg_mcapacity = min( (1 - beta_moment) * self.leg_moment_d, leg_moment_d_limiting) self.moment_high_shear_beta = beta_moment self.moment_capacity_angle = round(angle_outst_leg_mcapacity, 1) if self.moment_capacity_angle < self.moment_at_root_angle: self.safe = False logger.error( ": Moment capacity of the outstanding leg of the seat angle is not sufficient " + angle_moment_capacity_clause) logger.warning(": Moment capacity should be at least %2.2f kN-mm" % self.moment_at_root_angle) logger.info( ": Increase thickness or decrease length of the outstanding leg of the seat angle" ) """ Check for local buckling capacity of web of supported beam (cl. 8.7.3.1) Variables are prefixed with bwlb: beam web local buckling Assumptions: 1) Effective length of web of supported beam (8.7.1.5) [KL = L] 2) steel_E = 200000 MPa 3) Effective sectional area for computing design compressive strength P_d (7.1.2) is taken as indicated in (8.7.3.1) """ # Area of cross section of beam web: bwlb_b1 = b1 # width of stiff bearing on flange (8.7.1.3) # Dispersion of the load through the web at 45 degree, to the level of half the depth of the cross-section bwlb_n1 = self.beam_d / 2 - self.beam_R1 - self.beam_f_t # Effective length of web of supported beam (8.7.1.5) assumed KL = L bwlb_KL = self.beam_d - 2 * self.beam_f_t - 2 * self.beam_R1 # For calculating design compressive strength of web of supported beam (7.1.2.1) steel_E = 200000 # MPa bwlb_lambda = (bwlb_KL * 2 * root_3 / self.beam_w_t / math.pi) * math.sqrt(float(self.beam_fy) / steel_E) bwlb_alpha = 0.49 # Imperfection factor for buckling class 'c' (IS 800 - Table 7 and 8.7.3.1) bwlb_phi = 0.5 * (1 + bwlb_alpha * (bwlb_lambda - 0.2) + bwlb_lambda**2) bwlb_chi = max((bwlb_phi + (bwlb_phi**2 - bwlb_lambda**2)**0.5)**(-1), 1.0) bwlb_f_cd = bwlb_chi * float(self.beam_fy) / self.gamma_m0 # Design compressive strength (7.1.2) bwlb_P_d = (bwlb_b1 + bwlb_n1) * bwlb_f_cd self.beam_web_local_buckling_capacity = bwlb_P_d if self.beam_web_local_buckling_capacity < self.shear_force: self.safe = False logger.error( ": Local buckling capacity of the web of the supported beam is less than the shear force [cl. 8.7.3.1]" ) logger.warning(": Local buckling capacity is %2.2f kN-mm" % self.beam_web_local_buckling_capacity) logger.info( ": Increase the length of the outstanding leg of the seat angle to increase the stiff bearing length" ) # End of calculation # --------------------------------------------------------------------------- self.sa_output() if self.output_dict['SeatAngle']['status'] is True: logger.info(": Overall seated angle connection design is safe") logger.debug(": =========End Of design===========") else: logger.error(": Design is not safe") logger.debug(": =========End Of design===========") return self.output_dict