Source code for simdesign.rcmrf.bdim.baselib.infill

"""This module provides the base class for representing masonry infill walls
within the BDIM layer.
"""
# Imports from installed packages
from abc import ABC
import numpy as np
from typing import List, Optional, Literal

# Imports from bdim base library
from .beam import BeamBase
from .column import ColumnBase

# Imports from geometry library
from ... geometry.base import Rectangle

# Imports from utils library
from ....utils.units import kN, m, mm
from ....utils.misc import PRECISION


# Infill property mapper (Parameters from Hak et al. 2012)
INFILL_PROPERTIES = {
    "Weak": {
        "tw": 80.0,     # Wall thickness [mm]
        "W": 6.87,      # Unit weight [kN/m3]
    },
    "Medium": {
        "tw": 240.0,    # Wall thickness [mm]
        "W": 6.87,      # Unit weight [kN/m3]
    },
    "Strong": {
        "tw": 300.0,    # Wall thickness [mm]
        "W": 7.36,      # Unit weight [kN/m3]
    },
}
"""
The weak masonry infill consists of a 8.0 cm thick single-leaf masonry wall
constructed of horizontally hollowed brick units (volumetric percentage of
holes ≈60%) with a 1.0-cm thick plaster on each face, while the medium
typology consists of two 12.0-cm thick leaves, each constructed of
horizontally hollowed brick units (volumetric percentage of holes ≈60%),
divided by an intermediate 5.0-cm cavity and covered with a 1.0-cm thick
plaster placed at the external sides of the walls. The typology representing
strong infill walls is constituted by a single 30-cm thick leaf built with
vertically hollowed brick units (volumetric percentage of holes ≈50%).

TODO: Verify the weights if they make sense.
"""


[docs] class InfillBase(ABC): """ Abstract base class for infills. Must be inherited by design-class-specific infills. Attributes ---------- rectangle : ~simdesign.rcmrf.geometry.base.Rectangle Geometric mesh representation of the infill (tag, points, lines). beams : List[Optional[~simdesign.rcmrf.bdim.baselib.beam.BeamBase]] List of beams corresponding to the rectangle lines with indices 1 and 3. columns : List[~simdesign.rcmrf.bdim.baselib.column.ColumnBase \ | List[~simdesign.rcmrf.bdim.baselib.column.ColumnBase]] List of columns corresponding to the rectangle lines with indices 0 and 2. loc : Literal['exterior', 'interior'] Location of the infill wall : 'exterior' or 'interior'. """ rectangle: Rectangle beams: List[Optional[BeamBase]] columns: List[ColumnBase | List[ColumnBase]] loc: Literal['exterior', 'interior'] def __init__( self, rectangle: Rectangle, beams: List[Optional[BeamBase]], columns: List[ColumnBase | List[ColumnBase]], loc: Literal['exterior', 'interior'] ): """ Initialize a new instance of InfillBase. Parameters ---------- rectangle : ~simdesign.rcmrf.geometry.base.Rectangle Geometric rectangle representing the infill panel. beams : List[Optional[~simdesign.rcmrf.bdim.baselib.beam.BeamBase]] Beams associated with the rectangle's 1st and 3rd edges (lines). columns : List[~simdesign.rcmrf.bdim.baselib.column.ColumnBase \ | List[~simdesign.rcmrf.bdim.baselib.column.ColumnBase]] Columns associated with the rectangle's 0th and 2nd edges (lines). loc : Literal['exterior', 'interior'] Location type of the infill wall which determines thickness. """ self.rectangle = rectangle self.beams = beams self.columns = columns self.loc = loc @property def typology(self) -> Literal['Weak', 'Medium', 'Strong']: """ Return the infill wall typology (strength) based on assignment. Returns ------- Literal['Weak', 'Medium', 'Strong'] Type of the infill wall. Raises ------ KeyError If ``loc`` is not set to 'interior' or 'exterior' and strength is not defined. """ if self.rectangle.typology: return self.rectangle.typology elif self.loc == 'interior': return 'Weak' # Default typology for interior frame infills elif self.loc == 'exterior': return 'Medium' # Default typology for exterior frame infills else: raise KeyError('Infill location is not set or not valid') @property def thickness(self) -> float: """ Return the infill wall thickness based on its typology. Returns ------- float Thickness of the infill wall. """ return INFILL_PROPERTIES[self.typology]['tw'] * mm @property def unit_weight(self) -> float: """ Return the infill wall unit weight based on its typology. Returns ------- float Unit weight of the infill wall. """ return INFILL_PROPERTIES[self.typology]['W'] * kN/m**3 @property def height(self) -> float: """ Compute the infill height from its rectangle points (z-extent). Returns ------- float Height of infill wall. """ zs = [p.coordinates[2] for p in self.rectangle.points] height = max(zs) - min(zs) return round(height, PRECISION) @property def length(self) -> float: """ Compute the infill length along its in-plane horizontal axis. Returns ------- float Length of wall along y (if YZ plane) or along x (if XZ plane). Raises ------ ValueError If the rectangle is not axis-aligned in YZ or XZ planes. """ plane = self.plane if plane == 'YZ': ys = [p.coordinates[1] for p in self.rectangle.points] length = max(ys) - min(ys) elif plane == 'XZ': xs = [p.coordinates[0] for p in self.rectangle.points] length = max(xs) - min(xs) else: raise ValueError("Rectangle not aligned with YZ or XZ plane") return round(length, PRECISION) @property def plane(self) -> Literal['XZ', 'YZ']: """ Detect whether the rectangle lies in the YZ or XZ plane and return the corresponding in-plane name. Returns ------- Literal['XZ', 'YZ'] The plane name which is parallel to the infill. Raises ------ ValueError If the rectangle is not axis-aligned in YZ or XZ planes. """ u_norm = self.rectangle.unit_normal_vector if np.allclose(u_norm, [0.0, 1.0, 0.0]): return 'XZ' # XZ (ccw) elif np.allclose(u_norm, [-1.0, 0.0, 0.0]): return 'YZ' # YZ (ccw) else: raise ValueError("Rectangle not aligned with YZ or XZ plane") @property def weight(self) -> float: """ Compute the total weight of the infill panel. Returns ------- float Total weight of infill wall. """ weight = self.length * self.height * self.thickness * self.unit_weight return round(weight, PRECISION) @property def wg(self) -> float: """ Return the distributed load (line load) on the supporting beam. Returns ------- float Distributed weight of infill wall along its length. """ return round(self.weight / self.length, PRECISION)
[docs] def set_beam_infill_load(self) -> None: """ Assign the infill's distributed load to the supporting beam. Notes ----- If supporting beam exists (except ground floors), sets its ``infill_wg`` attribute to ``self.wg``. """ if self.beams[1]: # Bottom (supporting) beam self.beams[1].infill_wg = self.wg