NSPA
This example demonstrates the full step-by-step pipeline — from portfolio
generation to pushover analysis — using the
BCIM,
BDIM, and
BNSM classes directly rather
than through the high-level simdesign.rcmrf.generate() convenience
function. It also shows an adaptive convergence strategy that retries the
pushover with progressively finer displacement increments when the default
increment fails.
import matplotlib.pyplot as plt
from pathlib import Path
from simdesign import rcmrf
from simdesign.utils.misc import make_dir
model = "CP03"
scheme = "EQL"
max_drift = 0.1
include_infills = True
design_classes = [
"eu_cdn", "eu_cdl", "eu_cdm", "eu_cdh",
"tr_7599", "tr_0018_dcm", "tr_0018_dch",
"tr_post18_dcm", "tr_post18_dch",
]
outdir_main = Path("Outputs-NSPA-Batch")
make_dir(outdir_main)
for design_class in design_classes:
outdir_class = outdir_main / design_class
make_dir(outdir_class)
# Generate the building portfolio
bcim = rcmrf.BCIM()
bcim.generate(
sample_size=1,
design_class=design_class,
num_storeys=4,
beta=0.1,
)
bcim.to_csv(outdir_class / "BCIM_initial.csv")
for i, taxonomy in enumerate(bcim.taxonomy):
print(f"Designing {design_class.upper()} building "
f"{i + 1}/{len(bcim.taxonomy)}")
outdir_building = outdir_class / f"Building_{i + 1}"
# Simulated design
bdim = rcmrf.BDIM(taxonomy)
bdim.set_seed_for_quality_adjustments(bcim.inputs.seed)
bdim.run_iterative_design_algorithm()
if not bdim.ok:
continue
# Update BCIM attributes that may be adjusted during design
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
bdim.to_csv(outdir_building / "BDIM-Data")
# Modal analysis and model visualisation
bnsm = rcmrf.BNSM(
design=bdim, scheme=scheme, dincr=1e-3,
max_drift=max_drift, model=model,
include_infills=include_infills,
)
bnsm.do_modal(num_modes=6, out_dir=outdir_building / "Modal-Results")
bnsm.plot_model(directory=outdir_building, show=False)
bnsm.plot_mode_shape(
mode_number=1, contour="x", show=False, directory=outdir_building
)
bnsm.plot_mode_shape(
mode_number=2, contour="y", show=False, directory=outdir_building
)
# Pushover in X — retry with finer increments on convergence failure
dincr_x = 1e-3
dx, vx, ok_x = bnsm.do_nspa(
ctrl_dof=1, out_dir=outdir_building / "NSPA-Results-X"
)
for dincr_try in [1e-4, 1e-5]:
if ok_x != 0:
dincr_x = dincr_try
bnsm = rcmrf.BNSM(
design=bdim, scheme=scheme, dincr=dincr_x,
max_drift=max_drift, model=model,
include_infills=include_infills,
)
dx, vx, ok_x = bnsm.do_nspa(
ctrl_dof=1, out_dir=outdir_building / "NSPA-Results-X"
)
# Pushover in Y — same adaptive strategy
dincr_y = 1e-3
dy, vy, ok_y = bnsm.do_nspa(
ctrl_dof=2, out_dir=outdir_building / "NSPA-Results-Y"
)
for dincr_try in [1e-4, 1e-5]:
if ok_y != 0:
dincr_y = dincr_try
bnsm = rcmrf.BNSM(
design=bdim, scheme=scheme, dincr=dincr_y,
max_drift=max_drift, model=model,
include_infills=include_infills,
)
dy, vy, ok_y = bnsm.do_nspa(
ctrl_dof=2, out_dir=outdir_building / "NSPA-Results-Y"
)
# Rebuild BNSM with the finest increment that worked for both directions
bnsm = rcmrf.BNSM(
design=bdim, scheme=scheme,
dincr=min(dincr_x, dincr_y),
max_drift=max_drift, model=model,
include_infills=include_infills,
)
bnsm.to_py(outdir_building / "OpsPy-Model")
bnsm.to_tcl(outdir_building / "OpsTcl-Model")
# Plot pushover curves
plt.plot(dx, vx, label="X-dir")
plt.plot(dy, vy, label="Y-dir")
plt.xlabel("Control Node Displacement [m]")
plt.ylabel("Base Shear [kN]")
plt.legend()
plt.savefig(outdir_building / "nspa.png", dpi=300)
plt.close()
bcim.to_csv(outdir_class / "BCIM_final.csv")
Key points
- Adaptive convergence
do_nspa()returns a status flag as its third return value. A non-zero value indicates that the analysis did not converge. The example retries with successively finer increments (1e-3→1e-4→1e-5) before proceeding. A newBNSMinstance must be constructed for each retry because OpenSees state is not reset between runs.- BCIM update after design
Attributes such as
column_sectionandconcrete_grademay be adjusted by the design algorithm. Writing them back to the BCIM object ensures that the final CSV reflects the as-designed properties rather than the initially sampled values.- Final model export
The OpenSees model is exported only once, using the smallest displacement increment that successfully converged in both directions.