Source code for simdesign.rcmrf

"""A modular computational framework for the generation and nonlinear
modelling of reinforced concrete (RC) moment-resisting frames (MRFs).
It orchestrates the BCIM → BDIM → BNSM pipeline, generating portfolio-level
building class and design information data (exported CSV files), alongside
OpenSees-compatible nonlinear numerical models (in Python or Tcl).
:meth:`~simdesign.rcmrf.generate` serves as the entry point for running the
pipeline.

Pipeline::

    BCIM (Realisation Layer)

    BDIM (Design Layer)

    BNSM (Modelling Layer)

    OpenSees (Analysis Layer)
"""

from typing import Dict, Literal, Tuple, List
from pathlib import Path

from .bcim import BCIM
from .bdim import BDIM, TaxonomyData
from .bdim.factory import BuildingBase as BuildingDesign
from .bnsm import BNSM
from .bnsm.factory import BuildingBase as BuildingModel
from .geometry import StandardGeometry, CustomGeometry

from ..utils.misc import make_dir


__all__ = ["BCIM", "BDIM", "BNSM",
           "TaxonomyData", "StandardGeometry", "CustomGeometry"]


[docs] def generate( inputs: Dict[Literal['bcim', 'bnsm'], Dict], outdir: str | Path = None ) -> Tuple[BCIM, List[BuildingDesign | None], List[BuildingModel | None]]: """Generates BCIM, BDIM and BNSM data by following complete workflow in Built Data Environment (BED) SimDesign framework for RC-MRF systems. Parameters ---------- inputs : Dict[Literal['bcim', 'bnsm'], Dict] Contains input parameters required for data generation. These will replace the defaults obtained for the specified `design_class`. outdir : str | Path, optional Path to the user-defined output directory. If None, set to `Path.cwd() / 'Outputs'`. by default None. Returns ------- bcim : BCIM Building Class Information Model. bdim : List[BuildingDesign | None] List of Building Design Information Models (None if design failed). bnsm : List[BuildingModel | None] List of Building Nonlinear Structural Models (None if design failed). Raises ------ KeyError `inputs['bcim']['design_class']` is not specified. Examples -------- Example dictionary to pass as ``inputs``: .. code-block:: python inputs = { "bcim": { "design_class": "eu_cdh", "beta": 0.1, "sample_size": 150, "num_storeys": 5, # Distribution parameters "typical_storey_height": { "cv": 0.07, "mu": 2.90, "lower_bound": 2.3, "upper_bound": 3.8, }, "staircase_bay_width": { "lower_bound": 2.8, "upper_bound": 3.2, }, "standard_bay_width": { "corr_coeff_xy": -0.92, "lower_bound_x": 3.5, "upper_bound_x": 7.5, "theta_x": 4.5, "sigma_x": 0.35, "lower_bound_y": 3.5, "upper_bound_y": 7.5, "theta_y": 4.5, "sigma_y": 0.35, }, "steel": { "tag": ["S400", "S500"], "probability": [0.10, 0.90], }, "concrete": { "tag": ["C20/25", "C25/30", "C30/37", "C35/45"], "probability": [0.30, 0.45, 0.20, 0.05], }, "ground_storey_height": { "maximum": 4.20, "factor": [1.0, 1.1, 1.2, 1.3, 1.4], "probability": [0.55, 0.10, 0.20, 0.10, 0.05], }, "construction_quality": {"probability": [0.6, 0.3, 0.1]}, "slab_typology": { "ss1_prob_given_ss1_or_hs": 0.50, "ss2_prob_given_ss2_or_hs": 0.65, "upper_lim_for_min_ss_span_length": 6.0, "upper_lim_for_max_ss2_span_ratio": 2.0, "staircase_slab_depth": 0.15, "floor_slab_thickness": 0.15, }, "wb_prob_given_hs": 0.50, "square_column_prob": 0.50, "layout": "all", "seed": 1993, }, "bnsm": { "model": "CP03", "load_factors": {"G": 1.0, "Q": 0.3}, "mass_factors": {"G": 1.0, "Q": 0.3}, "scheme": "EQL", "max_drift": 0.05, "dincr": 0.001, "opensees": "py", }, } """ # Get bcim generation settings bcim_inputs = inputs.get('bcim') if not bcim_inputs or not bcim_inputs.get('design_class'): raise KeyError('design_class in bcim is not specified!') # Get bnsm settings bnsm_inputs = inputs.get('bnsm') lang = 'py' if bnsm_inputs is None: bnsm_inputs = {} elif bnsm_inputs.get('opensees'): lang = bnsm_inputs.pop('opensees') # Create output directory if outdir is None: outdir = Path.cwd() / 'Outputs' else: outdir = Path(outdir) bcim_path = outdir / "BCIM.csv" bdim_path = outdir / 'BDIM' bnsm_path = outdir / 'BNSM' make_dir(outdir) make_dir(bdim_path) make_dir(bnsm_path) # Initialize BCIM bcim = BCIM() # Generate a building portfolio bcim.generate(**bcim_inputs) # BDIM database bdim = [] # BNSM database bnsm = [] # Loop through each building in portfolio for i, taxonomy in enumerate(bcim.taxonomy): print("----------------------------------------------------") print(f"Designing {taxonomy.design_class} building", f"{i + 1}/{len(bcim.taxonomy)} for beta={taxonomy.beta}g") # Initialize BDIM bdim_ = BDIM(taxonomy) # To ensure the reproducibility of BDIM set the seed bdim_.set_seed_for_quality_adjustments(bcim.inputs.seed) # Make simumlated design bdim_.run_iterative_design_algorithm() # Update BCIM in case some properties changed during design if bdim_.ok: # If the design is ok, continue with the model bcim.column_section[i] = bdim_.column_section bcim.beam_type[i] = bdim_.beam_type bcim.concrete_grade[i] = bdim_.concrete_grade bcim.steel_grade[i] = bdim_.steel_grade # Export to csv bdim_.to_csv(bdim_path / f'Building_{i + 1}') # Initialize BNSM kwargs = bnsm_inputs.copy() kwargs['design'] = bdim_ bnsm_ = BNSM(**kwargs) if lang == 'py': # Export numerical models for OpenSeesPy bnsm_.to_py(bnsm_path / f'Building_{i + 1}') elif lang == 'tcl': # Export numerical models for OpenSeesTcl bnsm_.to_tcl(bnsm_path / f'Building_{i + 1}') # Plot the model and save bnsm_.plot_model(directory=bnsm_path / f'Building_{i + 1}', show=False) # Add to the BDIM and BNSM databases bdim.append(bdim_) bnsm.append(bnsm_) else: bdim.append(None) bnsm.append(None) # Save bcim information bcim.to_csv(bcim_path) return bcim, bdim, bnsm