.. _architecture_overview: ============================= Architecture overview ============================= This document describes the internal architecture of GenSec at a level of detail that allows a civil engineer to understand what each software component does and how data flows through the program. No prior software engineering knowledge is required beyond a basic familiarity with the concept of *functions* and *objects* (containers that group data and operations together). What GenSec does ----------------- GenSec receives a description of a cross-section (geometry, materials, reinforcement) and a set of load demands, and answers two questions: 1. **What is the section's resistance domain?** The set of all :math:`(N, M_x, M_y)` combinations the section can carry at the ultimate limit state. 2. **Are the demands inside that domain?** For each demand point, GenSec computes one or more utilization ratios :math:`\eta` that measure how close the demand is to the boundary. Everything else — moment-curvature diagrams, stress maps, CSV/JSON exports, plots — is built on top of these two capabilities. Package structure ------------------ GenSec is organized into four *subpackages* (folders), each with a well-defined responsibility: .. mermaid:: graph TB subgraph materials["materials/"] base["base.py
Abstract Material"] concrete["concrete.py
Parabola-rectangle"] steel["steel.py
Elastic-plastic"] tabulated["tabulated.py
Arbitrary σ-ε"] ec2props["ec2_properties.py
EC2 Table 3.1"] ec2bridge["ec2_bridge.py
EC2 → GenSec factory"] end subgraph geometry["geometry/"] fiber["fiber.py
RebarLayer"] primitives["primitives.py
Shape factories"] geom["geometry.py
GenericSection + mesher"] section["section.py
RectSection factory"] end subgraph solver["solver/"] integrator["integrator.py
FiberSolver"] capacity["capacity.py
NMDiagram"] check["check.py
VerificationEngine"] end subgraph output["output/"] plots["plots.py
matplotlib"] export["export.py
CSV / JSON"] report["report.py
Terminal"] end io_yaml["io_yaml.py
YAML loader"] cli["cli.py
CLI: run / plot"] cli --> io_yaml io_yaml --> materials io_yaml --> geometry cli --> solver cli --> output solver --> materials solver --> geometry Think of these subpackages as departments in a design office: - **materials/** — the *material laboratory*: knows how to convert a strain value into a stress value for any material (concrete, steel, CFRP, etc.). - **geometry/** — the *drafter's desk*: defines section shapes, places rebars, and discretizes the section into fibers. - **solver/** — the *calculation team*: takes a section and its materials, computes internal forces, builds resistance domains, verifies demands. - **output/** — the *reporting team*: produces plots, data files, and terminal summaries. - **io_yaml.py** — the *secretary*: reads the YAML input file and hands the right objects to each department. - **cli.py** — the *project manager*: coordinates the entire workflow. Main workflow -------------- When you run ``gensec run input.yaml``, the following happens: .. mermaid:: flowchart TD A["Read YAML file
(io_yaml.py)"] --> B["Build Material objects
(concrete, steel, ...)"] B --> C["Build Section object
(meshed polygon + rebars)"] C --> D["Create FiberSolver
(strain → forces integrator)"] D --> E["Generate N-M diagrams
(NMDiagram)"] D --> F["Generate 3D surface
(NMDiagram.generate_biaxial)"] D --> G["Generate M-χ curves
(NMDiagram.generate_moment_curvature)"] E --> H["Build VerificationEngine"] F --> H H --> I["Check demands
(η_3D, η_2D)"] H --> J["Check combinations
(η_path, staged)"] H --> K["Check envelopes
(max η among members)"] I --> L["Export JSON + CSV"] J --> L K --> L L --> M["Generate plots
(plots.py)"] M --> N["Done: all outputs
in output directory"] style A fill:#e1f5fe style N fill:#c8e6c9 Class hierarchy ---------------- The key classes and their relationships: .. mermaid:: classDiagram class Material { <> +stress(eps) float +stress_array(eps) ndarray +tangent(eps) float +tangent_array(eps) ndarray +eps_min float +eps_max float } class Concrete { +fck: float +fcd: float +eps_c2: float +eps_cu2: float +n_parabola: float +fct: float +Ec: float +tension_enabled: bool } class Steel { +fyk: float +fyd: float +Es: float +eps_yd: float } class TabulatedMaterial { +strains: ndarray +stresses: ndarray } Material <|-- Concrete Material <|-- Steel Material <|-- TabulatedMaterial class RebarLayer { +x: float +y: float +As: float +material: Material +embedded: bool } class GenericSection { +polygon: Polygon +bulk_material: Material +rebars: list~RebarLayer~ +x_fibers: ndarray +y_fibers: ndarray +A_fibers: ndarray +n_grid_x: int or None +n_grid_y: int or None +dx: float +dy: float } GenericSection o-- Material : bulk GenericSection o-- RebarLayer : rebars note for GenericSection "RectSection() is a factory function\nthat returns a GenericSection\nwith a rectangular polygon." class FiberSolver { +integrate(eps0, chi_x, chi_y) +integrate_batch(eps0[], chi_x[], chi_y[]) +integrate_with_tangent(eps0, chi_x, chi_y) +solve_equilibrium(N, Mx, My) +get_fiber_results(...) } class NMDiagram { +generate() +generate_biaxial() +generate_mx_my() +generate_moment_curvature() } class VerificationEngine { +check_demand() +check_combination() +check_envelope() } class DomainChecker { +eta_3D() +eta_path() +is_inside() } class MxMyContour { +eta_2D() +eta_path_2D() } FiberSolver --> GenericSection : reads NMDiagram --> FiberSolver : uses VerificationEngine --> DomainChecker : 3D checks VerificationEngine --> MxMyContour : 2D checks VerificationEngine --> NMDiagram : generates contours Units and sign conventions --------------------------- All internal computations use **basic SI units**: +------------------+--------+---------------------------------------------+ | Quantity | Unit | Sign convention | +==================+========+=============================================+ | Length | mm | | +------------------+--------+---------------------------------------------+ | Force | N | Positive = tension | +------------------+--------+---------------------------------------------+ | Moment | N·mm | Right-hand rule around each axis | +------------------+--------+---------------------------------------------+ | Stress | MPa | Positive = tension | +------------------+--------+---------------------------------------------+ | Strain | — | Positive = tension, negative = compression | +------------------+--------+---------------------------------------------+ | Curvature | 1/mm | | +------------------+--------+---------------------------------------------+ YAML input uses **engineering units** (kN, kN·m) for convenience. The parser converts automatically. All output files provide values in both unit systems. The coordinate origin is at the **bottom-left corner** of the section's bounding box: - :math:`x` axis: horizontal (width direction). - :math:`y` axis: vertical (height direction, upward). - Reference point for moments: the **geometric centroid** of the gross section (computed from the polygon, not from the bounding box).