"""This module provides the class implementation representing the elastic
numerical model used in the BDIM layer for the ``tr_post18_dch`` design class.
"""
# Imports from installed packages
from typing import List
from itertools import product
# Imports from the design class (tr_post18_dch) library
from .beam import Beam
from .column import Column
# Imports from bdim base library
from ..baselib.analysis import ElasticModelBase
from ..baselib.beam import BeamForces
from ..baselib.column import ColumnForces
[docs]
class ElasticModel(ElasticModelBase):
"""Elastic model implementation for design class ``tr_post18_dch``.
This class extends ``ElasticModelBase`` by narrowing the attribute types
and overriding ``analyze_for_all`` method.
Attributes
----------
beams : List[~simdesign.rcmrf.bdim.tr_post18_dch.beam.Beam]
List of beam objects of the building.
columns : List[~simdesign.rcmrf.bdim.tr_post18_dch.column.Column]
List of column objects of the building.
OVERSTRENGTH_FACTOR : float
Overstrength factor for buildings with high ductility.
See Also
--------
:class:`~bdim.baselib.analysis.ElasticModelBase`
Base class defining the core behaviour and configuration.
Notes
-----
Overrides :meth:`analyze_for_all` method to include an overstrength factor
of 3, which is the value for RCMRF buildings with high ductility in the
case of DTS1 and DTS2.
"""
beams: List[Beam]
columns: List[Column]
OVERSTRENGTH_FACTOR: float = 3.0
[docs]
def analyze_for_all(self):
"""Analyze the building and store element forces for all load cases
and combinations.
"""
# Seismic load cases
seismic_load_cases = ["E+X", "E-X", "E+Y", "E-Y"]
# Distinguish gravity and seismic load combinations
seismic_combos = self.loads.get_seismic_load_combos()
# Run all load cases
self._run_gravity_load_cases()
if any(seismic_combos):
self._run_seismic_load_cases()
# Accidental eccentricity
ecc = self.loads.eccentricity
ecc_factors = [ecc / 100, 0.0, -ecc / 100] if ecc != 0 else [0.0]
# Start combining forces for BEAMS
for beam in self.beams:
# Restart combo forces
beam.design_forces = []
beam.design_forces_overstrength_adjusted = []
# Loop through combinations
for combo in self.loads.combinations:
# Initialize total combined forces
forces = BeamForces(0, 0, 0, 0, 0, 0)
# Determine type of the load combination
if combo in seismic_combos:
combo_type = "seismic"
else:
combo_type = "gravity"
# Permanent Loads
if 'G' in combo.loads:
gfactor = combo.loads['G']
forces += gfactor * beam.forces[f"G/{combo_type}/alpha"]
# Variable Loads
if 'Q' in combo.loads:
qfactor = combo.loads['Q']
forces += qfactor * beam.forces[f"Q/{combo_type}/alpha"]
if combo_type == 'gravity':
# Set the loading case (type)
forces.case = combo_type
# Append the combined forces
beam.design_forces.append(forces)
elif combo_type == 'seismic' and self.beta > 0.0:
# Add the forces from seismic loading
forces_ov = BeamForces(*forces.__dict__.values())
ecc_forces = [] # forces due to eccentric loading
ecc_forces_ov = []
gfactor = combo.masses['G'] # permanent loads factor
qfactor = combo.masses['Q'] # variable loads factor
for load_case in seismic_load_cases:
if load_case in combo.loads:
tag = f"{load_case}/{gfactor}G/{qfactor}Q"
fact = combo.loads[load_case]
forces += fact * beam.forces[tag]
forces_ov += self.OVERSTRENGTH_FACTOR * \
fact * beam.forces[tag]
tmp, tmp_ov = [], []
for ecc in ecc_factors:
if ecc == 0:
tmp.append(BeamForces(0, 0, 0, 0, 0, 0))
tmp_ov.append(BeamForces(0, 0, 0, 0, 0, 0))
else:
tag_e = tag + f"/{ecc}ecc"
tmp.append(fact * beam.forces[tag_e])
tmp_ov.append(self.OVERSTRENGTH_FACTOR
* fact * beam.forces[tag_e])
ecc_forces.append(tmp)
ecc_forces_ov.append(tmp_ov)
# Possible combinations with eccentric loadings
ecc_combos = list(product(*ecc_forces))
ecc_combos_ov = list(product(*ecc_forces_ov))
for ecc_combo, ecc_combo_ov in zip(ecc_combos,
ecc_combos_ov):
# Add the forces due to ecc. loading
forces_ = sum(ecc_combo, forces)
forces_ov_ = sum(ecc_combo_ov, forces_ov)
# Set the loading case (type)
forces_.case = combo_type
forces_ov_.case = combo_type
# Append the combined forces
beam.design_forces.append(forces_)
beam.design_forces_overstrength_adjusted.append(
forces_ov_)
if len(beam.design_forces_overstrength_adjusted) == 0:
beam.design_forces_overstrength_adjusted.append(
BeamForces(0, 0, 0, 0, 0, 0)
)
# Start combining forces for COLUMNS
for column in self.columns:
# Restart combo forces
column.design_forces = []
column.design_forces_overstrength_adjusted = []
# Loop through combinations
for combo in self.loads.combinations:
# Initialize total combined forces
forces = ColumnForces(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
# Determine type of the load combination
if combo in seismic_combos:
combo_type = "seismic"
else:
combo_type = "gravity"
# Permanent Loads
if 'G' in combo.loads:
gfactor = combo.loads['G']
forces += gfactor * column.forces[f"G/{combo_type}"]
# Variable Loads
if 'Q' in combo.loads:
qfactor = combo.loads['Q']
forces += qfactor * column.forces[f"Q/{combo_type}"]
if combo_type == 'gravity':
# Set the loading case (type)
forces.case = combo_type
# Append the combined forces
column.design_forces.append(forces)
elif combo_type == 'seismic' and self.beta > 0.0:
# Add the forces from seismic loading
forces_ov = ColumnForces(*forces.__dict__.values())
ecc_forces = [] # forces due to eccentric loading
ecc_forces_ov = [] # forces due to eccentric loading
gfactor = combo.masses['G'] # permanent loads factor
qfactor = combo.masses['Q'] # variable loads factor
for load_case in seismic_load_cases:
if load_case in combo.loads:
tag = f"{load_case}/{gfactor}G/{qfactor}Q"
fact = combo.loads[load_case]
forces += fact * column.forces[tag]
forces_ov += self.OVERSTRENGTH_FACTOR * fact * \
column.forces[tag]
tmp, tmp_ov = [], [] # ecc. forces per load_case
for ecc in ecc_factors:
if ecc == 0:
tmp.append(ColumnForces(0, 0, 0, 0, 0,
0, 0, 0, 0, 0))
tmp_ov.append(ColumnForces(0, 0, 0, 0, 0,
0, 0, 0, 0, 0))
else:
tag_e = tag + f"/{ecc}ecc"
tmp.append(fact * column.forces[tag_e])
tmp_ov.append(
self.OVERSTRENGTH_FACTOR
* fact * column.forces[tag_e]
)
ecc_forces.append(tmp)
ecc_forces_ov.append(tmp_ov)
# Possible combinations with eccentric loadings
ecc_combos = list(product(*ecc_forces))
ecc_combos_ov = list(product(*ecc_forces_ov))
for ecc_combo, ecc_combo_ov in zip(ecc_combos,
ecc_combos_ov):
# Add the forces due to ecc. loading
forces_ = sum(ecc_combo, forces)
forces_ov_ = sum(ecc_combo_ov, forces_ov)
# Set the loading case (type)
forces_.case = combo_type
forces_ov_.case = combo_type
# Append the combined forces
column.design_forces.append(forces_)
column.design_forces_overstrength_adjusted.append(
forces_ov_)
if len(column.design_forces_overstrength_adjusted) == 0:
column.design_forces_overstrength_adjusted.append(
ColumnForces(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
)