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

"""This module provides the column class implementation for the ``eu_cdl``
design class in the BDIM layer.
"""
# Imports from installed packages
from math import ceil
import numpy as np
from typing import Tuple
from scipy.interpolate import RegularGridInterpolator

# Imports from the design class (eu_cdl) 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

# CONSTANTS
ECONOMIC_MU = 0.25
"""Maximum mu value considered for the economic column design."""
MAX_NIU = 1.0
"""Maximum allowed value of axial load ratio."""
TAU_C_VECT = np.array([0.4, 0.45, 0.50, 0.55, 0.60]) * MPa
"""Vector of allowable shear stresses that carried by the concrete or
vector of the design shear strength values of concrete."""
TAU_MAX_VECT = np.array([2.4, 2.7, 3.0, 3.3, 3.6]) * MPa
"""Vector of allowable shear stresses that can be carried by
the column section."""
FCK_CUBE_VECT = np.array([180, 225, 300, 350, 400])
"""Vector of cubic concrete compressive strength values (kg/cm2)."""
MODULAR_RATIO = 15
"""Assumed steel to concrete elastic modular ratio for reinf. computation."""
ABACUS_MU = np.array([
    0.0, 0.0277777777777778, 0.0555555555555556, 0.0833333333333333,
    0.111111111111111, 0.138888888888889, 0.166666666666667,
    0.194444444444444, 0.222222222222222, 0.250000000000000
])
ABACUS_NIU = np.array([
    0.0, 0.0777777777777778, 0.155555555555556, 0.233333333333333,
    0.311111111111111, 0.388888888888889, 0.466666666666667,
    0.544444444444444, 0.622222222222222, 0.700000000000000])
ABACUS_RHOL = np.array([
    [0.0, 0.00970555555555555, 0.0194111111111111, 0.0291166666666667,
     0.0440915555555555, 0.0702232222222222, 0.102243666666667,
     0.131266888888889, 0.164154666666667, 0.198892000000000],
    [0.0, 0.0102261111111111, 0.0205228888888889, 0.0309256666666667,
     0.0472451111111111, 0.0758481111111111, 0.108280777777778,
     0.141384444444444, 0.178964000000000, 0.217524333333333],
    [0.0, 0.0100394444444444, 0.0200788888888889, 0.0301183333333333,
     0.0487321111111111, 0.0823443333333333, 0.117531222222222,
     0.155449111111111, 0.195662444444444, 0.236222222222222],
    [0, 0.00899250000000000, 0.0164730000000000, 0.0235755000000000,
     0.0437693333333333, 0.0865265555555556, 0.127303000000000,
     0.170060666666667, 0.213891555555556, 0.257134666666667],
    [0.0, 0.00529166666666667, 0.0105833333333333, 0.0155798888888889,
     0.0384402222222222, 0.0905643333333333, 0.137157222222222,
     0.185445111111111, 0.232910444444444, 0.279392888888889],
    [0.0, 0.00386794444444444, 0.00794322222222222, 0.0120185000000000,
     0.0384363333333333, 0.0967137777777778, 0.150187333333333,
     0.203398333333333, 0.253433222222222, 0.299813444444444],
    [0.0, 0.00610583333333333, 0.0122116666666667, 0.0204363333333333,
     0.0506684444444444, 0.110025777777778, 0.166942333333333,
     0.220166777777778, 0.271086333333333, 0.315488333333333],
    [0.0, 0.0122712222222222, 0.0262984444444444, 0.0403256666666666,
     0.0718958888888889, 0.129945222222222, 0.186308666666667,
     0.238572111111111, 0.289164000000000, 0.332430555555556],
    [0.0, 0.0195072222222222, 0.0390144444444444, 0.0639063888888889,
     0.100675333333333, 0.156645555555556, 0.210372888888889,
     0.260533555555556, 0.312908111111111, 0.359491777777778],
    [0.0, 0.0309847222222222, 0.0619694444444444, 0.0929541666666667,
     0.132961000000000, 0.185786555555556, 0.239298333333333,
     0.283691888888889, 0.338197000000000, 0.387725000000000]
]) / MODULAR_RATIO
# Interpolator used for retrieving the required column long. reinf. ratio
# NOTE: The values outside the domain are extrapolated
rho_interpolator = RegularGridInterpolator(
    (ABACUS_MU, ABACUS_NIU), ABACUS_RHOL.T,
    method='linear', bounds_error=False, fill_value=None)


[docs] def get_rhol(niu: float, mu_x: float, mu_y: float, fcd: float, fsyd: float) -> Tuple[float, float]: """Get required reinforcement ratio for given dimensionless forces. Parameters ---------- niu : float Normalized axial load or axial load ratio. mu_x : float Normalized moment around x-axis. mu_y : float Normalized moment around y-axis. fcd : float Design concrete compressive strength. fsyd : float Design yield steel strength. Returns ------- Tuple[float, float] Required reinforcement ratio around x and y axes. References ---------- Guerrin, A. (1966). Traité de Béton Armé. Dunod, Paris, France. """ # Page 146 if niu < 0.0: # for tensile force rhol_xm = rho_interpolator((mu_x, 0.001)) rhol_ym = rho_interpolator((mu_y, 0.001)) # 0.50 bcs it will be uniformally distributed over the cross-section rhol_x = rhol_xm - 0.5 * niu * fcd / fsyd rhol_y = rhol_ym - 0.5 * niu * fcd / fsyd else: rhol_x = rho_interpolator((mu_x, niu)) rhol_y = rho_interpolator((mu_y, niu)) return rhol_x, rhol_y
[docs] class Column(ColumnBase): """Column implementation for design class ``eu_cdl``. This class extends ``ColumnBase`` by narrowing the attribute types and overriding design methods per REBA (1967). Attributes ---------- steel : ~simdesign.rcmrf.bdim.eu_cdl.materials.Steel Steel material assigned to the column. concrete : ~simdesign.rcmrf.bdim.eu_cdl.materials.Concrete Concrete material assigned to the column. See Also -------- :class:`~bdim.baselib.column.ColumnBase` Base class defining the core behaviour and configuration. References ---------- REBA (1967). Regulamento de Estruturas de Betão Armado. Decreto N.° 47:723, Lisbon, Portugal. Guerrin, A. (1966). Traité de Béton Armé. Dunod, Paris, France. """ steel: Steel concrete: Concrete @property def fcd_eq(self) -> float: """ Returns ------- float Seismic design concrete compressive strength (in base units). """ return self.concrete.fcd_eq * MPa @property def fsyd_eq(self) -> float: """ Returns ------- float Seismic design steel yield strength (in base units). """ return self.steel.fsyd_eq * MPa @property def rhol_max(self) -> float: """ Returns ------- float Maximum longitudinal reinforcement ratio. """ # Art 70 in REBA (1967) if self.concrete.fck_cube <= 180: return 0.03 elif 180 < self.concrete.fck_cube <= 225: return 0.04 elif 225 < self.concrete.fck_cube <= 300: return 0.05 elif 300 < self.concrete.fck_cube: return 0.06 @property def rhol_min(self) -> float: """ Returns ------- float Minimum longitudinal reinforcement ratio. """ return 0.01 * 0.66
[docs] def predesign_section_dimensions(self) -> None: """Make an initial guess for column section dimensions. Notes ----- It is overwritten for eu_cdl design class with following changes: - In case of the rectangular sections, the longer dimension does no longer need to be twice of shorter one. """ # Initial guess for column concrete area min_area = self.pre_Nd / self.fcd # 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.by = self.min_b self.bx = min_area / self.min_b elif self.orient == "y": # Longer dimension is by self.bx = self.min_b self.by = min_area / self.min_b # 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 apply_section_compatibility(self) -> None: """Modify the section dimensions for square section compatibility. This method is used in design iterations while increasing section dimensions. Notes ----- It is overwritten for eu_cdl design class with following changes: - In case of the rectangular sections, the longer dimension does no longer need to be twice of shorter one. """ if self.section == 1: # Square section # Make both dimensions equal to their maximum self.bx = ceil(20 * max(self.bx, self.by)) / 20 self.by = ceil(20 * max(self.bx, self.by)) / 20 elif self.section == 2: # Rectangular section pass
[docs] def verify_section_adequacy(self) -> None: """Verify the adequacy of section dimensions 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 # Variables considered for section adequacy checks. max_niu = 0.0 max_mu_x = 0.0 max_mu_y = 0.0 max_tau_x = 0.0 max_tau_y = 0.0 # fc to use for calculations fc_map = {'gravity': self.fcd, 'seismic': self.fcd_eq} for force in self.design_forces: # Other force related quantities (normalized) fc = fc_map.get(force.case) niu_1 = abs(force.N1 / (self.Ag * fc)) niu_9 = abs(force.N9 / (self.Ag * fc)) mu_x1 = abs(force.Mx1 / ((self.bx * self.by**2) * fc)) mu_y1 = abs(force.My1 / ((self.by * self.bx**2) * fc)) mu_x9 = abs(force.Mx9 / ((self.bx * self.by**2) * fc)) mu_y9 = abs(force.My9 / ((self.by * self.bx**2) * fc)) tau_x1 = abs(force.Vx1 / (self.by * zx)) tau_y1 = abs(force.Vy1 / (self.bx * zy)) tau_x9 = abs(force.Vx9 / (self.by * zx)) tau_y9 = abs(force.Vy9 / (self.bx * zy)) # update max values max_niu = max(max_niu, niu_1, niu_9) max_mu_x = max(max_mu_x, mu_x1, mu_x9) max_mu_y = max(max_mu_y, mu_y1, mu_y9) max_tau_x = max(max_tau_x, tau_x1, tau_x9) max_tau_y = max(max_tau_y, tau_y1, tau_y9) # Allowable shear stress that can be carried by the beam tau_max = np.interp(self.concrete.fck_cube, FCK_CUBE_VECT, TAU_MAX_VECT) # Verify the adequacy of the section dimensions if max_mu_y > ECONOMIC_MU or max_tau_x > tau_max: # Need to increase dimension parallel to global-x self.ok_x = False else: self.ok_x = True if max_mu_x > ECONOMIC_MU or max_tau_y > tau_max: # 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. """ # fc and fsy to use for calculations fc_map = {'gravity': self.fcd, 'seismic': self.fcd_eq} fsy_map = {'gravity': self.fsyd, 'seismic': self.fsyd_eq} # Initial longitudinal reinforcement area Aslx_req = 0.0 Asly_req = 0.0 for force in self.design_forces: # Design strength values considered for this combo fc = fc_map.get(force.case) fsy = fsy_map.get(force.case) # Dimensionless design force quantities niu_1 = (-force.N1) / (self.Ag * fc) niu_9 = (-force.N9) / (self.Ag * fc) mu_x1 = abs(force.Mx1) / ((self.bx * self.by**2) * fc) mu_y1 = abs(force.My1) / ((self.by * self.bx**2) * fc) mu_x9 = abs(force.Mx9) / ((self.bx * self.by**2) * fc) mu_y9 = abs(force.My9) / ((self.by * self.bx**2) * fc) # Determine the required longitudinal reinforcement ratio rhol_x1, rhol_y1 = get_rhol(niu_1, mu_x1, mu_y1, fc, fsy) rhol_x9, rhol_y9 = get_rhol(niu_9, mu_x9, mu_y9, fc, fsy) rhol_x = max(rhol_x1, rhol_x9) rhol_y = max(rhol_y1, rhol_y9) Aslx = 0.5 * rhol_x * self.Ag Asly = 0.5 * rhol_y * self.Ag # Update the required area based on maximum Aslx_req = max(Aslx_req, Aslx) Asly_req = max(Asly_req, Asly) # Save the required longitudinal reinforcement area 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. """ # fsy to use for calculations fsy_map = {'gravity': self.fsyd, 'seismic': self.fsyd_eq} # Allowable shear stress that can be carried by the beam tau_c = np.interp(self.concrete.fck_cube, FCK_CUBE_VECT, TAU_C_VECT) # Initial transverse reinforcement area to spacing ratio Ashx_sh_req = 0.0 # along X Ashy_sh_req = 0.0 # along Y for force in self.design_forces: # Design strength values considered for this combo fsy = fsy_map.get(force.case) # Available longitudinal reinforcement Abl_cor = (np.pi * self.dbl_int**2) / 4 Abl_int = (np.pi * self.dbl_int**2) / 4 Aslx = self.nblx_int * Abl_int + 2 * Abl_cor Asly = self.nbly_int * Abl_int + 2 * Abl_cor # Distance of long. bars in tens. to extreme conc. fibers in compr. dx = 0.9 * self.bx dy = 0.9 * self.by # Lever arms zx = 0.9 * dx zy = 0.9 * dy # Design forces Vy1 = abs(force.Vy1) Vx1 = abs(force.Vx1) Vy9 = abs(force.Vy9) Vx9 = abs(force.Vx9) # Allowable shear force in concrete (tauc*b*0.9h) Vcd_x = tau_c * self.by * dx Vcd_y = tau_c * self.bx * dy # Start section -X direction if ( # REBAP-1967 Article 35 Aslx * self.fsyd * zx < Vx1 * dx and force.N1 > 0 ): Ash_sh_x1 = Vx1 / (zx * fsy) elif Vx1 > Vcd_x: Ash_sh_x1 = (Vx1 - Vcd_x) / (zx * fsy) else: Ash_sh_x1 = 0 # Start section -Y direction if ( Asly * self.fsyd * zy < Vy1 * dy and force.N1 > 0 ): Ash_sh_y1 = Vy1 / (zy * fsy) elif Vy1 > Vcd_y: Ash_sh_y1 = (Vy1 - Vcd_y) / (zy * fsy) else: Ash_sh_y1 = 0 # End section -X direction if ( Aslx * self.fsyd * zx < Vx9 * dx and force.N9 > 0 ): Ash_sh_x9 = Vx9 / (zx * fsy) elif Vx9 > Vcd_x: Ash_sh_x9 = (Vx9 - Vcd_x) / (zx * fsy) else: Ash_sh_x9 = 0 # End section -Y direction if ( Asly * self.fsyd * zy < Vy9 * dy and force.N9 > 0 ): Ash_sh_y9 = Vy9 / (zy * fsy) elif Vy9 > Vcd_y: Ash_sh_y9 = (Vy9 - Vcd_y) / (zy * fsy) else: Ash_sh_y9 = 0 # Update the required transverse reinforcement based on maximum Ashx_sh_req = max(Ashx_sh_req, Ash_sh_x1, Ash_sh_x9) Ashy_sh_req = max(Ashy_sh_req, Ash_sh_y1, Ash_sh_y9) # Save the required transverse reinforcement area to spacing ratio self.Ashx_sbh_req = Ashx_sh_req self.Ashy_sbh_req = Ashy_sh_req