Source code for simdesign.rcmrf.bnsm.cp02.beam

"""This module provides the beam class implementation for the ``CP01`` model in
the BNSM layer.
"""
# Imports from installed packages
import numpy as np
from typing import Tuple, List

# Imports from bnsm base library
from ..cp01.beam import Beam as BeamCP01

# Imports from utils library
from ....utils.units import MPa
from ....utils.misc import round_list


[docs] class Beam(BeamCP01): """Beam implementation for the ``CP02`` model. This class directly uses the behaviour defined in ``BeamCP01``, but overrides the plastic hinge material definition for rotational degrees of freedoms based on the PhD Thesis of Serkan Hasanoglu. See Also -------- :class:`~BeamCP01` CP01 beam model definition extended by this class. """ def _get_mz_mat_inputs(self) -> Tuple[List[str | float | int], List[str | float | int]]: """Retrieves the material inputs defining the flexural behaviour around local-z for the plastic hinge. Returns ------- mat_inputs_i : List[str | float | int] HystereticSM material model inputs for hinge at the start section. mat_inputs_j : List[str | float | int] HystereticSM material model inputs for hinge at the end section. References --------- Hasanoglu, S. and O'Reilly G. J. (2026). A hysteretic energy-based framework for seismic fragility assessment of ductile reinforced concrete frame buildings """ h = self.design.h ln = self.design.L fc_mpa = self.design.fc_q / MPa fsyl_mpa = self.design.fsyl_q / MPa dbh = self.design.dbh_q dbl = self.design.dbl_b1_q cover = self.design.cover_q rhol = self.rhol_q rhoh = self.rhoh_y_q ls = ln / 2 # Shear span length niu = 0.0 # Axial load ratio, assuming beams do not have any dd = h - cover - dbh - 0.5 * dbl rSsD = ls / dd # shear span to effective depth ratio # Compute yield moments in positive and negative directions at both # end sections of the beam (i and j) - Panagiotakos and Fardis (2001) My_pos, _ = self._compute_yield_point('positive') My_neg, _ = self._compute_yield_point('negative') # Capping moment capacities in positive and negative directions Mc_My = (1.08 ** niu) * (1.38 ** (10*rhol)) * (1.14 ** (0.1*rSsD)) Mc_pos = Mc_My * My_pos Mc_neg = Mc_My * My_neg # Ultimate moment capacities in positive and negative directions Mu_Mc = (0.91 ** (0.01*fc_mpa)) * (0.8 ** (0.1*rSsD)) Mu_pos = Mu_Mc * Mc_pos Mu_neg = Mu_Mc * Mc_neg # Zero moment values in positive and negative directions M0_neg = 0.1 * My_neg M0_pos = 0.1 * My_pos # Yield rotation capacities in positive and negative directions EI_ratio = np.clip(0.08 * (1.25 ** (10*niu)) * (1.2 ** rSsD), 0.2, 0.8) EI_gross = self.Ecm_q * self.design.Iz EIy = EI_gross * EI_ratio theta_y_pos = My_pos * ls / (3 * EIy) theta_y_neg = My_neg * ls / (3 * EIy) # Plastic rotation capacities before capping theta_cap_pl_pos = 0.009 * (0.25 ** (0.01*fc_mpa)) * (0.23 ** niu) * \ (2.17 ** (100*rhol)) ratio_pos_neg = ( np.maximum(0.01, fsyl_mpa * self.rhol_top_q / fc_mpa) / np.maximum(0.01, fsyl_mpa * self.rhol_bot_q / fc_mpa) ) ** 0.225 theta_cap_pl_neg = ratio_pos_neg * theta_cap_pl_pos # Post-capping rotation capacity theta_pc_pos = 0.01 * (0.07 ** niu) * (1.78 ** (100*rhoh)) * \ (1.18 ** (0.01*fsyl_mpa)) theta_pc_neg = 0.01 * (0.07 ** niu) * (1.78 ** (100*rhoh)) * \ (1.18 ** (0.01*fsyl_mpa)) # Post-ultimate rotation capacity theta_pu_pos = 0.0023 * (1.96 ** (0.1*fc_mpa)) * (2.74 ** (100*rhoh)) theta_pu_neg = 0.0023 * (1.96 ** (0.1*fc_mpa)) * (2.74 ** (100*rhoh)) theta_pu_pos = np.minimum(theta_pu_pos, 4*theta_pc_pos) theta_pu_neg = np.minimum(theta_pu_neg, 4*theta_pc_neg) # Rotation values for cyclic loading (HystereticSM material) if self.cyclic_model: # Positive backbone moment_1_pos = My_pos moment_2_pos = Mc_pos moment_3_pos = Mu_pos moment_4_pos = M0_pos theta_1_pos = theta_y_pos theta_2_pos = theta_y_pos + theta_cap_pl_pos theta_3_pos = theta_y_pos + theta_cap_pl_pos + theta_pc_pos theta_4_pos = theta_y_pos + theta_cap_pl_pos + theta_pc_pos + \ theta_pu_pos # Negative backbone moment_1_neg = My_neg moment_2_neg = Mc_neg moment_3_neg = Mu_neg moment_4_neg = M0_neg theta_1_neg = theta_y_neg theta_2_neg = theta_y_neg + theta_cap_pl_neg theta_3_neg = theta_y_neg + theta_cap_pl_neg + theta_pc_neg theta_4_neg = theta_y_neg + theta_cap_pl_neg + theta_pc_neg + \ theta_pu_neg else: # These modifiers were determined based on the suggested # values in ATC 72-1 report # Positive backbone moment_1_pos = My_pos moment_2_pos = 1.1 * Mc_pos moment_3_pos = 1.1 * Mu_pos moment_4_pos = M0_pos theta_1_pos = theta_y_pos theta_2_pos = theta_y_pos + 1.4*theta_cap_pl_pos theta_3_pos = theta_y_pos + 1.4*theta_cap_pl_pos + 2*theta_pc_pos theta_4_pos = theta_y_pos + 1.4*theta_cap_pl_pos + \ 2*theta_pc_pos + 2*theta_pu_pos # Negative backbone moment_1_neg = My_neg moment_2_neg = 1.1 * Mc_neg moment_3_neg = 1.1 * Mu_neg moment_4_neg = M0_neg theta_1_neg = theta_y_neg theta_2_neg = theta_y_neg + 1.4*theta_cap_pl_neg theta_3_neg = theta_y_neg + 1.4*theta_cap_pl_neg + 2*theta_pc_neg theta_4_neg = theta_y_neg + 1.4*theta_cap_pl_neg + \ 2*theta_pc_neg + 2*theta_pu_neg # Pinching factor for strain (or deformation) during reloading pinchx = 0.5 # Pinching factor for stress (or force) during reloading pinchy = 0.5 # Damage due to ductility: D1(mu-1) damage1 = 0.0 # Damage due to energy: D2(Eii/Eult) damage2 = 0.7 # Power used to determine the degraded unloading stiffness beta = 0.2 # The negative ones are based on top (compression) reinforcement # The positive ones are based on bottom (tension) renforcement hinge_i_mat_inputs = [ 'HystereticSM', self.mz_i_mat_tag, moment_1_pos[0], theta_1_pos[0], moment_2_pos[0], theta_2_pos[0], moment_3_pos[0], theta_3_pos[0], moment_4_pos[0], theta_4_pos[0], -moment_1_neg[0], -theta_1_neg[0], -moment_2_neg[0], -theta_2_neg[0], -moment_3_neg[0], -theta_3_neg[0], -moment_4_neg[0], -theta_4_neg[0], pinchx, pinchy, damage1, damage2, beta ] hinge_j_mat_inputs = [ 'HystereticSM', self.mz_j_mat_tag, moment_1_pos[-1], theta_1_pos[-1], moment_2_pos[-1], theta_2_pos[-1], moment_3_pos[-1], theta_3_pos[-1], moment_4_pos[-1], theta_4_pos[-1], -moment_1_neg[-1], -theta_1_neg[-1], -moment_2_neg[-1], -theta_2_neg[-1], -moment_3_neg[-1], -theta_3_neg[-1], -moment_4_neg[-1], -theta_4_neg[-1], pinchx, pinchy, damage1, damage2, beta ] # Rounding to precision hinge_i_mat_inputs = round_list(hinge_i_mat_inputs) hinge_j_mat_inputs = round_list(hinge_j_mat_inputs) return hinge_i_mat_inputs, hinge_j_mat_inputs