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

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

# Imports from bnsm library
from ..dp03.beam import Beam as BeamDP03
from ..baselib.node import Node
from ..baselib.constants import RIGID_MAT

# Imports from utils library
from ....utils.tags import node_tag, TYPE_UNIT


[docs] class Beam(BeamDP03): """Beam implementation for the ``DP05`` model. This class extends the ``DP03`` beam (fiber end sections) with an axial release at the end section (*j-end*). The beam element frames into an auxiliary node, ``ele_node_j``, which is connected to the beam-side joint node, ``release_node``, by a ``zeroLength`` element. The release is free along the beam axis and rigid in the transverse translations and in the rotations, so the beam can elongate as its fiber sections crack and yield, although the joint nodes are constrained by the rigid floor diaphragm. The beam then carries no axial force. The mid-storey stairs beams have no release (see :meth:`~simdesign.rcmrf.bnsm.dp05.building.Building._initialize_beams`). Attributes ---------- release_node : Node | None Beam-side joint node at the *j-end*, constrained by the floor diaphragm. None if the beam has no release. See Also -------- :class:`~simdesign.rcmrf.bnsm.dp03.beam.Beam` Beam definition extended by this class. """ release_node: Optional[Node] = None @property def release_ele_tag(self) -> int: """ Returns ------- int Tag of the ``zeroLength`` element of the axial release, equal to the tag of the auxiliary node. """ return self.ele_node_j.tag
[docs] def set_axial_release(self) -> None: """Moves the *j-end* of the beam element to an auxiliary node at the location of the joint node, which becomes the ``release_node``. The auxiliary node takes the tag of the beam-side node of the joint, i.e., ``left`` for beams along x and ``rear`` for beams along y, which is unique for each beam end. """ self.release_node = self.ele_node_j point = self.release_node.tag % TYPE_UNIT side = 'left' if self.design.direction == 'x' else 'rear' self.ele_node_j = Node(node_tag(point, side), self.release_node.coordinates.copy())
[docs] def add_to_ops(self) -> None: """Adds beam components to the OpenSees domain (i.e, auxiliary node, axial release, fiber sections and beam element). """ if self.release_node is not None: self.ele_node_j.add_to_ops() ops.element(*self._get_release_ele_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, auxiliary node, axial release, fiber sections and beam element). Returns ------- List[str] List of Python commands for constructing the components of beam object in OpenSees. """ if self.release_node is None: return super().to_py() release_inputs = ', '.join( repr(item) if isinstance(item, str) else str(item) for item in self._get_release_ele_inputs() ) content = ['# Create the auxiliary node and the axial release'] content.append(self.ele_node_j.to_py()) content.append(f"ops.element({release_inputs})") return content + super().to_py()
[docs] def to_tcl(self) -> List[str]: """Gets the Tcl commands to construct beam components in OpenSees domain (i.e, auxiliary node, axial release, fiber sections and beam element). Returns ------- List[str] List of Tcl commands for constructing the components of beam object in OpenSees. """ if self.release_node is None: return super().to_tcl() release_inputs = ' '.join( f'{item}' for item in self._get_release_ele_inputs()) content = ['# Create the auxiliary node and the axial release'] content.append(self.ele_node_j.to_tcl()) content.append(f"element {release_inputs}") return content + super().to_tcl()
def _get_release_ele_inputs(self) -> List[str | float | int]: """Retrieves the inputs of the axial release (zero-length element). Returns ------- List[str | float | int] Inputs of the ``zeroLength`` element between the joint node and the auxiliary node. No material is assigned along the beam axis (local direction 1), and rigid materials are assigned to the transverse translations and the rotations (directions 2-6). """ nodes = [self.release_node.tag, self.ele_node_j.tag] if self.design.direction == 'x': vecx = [1.0, 0.0, 0.0] vecyp = [0.0, -1.0, 0.0] elif self.design.direction == 'y': vecx = [0.0, 1.0, 0.0] vecyp = [1.0, 0.0, 0.0] return [ 'zeroLength', self.release_ele_tag, *nodes, '-mat', *[RIGID_MAT] * 5, '-dir', 2, 3, 4, 5, 6, '-orient', *vecx, *vecyp ]