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

"""This module provides the base class for representing the
construction quality-based modifications in the BDIM layer.
"""
# Imports from installed packages
from abc import ABC
import numpy as np
from scipy.stats import lognorm, uniform
import json
from pathlib import Path
from pydantic import BaseModel
from typing import Literal, Optional, List

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


[docs] class QualityModelData(BaseModel): """Construction quality model data. Attributes ---------- joint : Literal["inelastic", "elastic", "rigid"] Joint modelling option considered in nonlinear models. bondslip_factor : float Bondslip factor considered for nonlinear beam-column elements. theta_fck : float Median concrete strength ratio, by default 1.0. sigma_fck : float Logarithmic standard deviation of concrete strength ratio. theta_fsyk : float Median steel yield strength ratio, by default 1.0. sigma_fsyk : float Logarithmic standard deviation of steel yield strength ratio. theta_cover : float Median concrete cover ratio, by default 1.0. sigma_cover : float Logarithmic standard deviation of concrete cover ratio. uniform_low_sbh : float Lower boundary of uniform stirrup spacing ratio distribution. uniform_up_sbh : float Upper boundary of uniform stirrup spacing ratio distribution. rand : bool, optional If True, sample the parameters randomly from the relevant distribution. If False, always return 1.0 (deterministic mode). By default True. """ joint: Literal["inelastic", "elastic", "rigid"] bondslip_factor: float theta_fck: float = 1.0 sigma_fck: float theta_fsyk: float = 1.0 sigma_fsyk: float theta_cover: float = 1.0 sigma_cover: float uniform_low_sbh: float uniform_up_sbh: float rand: bool = True
[docs] class QualityData(BaseModel): """Construction quality models. Attributes ---------- high : QualityModelData High construction quality model. moderate : QualityModelData Moderate construction quality model. low : QualityModelData Low construction quality model. """ high: QualityModelData moderate: QualityModelData low: QualityModelData
[docs] class QualityBase(ABC): """Abstract base class for adjusting properties of structural members based on construction quality level. Attributes ---------- data_path : Path | str Path to the json file containing all the construction quality data. data : QualityData All the construction quality data considered for the design class. _model : QualityModelData Internal attribute for selected construction quality model. seed : int, optional Seed number considered for generating random values, by default None. """ data_path: Path | str data: QualityData _model: QualityModelData seed: Optional[int] = None def __init__(self) -> None: """Initialize a new instance of QualityBase. """ # Load quality model data with open(self.data_path, 'r') as json_file: # Load the JSON data into a Python dictionary data = json.load(json_file) # Store the quality model self.data = QualityData(**data) # Set the seed to use if self.seed: np.random.seed(self.seed) @property def model(self) -> QualityModelData: """Selected construction quality model. Returns ------- QualityModelData Construction quality model. """ return self._model @model.setter def model(self, identifier: Literal[0, 1, 2, 3]) -> None: """Select construction quality model based on the quality identifier. Parameters ---------- identifier : Literal[0, 1, 2, 3] Construction quality identifier. 0. Excellent construction quality. 1. High construction quality. 2. Moderate construction quality. 3. Low construction quality. Notes ----- Excellent construction quality (0) corresponds to the expected values. In other words, quality based modification is not performed to adjust the expected parameters through sampling (deterministic mode). Fixed parameters such as bondslip_factor correspond to that of high construction quality. """ mapper = { 0: self.data.high, 1: self.data.high, 2: self.data.moderate, 3: self.data.low } self._model = mapper.get(identifier) if identifier == 0: self._model.rand = False
[docs] def set_new_seed(self, seed: int) -> None: """Set a new random seed for reproducibility. Parameters ---------- seed : int New seed value. """ self.seed = seed np.random.seed(self.seed)
[docs] def set_adjusted_properties(self, beams: List[BeamBase], columns: List[ColumnBase]) -> None: """Set quality-adjusted properties of beams and columns. Parameters ---------- beams : List[~simdesign.rcmrf.bdim.baselib.beam.BeamBase] List of beams whose properties will be adjusted. columns : List[~simdesign.rcmrf.bdim.baselib.column.ColumnBase] List of columns whose properties will be adjusted. Notes ----- The following properties are adjusted: - Concrete compressive strength - Longitudinal reinforcement yield strength - Transverse reinforcement yield strength - Concrete cover - Stirrup spacing """ # Initialize some parameters theta_fck = self.model.theta_fck sigma_fck = self.model.sigma_fck theta_fsyk = self.model.theta_fsyk sigma_fsyk = self.model.sigma_fsyk theta_cover = self.model.theta_cover sigma_cover = self.model.sigma_cover uniform_low_sbh = self.model.uniform_low_sbh uniform_up_sbh = self.model.uniform_up_sbh num_columns = len(columns) num_beams = len(beams) # NOTE: Mean strength ratio is also randomised* theta_fck = lognorm.ppf(np.random.rand(), s=sigma_fck, scale=theta_fck) if self._model.rand: # Concrete compressive strength col_fc_ratio = lognorm.ppf( np.random.rand(num_columns), s=sigma_fck, scale=theta_fck ) beam_fc_ratio = lognorm.ppf( np.random.rand(num_beams), s=sigma_fck, scale=theta_fck ) # Longitudinal steel yield strength col_fsyl_ratio = lognorm.ppf( np.random.rand(num_columns), s=sigma_fsyk, scale=theta_fsyk ) beam_fsyl_ratio = lognorm.ppf( np.random.rand(num_beams), s=sigma_fsyk, scale=theta_fsyk ) # Transverse steel yield strength col_fsyh_ratio = lognorm.ppf( np.random.rand(num_columns), s=sigma_fsyk, scale=theta_fsyk ) beam_fsyh_ratio = lognorm.ppf( np.random.rand(num_beams), s=sigma_fsyk, scale=theta_fsyk ) # Concrete cover col_cover_ratio = lognorm.ppf( np.random.rand(num_columns), s=sigma_cover, scale=theta_cover ) beam_cover_ratio = lognorm.ppf( np.random.rand(num_beams), s=sigma_cover, scale=theta_cover ) # Stirrup spacing col_sbh_ratio = uniform.ppf( np.random.rand(num_columns), loc=uniform_low_sbh, scale=uniform_up_sbh - uniform_low_sbh, ) beam_sbh_start_ratio = uniform.ppf( np.random.rand(num_beams), loc=uniform_low_sbh, scale=uniform_up_sbh - uniform_low_sbh, ) beam_sbh_end_ratio = uniform.ppf( np.random.rand(num_beams), loc=uniform_low_sbh, scale=uniform_up_sbh - uniform_low_sbh, ) beam_sbh_mid_ratio = uniform.ppf( np.random.rand(num_beams), loc=uniform_low_sbh, scale=uniform_up_sbh - uniform_low_sbh, ) else: # Concrete compressive strength col_fc_ratio = np.ones(num_columns) beam_fc_ratio = np.ones(num_beams) # Longitudinal steel yield strength col_fsyl_ratio = np.ones(num_columns) beam_fsyl_ratio = np.ones(num_beams) # Transverse steel yield strength col_fsyh_ratio = np.ones(num_columns) beam_fsyh_ratio = np.ones(num_beams) # Concrete cover col_cover_ratio = np.ones(num_columns) beam_cover_ratio = np.ones(num_beams) # Stirrup spacing col_sbh_ratio = np.ones(num_columns) beam_sbh_start_ratio = np.ones(num_beams) beam_sbh_end_ratio = np.ones(num_beams) beam_sbh_mid_ratio = np.ones(num_beams) # Store adjusted properties of columns for i, col in enumerate(columns): col.fc_q = col.fcm * col_fc_ratio[i] col.fsyl_q = col.fsym * col_fsyl_ratio[i] col.fsyh_q = col.fsym * col_fsyh_ratio[i] col.cover_q = col.cover * col_cover_ratio[i] col.sbh_q = col.sbh * col_sbh_ratio[i] # Extra design parameters which can be quality adjusted col.dbh_q = col.dbh col.nbh_x_q = col.nbh_x col.nbh_y_q = col.nbh_x col.dbl_cor_q = col.dbl_cor col.dbl_int_q = col.dbl_int col.nblx_int_q = col.nblx_int col.nbly_int_q = col.nbly_int # Store adjusted properties of beams for i, beam in enumerate(beams): beam.fc_q = beam.fcm * beam_fc_ratio[i] beam.fsyl_q = beam.fsym * beam_fsyl_ratio[i] beam.fsyh_q = beam.fsym * beam_fsyh_ratio[i] beam.cover_q = beam.cover * beam_cover_ratio[i] sbh_start = beam.sbh[0] * beam_sbh_start_ratio[i] sbh_mid = beam.sbh[1] * beam_sbh_mid_ratio[i] sbh_end = beam.sbh[2] * beam_sbh_end_ratio[i] beam.sbh_q = np.array([sbh_start, sbh_mid, sbh_end]) # Extra design parameters which can be quality adjusted beam.nbh_b_q = beam.nbh_b beam.nbh_h_q = beam.nbh_h beam.dbh_q = beam.dbh beam.dbl_t1_q = beam.dbl_t1 beam.nbl_t1_q = beam.nbl_t1 beam.dbl_t2_q = beam.dbl_t2 beam.nbl_t2_q = beam.nbl_t2 beam.dbl_b1_q = beam.dbl_b1 beam.nbl_b1_q = beam.nbl_b1 beam.dbl_b2_q = beam.dbl_b2 beam.nbl_b2_q = beam.nbl_b2