Source code for simdesign.rcmrf.bdim.eu_cdh.column

"""This module provides the column class implementation for the ``eu_cdh``
design class in the BDIM layer.
"""
# Imports from installed packages
from math import ceil
import numpy as np

# Imports from the design class (eu_cdh) library
from .materials import Steel, Concrete

# Imports from bdim base library
from ..baselib.column import ColumnBase

# Imports from units library
from ....utils.units import MPa, m

# Constants
ECONOMIC_MU: float = 0.25
"""Maximum mu value considered for the economic column design."""
MAX_NIU = 0.65
"""Maximum allowed value of axial load ratio.
For DCM columns, 0.65 according to Eurocode 8 - Part 1: 5.4.3.2.1(3)P
For DCH columns, 0.55 according to Eurocode 8 - Part 1: 5.5.3.2.1(3)P
"""
BETA_FC_VECTOR = [1.00, 0.93, 0.88, 0.88, 0.93]
"""Stress block coefficients for different axial load ratio (in REBAP 1983)."""
NIU_VECTOR = [0.40, 0.50, 0.60, 0.70, 0.85]
"""Axial load ratio corresponding to each stress block coefficient."""


[docs] class Column(ColumnBase): """Column implementation for design class ``eu_cdh``. This class extends ``ColumnBase`` by narrowing the attribute types and overriding design methods per Eurocodes 2 and 8. Attributes ---------- steel : ~simdesign.rcmrf.bdim.eu_cdh.materials.Steel Steel material assigned to the column. concrete : ~simdesign.rcmrf.bdim.eu_cdh.materials.Concrete Concrete material assigned to the column. See Also -------- :class:`~bdim.baselib.column.ColumnBase` Base class defining the core behaviour and configuration. References ---------- Comité Européen de Normalisation, CEN (2004). Eurocode 2: Design of Concrete Structures — Part 1-1: General Rules and Rules for Buildings. European Committee for Standardization, Brussels, Belgium. Comité Européen de Normalisation, CEN (2004). Eurocode 8: Design of Structures for Earthquake Resistance — Part 1: General Rules, Seismic Actions and Rules for Buildings. European Committee for Standardization, Brussels, Belgium. d'Arga e Lima, J., Monteiro, V., Mun, M. (2005). Betão armado: esforços normais e de flexão: REBAP-83. Laboratório Nacional de Engenharia Civil, Lisboa. """ steel: Steel concrete: Concrete @property def Ix_eff(self) -> float: """ Returns ------- float Effective column moment of inertia around x-axis. """ return 0.5 * self.Ix # EN 1998-1:2004 4.3.1(7) @property def Iy_eff(self) -> float: """ Returns ------- float Effective column moment of inertia around y-axis. """ return 0.5 * self.Iy # EN 1998-1:2004 4.3.1(7) @property def rhol_max(self) -> float: """ Returns ------- float Maximum longitudinal reinforcement ratio. """ return 0.04 # EN 1992-1-1:2004 9.5.2(3) @property def rhol_min(self) -> float: """ Returns ------- float Minimum longitudinal reinforcement ratio. """ min_tensile_force = min( self.envelope_forces.N1_pos, self.envelope_forces.N9_pos, ) if min_tensile_force > 0.0: # Tensile axial force Ned = 0.0 else: # Compressive axial force Ned = min( abs(self.envelope_forces.N1_neg), abs(self.envelope_forces.N9_neg), ) # EN 1992-1-1:2004 9.5.2(2) rhol_min_ec2 = max(0.1 * Ned / self.fsyd, 0.002 * self.Ag) / self.Ag # 0.01 is introduced as a rule of thumb from practical point. # It is not a code requirement. return max(0.01, rhol_min_ec2) @property def rhoh_min(self) -> float: """ Returns ------- float Minimum transverse reinforcement ratio. Notes ----- The equation used herein is originally defined for beams. We keep using it for columns just to ensure safety. """ # EN 1992-1-1:2004, 9.2.2(5), Eqn. 9.5N return 0.08 * ((self.fck / MPa) ** 0.5) / (self.fsyk / MPa)
[docs] def predesign_section_dimensions(self) -> None: """Make an initial guess for column section dimensions. Notes ----- This method overrides ``ColumnBase.predesign_section_dimensions`` with the following changes: - Minimum cross section area is calculated based on axial load ratio limit from EC8. """ # Initial guess for column concrete area min_area = self.pre_Nd / (self.fcd * MAX_NIU) # Determine initial dimensions if self.section == 1: # Square section self.bx = (min_area**0.5) self.by = (min_area**0.5) elif self.section == 2: # Rectangular section if self.orient == 'x': # Longer dimension is bx self.bx = (2 * min_area) ** 0.5 self.by = 0.5 * self.bx elif self.orient == 'y': # Longer dimension is by self.by = (2 * min_area) ** 0.5 self.bx = 0.5 * self.by # Check against minimum dimensions self.bx = max(ceil(20 * self.bx) / 20, self.min_b) self.by = max(ceil(20 * self.by) / 20, self.min_b)
[docs] def verify_section_adequacy(self) -> None: """Verify the adequacy of section dimensions for design forces. Notes ----- - In accordance with EN 1992-1-1:2004 5.4.3.2.1(2) biaxial bending is taken into account by decreasing the uniaxial moment of resistance by 30%. """ # Distance from extreme compression fiber to centroid of longitudinal # tension reinforcement. dx = 0.9 * self.bx dy = 0.9 * self.by # Following EC2-1/6.2.3: Members with vertical shear reinforcement # Strength reduction factor for concrete cracked in shear v = 0.6 * (1 - self.fck / (250 * MPa)) # Eqn 6.6N if self.fsyd / self.fsyk >= 0.80: v1 = v # Note 1: Recommended strength reduction factor else: # Note 2: If fsyd is below 80% of fsyk if self.fck <= 60 * MPa: v1 = 0.6 else: v1 = max(0.6 * (1 - self.fck / (200 * MPa)), 0.5) # Coefficient taking account the stress state in the comp. chord alpha_cw = 1.0 # assuming no axial force (tension case), eqn. 6.11aN # Angle between the conc. comp. strut and the beam axis perp. to shear theta = 21.80140948635181 # in degrees, based on eqn. 6.7N theta = 45 # in degrees, based on eqn. 6.7N tan_theta = np.tan(theta * np.pi / 180) # 0.4 - 1.0 cot_theta = 1 / tan_theta # 1.0 - 2.5 # lever arm, i.e., distance between comp. and tens. forces zx = 0.9 * dx zy = 0.9 * dy # Assuming vertical shear reinforcement is provided: Eqn. 6.9 Vrdx = (alpha_cw * self.by * zx * v1 * self.fcd) / ( cot_theta + tan_theta ) Vrdy = (alpha_cw * self.bx * zy * v1 * self.fcd) / ( cot_theta + tan_theta ) # Maximum axial load ratio max_niu = max( self.envelope_forces.N1_pos, self.envelope_forces.N9_pos, abs(self.envelope_forces.N1_neg), abs(self.envelope_forces.N9_neg), ) / (self.Ag * self.fcd) # Maximum moment ratio max_mu_x = max( self.envelope_forces.Mx1_pos, self.envelope_forces.Mx9_pos, abs(self.envelope_forces.Mx1_neg), abs(self.envelope_forces.Mx9_neg), ) / ((self.bx * self.by**2) * self.fcd) max_mu_y = max( self.envelope_forces.My1_pos, self.envelope_forces.My9_pos, abs(self.envelope_forces.My1_neg), abs(self.envelope_forces.My9_neg), ) / ((self.by * self.bx**2) * self.fcd) # Maximum shear force max_Vx = max( self.envelope_forces.Vx1, self.envelope_forces.Vx9 ) max_Vy = max( self.envelope_forces.Vy1, self.envelope_forces.Vy9 ) # Verify the adequacy of the section dimensions if (max_mu_y / 0.70) > ECONOMIC_MU or max_Vx > Vrdx: # Need to increase dimension parallel to global-x self.ok_x = False else: self.ok_x = True if (max_mu_x / 0.70) > ECONOMIC_MU or max_Vy > Vrdy: # Need to increase dimension parallel to global-y self.ok_y = False else: self.ok_y = True if max_niu > MAX_NIU and self.ok_x and self.ok_y: # May increase both dimensions or random one? self.ok_x = False self.ok_y = False
[docs] def compute_required_longitudinal_reinforcement(self) -> None: """Compute the required longitudinal reinforcement for design forces. Notes ----- - In accordance with EN 1992-1-1:2004 5.4.3.2.1(2) biaxial bending is taken into account by decreasing the uniaxial moment of resistance by 30%. """ # Initial longitudinal reinforcement area Aslx_req = 2 * np.pi * 0.25 * ((0.012 * m)**2) # Minimum reinforcement Asly_req = 2 * np.pi * 0.25 * ((0.012 * m)**2) # Minimum reinforcement for force in self.design_forces: # Dimensionless design force quantities niu_1 = (-force.N1) / (self.Ag * self.fcd) niu_9 = (-force.N9) / (self.Ag * self.fcd) mu_x1 = abs(force.Mx1) / ((self.bx * self.by**2) * self.fcd) / 0.7 mu_y1 = abs(force.My1) / ((self.by * self.bx**2) * self.fcd) / 0.7 mu_x9 = abs(force.Mx9) / ((self.bx * self.by**2) * self.fcd) / 0.7 mu_y9 = abs(force.My9) / ((self.by * self.bx**2) * self.fcd) / 0.7 # Determine the required longitudinal reinforcement ratio beta1 = np.interp(niu_1, NIU_VECTOR, BETA_FC_VECTOR) beta9 = np.interp(niu_9, NIU_VECTOR, BETA_FC_VECTOR) lambda_y = 0.5 - self.cover / self.bx lambda_x = 0.5 - self.cover / self.by niuc_1 = niu_1 - 0.85 niuc_9 = niu_9 - 0.85 # Start section if niu_1 < 0.0: # Axial force is tensile # REBAP (1983), pp. 48, eqn. 22 omega_x1 = mu_x1 / (lambda_x * beta1) - niu_1 omega_y1 = mu_y1 / (lambda_y * beta1) - niu_1 elif niu_1 <= 0.85: omega_x1 = (mu_x1 + 0.55 * niu_1 * niuc_1) / (lambda_x * beta1) omega_y1 = (mu_y1 + 0.55 * niu_1 * niuc_1) / (lambda_y * beta1) else: omega_x1 = mu_x1 / (lambda_x * beta1) + niuc_1 omega_y1 = mu_y1 / (lambda_y * beta1) + niuc_1 # End section if niu_9 < 0.0: # Axial force is tensile # REBAP (1983), pp. 48, eqn. 22 omega_x9 = mu_x9 / (lambda_x * beta9) - niu_9 omega_y9 = mu_y9 / (lambda_y * beta9) - niu_9 elif niu_9 <= 0.85: omega_x9 = (mu_x9 + 0.55 * niu_9 * niuc_9) / (lambda_x * beta9) omega_y9 = (mu_y9 + 0.55 * niu_9 * niuc_9) / (lambda_y * beta9) else: omega_x9 = mu_x9 / (lambda_x * beta9) + niuc_9 omega_y9 = mu_y9 / (lambda_y * beta9) + niuc_9 # Compute required reinforcement area on two sides omega_x = max(omega_x1, omega_x9) omega_y = max(omega_y1, omega_y9) Aslx = (0.5 * omega_x * self.Ag * self.fcd / self.fsyd) Asly = (0.5 * omega_y * self.Ag * self.fcd / self.fsyd) # Update the reinforcement area Aslx_req = max(Aslx_req, Aslx) Asly_req = max(Asly_req, Asly) # Save the required longitudinal reinforcement area # on each side, along x and y axes self.Aslx_req = Aslx_req self.Asly_req = Asly_req
[docs] def compute_required_transverse_reinforcement(self) -> None: """Compute the required transverse reinforcement for design forces. """ # Distance of long. bars in tens. to extreme conc. fibers in compr. dx = 0.9 * self.bx dy = 0.9 * self.by # lever arm, i.e., distance between comp. and tens. forces zx = 0.9 * dx zy = 0.9 * dy # Compression strut angle, EN 1992-1-1:2004 eqn. 6.7N """TODO: This could 2.0 for both beams and columns. 1.0 is not ralistic (too conservative).""" cot_theta = 1.0 # 45 degrees # Initial transverse reinforcement area to spacing ratio Ashx_sh_min = self.rhoh_min * self.by Ashy_sh_min = self.rhoh_min * self.bx # Design forces Ved_x = max(self.envelope_forces.Vx1, self.envelope_forces.Vx9) Ved_y = max(self.envelope_forces.Vy1, self.envelope_forces.Vy9) # EN 1992-1-1:2004 6.2.3(3) eqn. 6.8 Ashx_sh = Ved_x / (zx * self.fsyd * cot_theta) Ashy_sh = Ved_y / (zy * self.fsyd * cot_theta) # Save the required ratio of transverse reinforcement area along # x and y axes to the reinforcement spacing self.Ashx_sbh_req = max(Ashx_sh_min, Ashx_sh) self.Ashy_sbh_req = max(Ashy_sh_min, Ashy_sh)
[docs] def check_local_ductility_requirement(self) -> None: """Check local ductility requirement for column. TODO ---- INCOMPLETE ! Compute bi values correctly. Come up with strategy to change transverse reinforcement. 1. First add more stirrup legs, 2. Then, decrease spacing, 3. Then, go back to iterations. Notes ----- Use DCM multi-storey frame for behaviour factor. Assume T1>Tc """ # alpha_u and alpha_1 ratio, EN 1998-1:2004 5.2.2.2(5) alpha_u_1_rat = 1.3 # Multi-storey, multi-bay frame # Behaviour factor, q0, EN 1998-1:2004 5.2.2.2(2) q0 = 3.0 * alpha_u_1_rat # DCM frame # EN 1998-1:2004 5.2.3.4(3) curv_duct = 2 * q0 - 1 # Assuming T1>Tc, use eqn. 5.4 # Check local ductility requirement in EN 1998-1: 2004, eqn. 5.15 b0_x = self.bx - 2 * self.cover - self.dbh nx = self.nbh_x - 1 bi_x = b0_x / nx b0_y = self.by - 2 * self.cover - self.dbh ny = self.nbh_y - 1 bi_y = b0_y / ny # eqn. 5.16a alpha_n = 1 - (2 * nx * bi_x**2 + 2 * ny * bi_y**2) / (6 * b0_x * b0_y) # eqn. 5.16b alpha_s = (1 - self.sbh / (2 * b0_x)) * (1 - self.sbh / (2 * b0_y)) alpha = alpha_n * alpha_s omega_wd_x = self.rhoh_x * (self.fsyd / self.fcd) omega_wd_y = self.rhoh_y * (self.fsyd / self.fcd) alpha_omega_x = alpha * omega_wd_x alpha_omega_y = alpha * omega_wd_y epsyd = self.fsyd / self.Es max_local_curv_duct_x = 0.0 max_local_curv_duct_y = 0.0 for factors in self.seism_comb_grav_facts: forces = factors['G'] * self.forces['G/seismic'] + \ factors['Q'] * self.forces['Q/seismic'] niu_d = -forces.N1 / (self.Ag * self.fcd) tmp_x = 2 * (alpha_omega_x + 0.035) / ( 30 * niu_d * epsyd * (self.by / b0_y)) tmp_y = 2 * (alpha_omega_y + 0.035) / ( 30 * niu_d * epsyd * (self.bx / b0_x)) max_local_curv_duct_x = max(max_local_curv_duct_x, tmp_x) max_local_curv_duct_y = max(max_local_curv_duct_y, tmp_y) # Should we increase shear reinforcement instead? if curv_duct > max_local_curv_duct_x: self.ok_y = False if curv_duct > max_local_curv_duct_y: self.ok_x = False