gensec.geometry

Section definition, fiber meshing, parametric shape factories, and ideal_gross geometric-property computation.

A cross-section in GenSec is represented as a collection of bulk fibers (from the meshed polygon) and point fibers (rebars, tendons, FRP strips). The GenericSection class is the primary section object; RectSection is a backward-compatible wrapper.

The ideal_gross geometric properties — area, centroid, centroidal and principal second-moments, central inertia ellipse, kern — are computed exactly on the polygon (independently of the fiber mesh) by the module gensec.geometry.properties. See the dedicated page ideal_gross_properties for the mathematical formulation and usage.

Point fibers (rebars)

Point fiber definitions (rebars, FRP strips, tendons).

Phase 2: each fiber has both x and y coordinates for biaxial bending.

class RebarLayer(
y: float,
As: float = 0.0,
material: Material = None,
x: float | None = None,
embedded: bool = True,
n_bars: int = 1,
diameter: float = 0.0,
)

Bases: object

A point fiber (rebar, FRP strip, tendon, etc.).

Each fiber carries its own Material reference, allowing mixed-material sections. For biaxial bending, both x and y coordinates are needed.

The cross-sectional area As can be specified directly or computed automatically from diameter and n_bars:

\[A_s = n_{\text{bars}} \cdot \frac{\pi}{4} \, d^2\]

If both As and diameter are given, As takes precedence. If only diameter is given (with As omitted or set to 0), As is computed from the formula above.

Parameters:
  • y (float) – Vertical coordinate from bottom edge [mm].

  • As (float, optional) – Cross-sectional area [mm²]. If 0 or omitted, computed from diameter and n_bars.

  • material (Material) – Constitutive law.

  • x (float, optional) – Horizontal coordinate from left edge [mm]. If None, defaults to the section centroid x-coordinate (set during section assembly). For uniaxial bending this is irrelevant.

  • embedded (bool, optional) – If True (default), the fiber is embedded within the bulk material. The integrator will subtract the bulk material contribution at this location to avoid double-counting the area. Set to False for external elements (e.g. external FRP strips, steel truss chords outside the concrete).

  • n_bars (int, optional) – Number of bars. Default 1. Also used to compute As when diameter is given.

  • diameter (float, optional) – Bar diameter [mm]. Default 0. When positive and As is 0, As is computed as \(n_{\text{bars}} \cdot \pi/4 \cdot d^2\).

Generic section with polygon meshing

Generic cross-section geometry with automatic fiber meshing.

Replaces the former RectSection with a fully general approach: any cross-section defined as a Shapely polygon (with holes) is automatically discretized into a fiber mesh suitable for FiberSolver.

Two meshing strategies are available:

  • Grid (default): rectangular grid clipped to the polygon boundary. Fast, simple, good for convex or mildly non-convex sections. Resolution controlled by mesh_size [mm].

  • Triangular: Constrained Delaunay triangulation via the triangle library. Better for curved boundaries and complex holes. Requires triangle to be installed.

The class exposes the same attribute interface that FiberSolver consumes, so the solver, capacity generator, and plotting modules need no changes.

Dependencies

  • shapely >= 2.0

  • triangle (optional, for triangular meshing)

  • numpy

Examples

Build a rectangular section the quick way:

>>> from gensec.geometry.section import GenericSection
>>> from gensec.geometry.fiber import RebarLayer
>>> from gensec.materials.concrete import Concrete
>>> from gensec.materials.steel import Steel
>>> from shapely.geometry import box
>>> poly = box(0, 0, 300, 600)
>>> sec = GenericSection(poly, Concrete(fck=25), [], mesh_size=10)
>>> sec.n_fibers
1800

Build a circular section with a square hole:

>>> from shapely.geometry import Point, box
>>> outer = Point(0, 0).buffer(500, resolution=64)
>>> hole = box(-100, -100, 100, 100)
>>> poly = outer.difference(hole)
>>> sec = GenericSection(poly, Concrete(fck=30), [], mesh_size=20)
class GenericSection(polygon: ~shapely.geometry.polygon.Polygon, bulk_material: ~gensec.materials.base.Material, rebars: ~typing.List[~gensec.geometry.fiber.RebarLayer], mesh_size: float = 10.0, mesh_method: 'grid' | 'triangle' = 'grid', bulk_materials: ~typing.List[tuple] = <factory>, n_grid_x: int | None = None, n_grid_y: int | None = None)

Bases: object

Cross-section defined by an arbitrary polygon, meshed into fibers.

The section geometry is a shapely.geometry.Polygon (which may contain holes). The bulk material is assigned to all fibers inside the polygon boundary. Point fibers (rebars, tendons, FRP strips) are placed independently.

Coordinate system

User-defined. Typically:

  • \(x\) horizontal, \(y\) vertical (upward).

  • Origin at bottom-left corner or at centroid, depending on the factory function used.

param polygon:

Section outline (may include holes).

type polygon:

shapely.geometry.Polygon

param bulk_material:

Constitutive law for the bulk (concrete, timber, …).

type bulk_material:

Material

param rebars:

Point fibers with their own materials.

type rebars:

list of RebarLayer

param mesh_size:

Target fiber size [mm]. For grid meshing, this is the cell side length. For triangular meshing, this controls the maximum triangle area \(\approx 0.5 \cdot \text{mesh\_size}^2\). Default 10.0.

type mesh_size:

float, optional

param mesh_method:

Meshing strategy. Default 'grid'.

type mesh_method:

'grid' or 'triangle', optional

param bulk_materials:

Additional bulk material zones. Each tuple is (Polygon, Material). Fibers inside each zone use that zone’s material instead of bulk_material. Zones are checked in order; first match wins. Default empty (single-material section).

type bulk_materials:

list of tuple, optional

param n_grid_x:

Explicit number of grid columns for the 'grid' mesher. When set, overrides the mesh_size-based computation for the x-direction. Default None (derive from mesh_size).

type n_grid_x:

int or None, optional

param n_grid_y:

Explicit number of grid rows. Default None.

type n_grid_y:

int or None, optional

ivar x_fibers:

x-coordinates of bulk fiber centroids [mm].

vartype x_fibers:

numpy.ndarray

ivar y_fibers:

y-coordinates [mm].

vartype y_fibers:

numpy.ndarray

ivar A_fibers:

Fiber areas [mm²].

vartype A_fibers:

numpy.ndarray

ivar mat_indices:

Material index for each bulk fiber. 0 = bulk_material, 1..N = zones from bulk_materials list.

vartype mat_indices:

numpy.ndarray of int

ivar x_rebars:

x-coordinates of rebar layers [mm].

vartype x_rebars:

numpy.ndarray

ivar y_rebars:

y-coordinates [mm].

vartype y_rebars:

numpy.ndarray

ivar A_rebars:

Areas [mm²].

vartype A_rebars:

numpy.ndarray

ivar embedded_rebars:

vartype embedded_rebars:

numpy.ndarray of bool

ivar n_fibers:

Total number of bulk fibers.

vartype n_fibers:

int

ivar B:

Bounding box width (x-direction) [mm].

vartype B:

float

ivar H:

Bounding box height (y-direction) [mm].

vartype H:

float

ivar n_fibers_x:

Number of grid columns (grid mesh only; triangular sets -1).

vartype n_fibers_x:

int

ivar n_fibers_y:

Number of grid rows (grid mesh only; triangular sets -1).

vartype n_fibers_y:

int

ivar ideal_gross_area:

ideal_gross polygon area [mm²].

vartype ideal_gross_area:

float

raises ValueError:

If the polygon is empty, invalid, or has zero area.

raises ImportError:

If mesh_method='triangle' but the triangle package is not installed.

property bbox

Bounding box as (minx, miny, maxx, maxy).

Return type:

tuple of float

get_all_bulk_materials()

Return the list of all bulk materials (base + zones).

Returns:

Index-aligned with mat_indices values.

Return type:

list of Material

get_material_for_fiber(
fiber_index,
)

Return the material object for a given bulk fiber index.

Parameters:

fiber_index (int)

Return type:

Material

property ideal_gross_properties

Lazy-computed homogenized section properties.

mesh_summary()

Return a summary dict of mesh quality metrics.

Returns:

Keys: n_fibers, total_area, ideal_gross_area, area_error_pct, min_fiber_area, max_fiber_area, mean_fiber_area, mesh_method, mesh_size.

Return type:

dict

property x_centroid

ideal_gross centroid x-coordinate [mm].

Computed from the Shapely polygon centroid (exact for arbitrary polygons, unlike the \(B/2\) approximation of the former RectSection).

property y_centroid

ideal_gross centroid y-coordinate [mm].

Parametric section primitives

Factory functions that return shapely.geometry.Polygon objects for common section shapes. Each polygon can be passed directly to GenericSection.

Parametric section primitives — factory functions.

Each function returns a shapely.geometry.Polygon that can be passed directly to GenericSection. All dimensions are in millimetres.

The coordinate origin convention is bottom-left corner of the bounding box, consistent with the former RectSection.

Available primitives

Examples

>>> from gensec.geometry.primitives import rect_poly
>>> p = rect_poly(300, 600)
>>> p.area
180000.0
>>> from gensec.geometry.primitives import tee_poly
>>> p = tee_poly(bf=800, hf=150, bw=300, hw=450)
>>> p.area
255000.0
annulus_poly(
D_ext,
D_int,
resolution=64,
)

Annular (hollow circular) section.

Parameters:
  • D_ext (float) – Outer diameter [mm].

  • D_int (float) – Inner diameter [mm].

  • resolution (int, optional)

Returns:

Polygon with an interior hole.

Return type:

shapely.geometry.Polygon

Raises:

ValueError – If D_int >= D_ext.

box_poly(
B,
H,
tw,
tf_top,
tf_bot=None,
)

Hollow rectangular (box) section.

Parameters:
  • B (float) – Outer width [mm].

  • H (float) – Outer height [mm].

  • tw (float) – Web (side wall) thickness [mm].

  • tf_top (float) – Top flange thickness [mm].

  • tf_bot (float, optional) – Bottom flange thickness [mm]. If None, same as tf_top.

Returns:

Polygon with one rectangular hole.

Return type:

shapely.geometry.Polygon

circle_poly(
D,
resolution=64,
)

Circular section polygon (regular N-gon approximation).

The circle is centred at \((D/2, D/2)\) so that the bounding box starts at the origin.

Parameters:
  • D (float) – Diameter [mm].

  • resolution (int, optional) – Number of vertices on the circumference. Default 64.

Return type:

shapely.geometry.Polygon

custom_poly(
exterior_coords,
holes=None,
)

Arbitrary polygon from vertex coordinates.

Parameters:
  • exterior_coords (list of tuple) – [(x0, y0), (x1, y1), ...]. The ring is automatically closed.

  • holes (list of list of tuple, optional) – Each inner list defines a hole boundary.

Return type:

shapely.geometry.Polygon

double_tee_slab_poly(
b_top,
h_top,
bw,
hw,
stem_spacing,
)

Double-tee precast slab section (tegolo doppio).

A wide top slab with two stems (ribs) below, symmetrically placed.

┌───────────────────────────────┐  b_top
│          top slab             │ h_top
└──┬────┬───────────────┬────┬──┘
   │ s1 │               │ s2 │ hw
   └────┘               └────┘
    bw      spacing      bw
Parameters:
  • b_top (float) – Top slab overall width [mm].

  • h_top (float) – Top slab thickness [mm].

  • bw (float) – Width of each stem [mm].

  • hw (float) – Depth of each stem [mm].

  • stem_spacing (float) – Centre-to-centre distance between the two stems [mm].

Return type:

shapely.geometry.Polygon

h_poly(
bf,
hf_top,
hf_bot,
bw,
hw,
)

H / I section (double-T, symmetric about the vertical axis).

┌─────────────────┐  bf
│   top flange    │ hf_top
└──┬─────────┬────┘
   │  web    │ hw
┌──┴─────────┴────┐
│  bottom flange  │ hf_bot
└─────────────────┘  bf
Parameters:
  • bf (float) – Flange width [mm] (same for top and bottom).

  • hf_top (float) – Top flange thickness [mm].

  • hf_bot (float) – Bottom flange thickness [mm].

  • bw (float) – Web width [mm].

  • hw (float) – Web height [mm] (between flanges).

Return type:

shapely.geometry.Polygon

inv_tee_poly(
bf,
hf,
bw,
hw,
)

Inverted T-section (flange on bottom).

Same parameters as tee_poly() but the flange is at \(y = 0\).

Parameters:
Return type:

shapely.geometry.Polygon

rect_poly(
B,
H,
)

Rectangular section polygon.

(0,H) ┌─────────┐ (B,H)
      │         │
      │         │
(0,0) └─────────┘ (B,0)
Parameters:
  • B (float) – Width [mm].

  • H (float) – Height [mm].

Return type:

shapely.geometry.Polygon

single_tee_slab_poly(
b_top,
h_top,
bw,
hw,
)

Single-tee precast slab section (tegolo singolo).

A wide top slab with a single stem (rib) below.

┌───────────────────────┐  b_top
│       top slab        │ h_top
└────┬───────────┬──────┘
     │   stem    │ hw
     └───────────┘
          bw
Parameters:
  • b_top (float) – Top slab width [mm].

  • h_top (float) – Top slab thickness [mm].

  • bw (float) – Stem width [mm].

  • hw (float) – Stem depth [mm] (below the slab).

Return type:

shapely.geometry.Polygon

tee_poly(
bf,
hf,
bw,
hw,
)

T-section with flange on top.

┌─────────────────┐  ← bf
│     flange      │ hf
└──┬─────────┬────┘
   │  web    │ hw
   │         │
   └─────────┘
      bw

Origin at bottom-left of the bounding box.

Parameters:
  • bf (float) – Flange width [mm].

  • hf (float) – Flange thickness [mm].

  • bw (float) – Web width [mm].

  • hw (float) – Web height [mm] (below the flange).

Return type:

shapely.geometry.Polygon

Raises:

ValueError – If bw > bf.

ideal_gross geometric properties

Exact polygon integrals (Green’s theorem), centroidal and principal second-moments, central inertia ellipse, kern. Documented in detail in ideal_gross_properties.

Homogenized geometric properties of an arbitrary cross-section.

All quantities in this module are computed on the homogenized section (also called ideal section or transformed section): the polygon area contributes with its own elastic modulus, and every point fiber (rebar, tendon, FRP strip) contributes with the differential area \((n_s - n_{\mathrm{bulk}}) A_s\), where \(n_i = E_i / E_{\mathrm{ref}}\).

This is the EC2 / NTC 2018 convention: the polygon is treated as a continuous region of the bulk material, and each reinforcement is added in excess to avoid double-counting the substrate displaced by the bar. Degeneracy is automatic:

  • when no point fibers are present, the section coincides with the polygon alone (scaled by \(n_{\mathrm{bulk}}\));

  • when \(E_s = E_{\mathrm{bulk}}\) for every fiber, the homogenization factors vanish and the result is purely geometrical.

The central quantities are:

  • homogenized area \(A\), static moments \(S_x, S_y\), centroid \((x_G, y_G)\);

  • centroidal second-moments \(I_x, I_y, I_{xy}\) in the user frame, and \(I_\xi \ge I_\eta\) in the principal frame, with rotation angle \(\alpha\);

  • radii of gyration, central inertia ellipse, kern;

  • distances to the extreme fibers (polygon vertices and point fibers are considered);

  • elastic section moduli \(W_x^{\pm}, W_y^{\pm}, W_\xi^{\pm}, W_\eta^{\pm}\);

  • plastic section moduli \(Z_x, Z_y, Z_\xi, Z_\eta\) obtained by locating the plastic neutral axis that splits the homogenized area in half;

  • placeholder for the torsional constant \(I_t\) (filled in by a future St.-Venant solver).

class HomogenizedRebar(
x: float,
y: float,
area: float,
E: float,
)

Bases: object

Minimal description of a point fiber for homogenization.

Parameters:
  • x (float) – Location in the user frame \([\mathrm{mm}]\).

  • y (float) – Location in the user frame \([\mathrm{mm}]\).

  • area (float) – Cross-sectional area \(A_s\,[\mathrm{mm}^2]\).

  • E (float) – Elastic modulus \(E_s\,[\mathrm{MPa}]\).

class SectionProperties(
E_ref: float,
E_bulk: float,
n_bulk: float,
area: float,
Sx: float,
Sy: float,
xg: float,
yg: float,
Ixx_o: float,
Iyy_o: float,
Ixy_o: float,
Ix: float,
Iy: float,
Ixy: float,
I_xi: float,
I_eta: float,
alpha: float,
rho_x: float,
rho_y: float,
rho_xi: float,
rho_eta: float,
I_polar: float,
is_convex: bool,
c_y_top: float,
c_y_bot: float,
c_x_left: float,
c_x_right: float,
c_xi_pos: float,
c_xi_neg: float,
c_eta_pos: float,
c_eta_neg: float,
W_x_top: float,
W_x_bot: float,
W_y_left: float,
W_y_right: float,
W_xi_pos: float,
W_xi_neg: float,
W_eta_pos: float,
W_eta_neg: float,
Z_x: float,
Z_y: float,
Z_xi: float,
Z_eta: float,
I_t: float | None = None,
)

Bases: object

Bundle of homogenized geometric properties of a cross-section.

All second-moment quantities are reported in \(\mathrm{mm}^4\), areas in \(\mathrm{mm}^2\), lengths in \(\mathrm{mm}\), and the principal-axis orientation angle in radians. All integral quantities (A, S, I, Z) are computed on the homogenized section, using the convention

\[\mathrm{d}A_{\mathrm{id}} = n_{\mathrm{bulk}}\,\mathrm{d}A \quad\text{(on the polygon)},\qquad \Delta A_{s,\mathrm{id}} = (n_s - n_{\mathrm{bulk}})\,A_s \quad\text{(per point fiber)},\]

with \(n_i = E_i / E_{\mathrm{ref}}\).

Variables:
  • E_ref (float) – Reference modulus used for homogenization.

  • E_bulk (float) – Elastic modulus of the polygon material.

  • n_bulk (float) – \(E_{\mathrm{bulk}} / E_{\mathrm{ref}}\) (= 1 by default).

  • area (float) – Homogenized area \(A_{\mathrm{id}}\).

  • Sy (Sx,) – Static moments about the user \(x, y\) axes through the origin.

  • yg (xg,) – Centroid of the homogenized section.

  • Ixy_o (Ixx_o, Iyy_o,) – Homogenized second-moments about the user origin.

  • Ixy (Ix, Iy,) – Homogenized centroidal second-moments in the user frame.

  • I_eta (I_xi,) – Homogenized principal centroidal second-moments \(I_\xi \ge I_\eta\).

  • alpha (float) – Rotation (CCW, radians) from the user \(x\) axis to the principal \(\xi\) axis, in \((-\pi/2, +\pi/2]\).

  • rho_eta (rho_x, rho_y, rho_xi,) – Radii of gyration.

  • I_polar (float) – \(I_p = I_x + I_y = I_\xi + I_\eta\).

  • is_convex (bool) – Whether the exterior ring is convex.

  • c_y_bot (c_y_top,) – Distances from the centroid to the extreme \(y\) fibers (always \(\ge 0\)). Polygon vertices and point-fiber positions are both considered.

  • c_x_right (c_x_left,) – Same for \(x\).

  • c_xi_neg (c_xi_pos,) – Distances to the extreme fibers along \(\xi\).

  • c_eta_neg (c_eta_pos,) – Distances to the extreme fibers along \(\eta\).

  • W_x_bot (W_x_top,) – Elastic section moduli for bending about \(x\): \(W_x^{\mathrm{top}} = I_x / c_y^{\mathrm{top}}\), \(W_x^{\mathrm{bot}} = I_x / c_y^{\mathrm{bot}}\).

  • W_y_right (W_y_left,) – Analogous for bending about \(y\).

  • W_xi_neg (W_xi_pos,) – Elastic moduli about the principal \(\xi\) axis: \(W_\xi = I_\xi / c_\eta\).

  • W_eta_neg (W_eta_pos,) – Elastic moduli about the principal \(\eta\) axis: \(W_\eta = I_\eta / c_\xi\).

  • Z_eta (Z_x, Z_y, Z_xi,) – Plastic section moduli of the homogenized section about the four reference axes through the centroid. The plastic neutral axis is the line that splits \(A_{\mathrm{id}}\) in two equal halves; \(Z\) is the sum of the absolute first moments of the two halves about the PNA.

  • I_t (float or None) – Torsional constant. Not yet computed (deferred to a future St.-Venant solver); kept in the schema so that JSON export and the future GUI have a stable layout.

compute_inertia_ellipse(
props,
n_points=240,
)

Sample points on the central inertia ellipse (Culmann).

In the centroidal principal frame \((\xi, \eta)\),

\[\frac{\xi^2}{\rho_\eta^2} + \frac{\eta^2}{\rho_\xi^2} = 1.\]
Parameters:
Return type:

numpy.ndarray of shape (n_points, 2)

compute_kern_polygon(
polygon,
props,
)

Compute the central kern (core) of the cross-section.

Parameters:
Return type:

numpy.ndarray of shape (N+1, 2) or (0, 2)

compute_section_properties(
polygon: Polygon,
rebars: Sequence[HomogenizedRebar] | None = None,
E_bulk: float = 1.0,
E_ref: float | None = None,
compute_plastic: bool = False,
) SectionProperties

Compute the homogenized geometric properties of a section.

Every polygon area element contributes as \(n_{\mathrm{bulk}}\,\mathrm{d}A\), and every point fiber contributes as \((n_s - n_{\mathrm{bulk}}) A_s\). In the typical RC case one takes \(E_{\mathrm{ref}} = E_{\mathrm{bulk}} = E_{\mathrm{cm}}\), giving \(n_{\mathrm{bulk}} = 1\) and \(n_s = E_s / E_{\mathrm{cm}}\).

Parameters:
  • polygon (shapely.geometry.Polygon) – Section outline with any number of holes.

  • rebars (sequence of HomogenizedRebar, optional) – Point fibers. If None or empty, the section is treated as pure bulk material.

  • E_bulk (float, optional) – Elastic modulus of the polygon material. Default 1.0.

  • E_ref (float or None, optional) – Reference modulus. If None, defaults to E_bulk.

  • compute_plastic (bool, optional) – Whether to compute the plastic moduli. Default False.

Return type:

SectionProperties

Raises:

ValueError – If the polygon is empty / invalid / has non-positive area, or if any modulus is non-positive.

Legacy rectangular section

Rectangular section factory — convenience wrapper.

RectSection() is a factory function (not a class) that builds a GenericSection with a rectangular polygon and grid meshing. It replaces the former RectSection dataclass, which was a thin delegation wrapper that introduced a mesh-size bug on anisotropic grids.

The returned object is a GenericSection. All attributes expected by FiberSolver are available directly (x_fibers, y_fibers, A_fibers, B, H, n_fibers_x, n_fibers_y, dx, dy, polygon, …).

Grid resolution

The mesh resolution in the y-direction is controlled by n_fibers_y. The x-direction follows one of two rules:

  • Isotropic (default, n_fibers_x 1): the x-resolution is derived from the same mesh_size = H / n_fibers_y, giving a square-celled grid. Example: B = 300, H = 600, n_fibers_y = 100 → mesh_size = 6 → n_fibers_x = ceil(300/6) = 50.

  • Explicit (n_fibers_x > 1): the user-specified value is passed as n_grid_x.

RectSection(
B,
H,
bulk_material,
rebars,
n_fibers_y=100,
n_fibers_x=1,
)

Create a rectangular GenericSection.

Parameters:
  • B (float) – Width (x-direction) [mm].

  • H (float) – Height (y-direction) [mm].

  • bulk_material (Material) – Bulk material (concrete, timber, …).

  • rebars (list of RebarLayer) – Point fibers.

  • n_fibers_y (int, optional) – Fiber rows. Controls the isotropic mesh size: \(s = H / n_y\). Default 100.

  • n_fibers_x (int, optional) – Fiber columns. When > 1, overrides the x-resolution explicitly. When 1 (default), the x-resolution is derived from the isotropic mesh size \(s\).

Returns:

Fully meshed rectangular section with all attributes expected by the solver (x_fibers, y_fibers, A_fibers, B, H, n_fibers_x, n_fibers_y, dx, dy, polygon, …).

Return type:

GenericSection