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

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

# Imports from bnsm base library
from ..baselib.beam import BeamBase, HYSTERETIC_PARAMETERS
from .column import STIFF_INTERIOR_FACTOR

# Imports from utils library
from ....utils.misc import round_list, PRECISION
from ....utils.tags import sub_tag


[docs] class Beam(BeamBase): """Beam implementation for the ``CP01`` model. The beam is modeled using a concentrated plasticity approach. Plastic rotations are concentrated at the element ends via ``beamIntegration('ConcentratedPlasticity', ...)`` (end hinge integration points with an elastic interior region), while the element formulation is provided by ``BeamBase``. End-hinge flexural behaviour about the local z-axis (Mz) is defined using a uniaxial ``Hysteretic`` material, expressed in terms of bending moment vs. chord rotation of the whole member (the yield rotation includes the elastic deformations). The elastic interior is therefore nearly rigid in flexure about local-z (``STIFF_INTERIOR_FACTOR``), and the springs carry the whole flexural flexibility. See Also -------- :class:`~simdesign.rcmrf.bnsm.baselib.beam.BeamBase` Base beam 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 ------- hinge_i_mat_inputs : List[str | float | int] Hysteretic material model inputs for hinge at the start section. hinge_j_mat_inputs : List[str | float | int] Hysteretic material model inputs for hinge at the end section. """ # Backbone of the plastic hinges ( _, My_neg, Mc_neg, Mr_neg, theta_y_neg, theta_cap_pl_neg, theta_pc_neg, _, My_pos, Mc_pos, Mr_pos, theta_y_pos, theta_cap_pl_pos, theta_pc_pos, ) = self._get_rot_hinge_props() # Rotation values theta_1_neg = theta_y_neg theta_2_neg = theta_1_neg + theta_cap_pl_neg theta_3_neg = theta_2_neg + theta_pc_neg theta_1_pos = theta_y_pos theta_2_pos = theta_1_pos + theta_cap_pl_pos theta_3_pos = theta_2_pos + theta_pc_pos # Material inputs hinge_i_mat_inputs = [ 'Hysteretic', self.mz_i_mat_tag, My_pos[0], theta_1_pos[0], Mc_pos[0], theta_2_pos[0], Mr_pos[0], theta_3_pos[0], -My_neg[0], -theta_1_neg[0], -Mc_neg[0], -theta_2_neg[0], -Mr_neg[0], -theta_3_neg[0], *HYSTERETIC_PARAMETERS ] hinge_j_mat_inputs = [ 'Hysteretic', self.mz_j_mat_tag, My_pos[-1], theta_1_pos[-1], Mc_pos[-1], theta_2_pos[-1], Mr_pos[-1], theta_3_pos[-1], -My_neg[-1], -theta_1_neg[-1], -Mc_neg[-1], -theta_2_neg[-1], -Mr_neg[-1], -theta_3_neg[-1], *HYSTERETIC_PARAMETERS ] # 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 @property def p_mat_tag(self) -> int: """Elastic material tag for the axial response (P) of the hinges.""" return sub_tag(self.design.line.tag, 92) @property def my_mat_tag(self) -> int: """Elastic material tag for the flexural response about local-y (My) of the hinges.""" return sub_tag(self.design.line.tag, 93) @property def t_mat_tag(self) -> int: """Elastic material tag for the torsional response (T) of the hinges.""" return sub_tag(self.design.line.tag, 94)
[docs] def add_to_ops(self) -> None: """Adds beam components to the OpenSees domain (i.e, beam element and nodes). """ # Create the elastic materials of the hinge sections for mat_inputs in self._get_hinge_elastic_mat_inputs(): ops.uniaxialMaterial(*mat_inputs) super().add_to_ops()
[docs] def to_py(self) -> List[str]: """Gets the Python commands to construct beam components in OpenSees domain (i.e, beam element and nodes). Returns ------- List[str] List of Python commands for constructing the components of beam object in OpenSees. """ content = super().to_py() # Create the elastic materials of the hinge sections idx = content.index('# Create element sections') for mat_inputs in reversed(self._get_hinge_elastic_mat_inputs()): mat_inputs = ', '.join( repr(item) if isinstance(item, str) else str(item) for item in mat_inputs ) content.insert(idx, f"ops.uniaxialMaterial({mat_inputs})") return content
[docs] def to_tcl(self) -> List[str]: """Gets the Tcl commands to construct beam components in OpenSees domain (i.e, beam element and nodes). Returns ------- List[str] List of Tcl commands for constructing the components of beam object in OpenSees. """ content = super().to_tcl() # Create the elastic materials of the hinge sections idx = content.index('# Create element sections') for mat_inputs in reversed(self._get_hinge_elastic_mat_inputs()): mat_inputs = ' '.join(f"{item}" for item in mat_inputs) content.insert(idx, f"uniaxialMaterial {mat_inputs}") return content
def _get_hinge_elastic_mat_inputs( self ) -> List[List[str | float | int]]: """Retrieves the elastic material inputs of the hinge sections. Returns ------- List[List[str | float | int]] Inputs of the elastic axial (EA), flexural about local-y (EIy) and torsional (GJ) materials. Notes ----- ``ConcentratedPlasticity`` gives each hinge section a weight of one length unit and removes the same length from the elastic interior. The hinge sections therefore carry the elastic flexibility of that length. With rigid materials, the axial stiffness becomes EA/(L-2), which is negative for clear lengths below 2 m. """ return [ round_list(['Elastic', self.p_mat_tag, self.Ecm_q * self.design.Ag]), round_list(['Elastic', self.my_mat_tag, self.Ecm_q * self.design.Iy]), round_list(['Elastic', self.t_mat_tag, self.Gcm_q * self.design.J]) ] def _get_inelastic_sec_i_inputs(self) -> List[str | int]: """Retrieves inputs for inelastic beam section at ith end. Returns ------- List[str | int] List of inputs for inelastic beam section at ith end, with elastic My, P and T materials. """ sec_inputs = super()._get_inelastic_sec_i_inputs() sec_inputs[6], sec_inputs[10], sec_inputs[12] = \ self.my_mat_tag, self.p_mat_tag, self.t_mat_tag return sec_inputs def _get_inelastic_sec_j_inputs(self) -> List[str | int]: """Retrieves inputs for inelastic beam section at jth end. Returns ------- List[str | int] List of inputs for inelastic beam section at jth end, with elastic My, P and T materials. """ sec_inputs = super()._get_inelastic_sec_j_inputs() sec_inputs[6], sec_inputs[10], sec_inputs[12] = \ self.my_mat_tag, self.p_mat_tag, self.t_mat_tag return sec_inputs def _get_elastic_sec_inputs(self) -> List[str | int | float]: """Retrieves elastic beam section inputs. Returns ------- List[str | int | float] List of elastic beam section inputs. Notes ----- The moment of inertia about local-z (Iz) is multiplied by ``STIFF_INTERIOR_FACTOR``. The backbone rotations are chord rotations of the whole member, so the springs carry the whole flexural flexibility. The weak-axis flexure (Iy) has no spring and keeps its elastic stiffness. """ sec_inputs = super()._get_elastic_sec_inputs() sec_inputs[4] = round(sec_inputs[4] * STIFF_INTERIOR_FACTOR, PRECISION) return sec_inputs def _get_int_inputs(self) -> List[str | float]: """Retrieves beam integration inputs. Returns ------- List[float] List of beam integration inputs. """ int_inputs = [ 'ConcentratedPlasticity', self.int_tag, self.inelastic_sec_i_tag, self.inelastic_sec_j_tag, self.elastic_sec_tag ] return int_inputs