gensec.geometry

Section definition, fiber meshing, and parametric shape factories.

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.

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 gross_area:

Gross polygon area [mm²].

vartype 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

mesh_summary()

Return a summary dict of mesh quality metrics.

Returns:

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

Return type:

dict

property x_centroid

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

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.

Rectangular section (legacy wrapper)

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

Package-level exports

Geometry subpackage.

Provides section definition classes: point fibers (RebarLayer) and rectangular section assemblies (RectSection).

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\).

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