Non-prismatic Elements#

A non-prismatic member has a flexural rigidity \(EI(x)\) that varies along its length — a haunch, a taper or a stepped section. In PyCBA such a member is an element, defined by a SectionEI object built from contiguous segments (const, linear, pwl, poly) and analysed exactly by flexibility integration.

The companion tutorial, Creep, Shrinkage, and Thermal Analysis, covers the loading side (creep/shrinkage/thermal curvatures), including a combined example that applies an imposed curvature to the non-prismatic beam built here. The underlying method is in the Theoretical Basis; the source texts are on the References page.

[1]:
import pycba as cba
import numpy as np
import matplotlib.pyplot as plt
from pycba import SectionEI

Example 1 - Building a variable-EI section#

A non-prismatic member is described by a SectionEI built from contiguous segments (const, linear, pwl, poly) giving \(EI(x)\) in the span-local coordinate. Here the member is stiff (haunched) at both supports and slender at midspan. SectionEI.plot() draws \(EI(x)\) so you can check the section you built — kinks show as slope changes and the segment joins are flagged.

[2]:
# Stiff (haunched) at both supports, slender at midspan: two linear haunches
# and a constant flat soffit.  SectionEI.plot() is an input-verification of EI(x).
sec = SectionEI(
    [
        ("linear", [0.0, 3.0], [3.0e5, 1.2e5]),   # haunch down from the left support
        ("const",  [3.0, 9.0], 1.2e5),            # slender flat soffit
        ("linear", [9.0, 12.0], [1.2e5, 3.0e5]),  # haunch up to the right support
    ]
)
fig, ax = sec.plot(figsize=(10, 3.5))
fig.tight_layout()
../_images/notebooks_nonprismatic_3_0.png

Example 2 - Two-span beam with a haunched support#

Haunching a continuous beam over its interior support stiffens the “pier” and attracts hogging moment to it. Each span deepens parabolically toward the interior support (so \(EI\) rises there); we compare the pier moment with the prismatic beam, whose value is the textbook \(-wL^2/8\).

[3]:
# Symmetric two-span beam; section depth deepens parabolically to the interior
# support, so EI = E*b*d(x)^3/12 rises toward the pier.
E, b = 30.0e6, 1.0                 # E = 30 GPa (kPa), unit width
Lsp, DC, Dh, Lh, w = 10.0, 0.6, 1.2, 3.0, 30.0   # span, mid depth, pier depth, haunch len, UDL
EI_const = E * b * DC**3 / 12.0    # prismatic (mid-depth) rigidity


def haunch_poly(d_end, d_pier, x_end, x_pier):
    """Parabolic depth: flat (vertex) at the shallow end (d_end at x_end),
    deepening to d_pier at the support (x_pier).  Returns an EI(x) callable."""
    def f(x):
        s = (np.asarray(x, float) - x_end) / (x_pier - x_end)
        return E * b * (d_end + (d_pier - d_end) * s**2) ** 3 / 12.0
    return f


# span 1: prismatic at the end support, haunch deepening to the pier (right end)
sec1 = SectionEI(
    [
        ("const", [0.0, Lsp - Lh], EI_const),
        ("poly",  [Lsp - Lh, Lsp], haunch_poly(DC, Dh, Lsp - Lh, Lsp), 6),
    ]
)
# span 2: the mirror image of span 1 -- haunch at the pier (left end), prismatic
# to the right.  Its parabola vertex is at the shallow (DC) end x = Lh, so the
# EI profile is symmetric about the pier.
sec2 = SectionEI(
    [
        ("poly",  [0.0, Lh], haunch_poly(DC, Dh, Lh, 0.0), 6),
        ("const", [Lh, Lsp], EI_const),
    ]
)

ba_h = cba.BeamAnalysis([Lsp, Lsp], [sec1, sec2], [-1, 0, -1, 0, -1, 0])
ba_h.add_udl(1, w)
ba_h.add_udl(2, w)
ba_h.analyze(npts=300)

ba_p = cba.BeamAnalysis([Lsp, Lsp], [EI_const, EI_const], [-1, 0, -1, 0, -1, 0])
ba_p.add_udl(1, w)
ba_p.add_udl(2, w)
ba_p.analyze(npts=300)
[3]:
0

The two-span beam and its loading (the schematic shows the supports and loads; the varying EI is not depicted):

[4]:
ba_h.plot_beam();
../_images/notebooks_nonprismatic_7_0.png
[5]:
# Bending moment: haunched vs prismatic, via the built-in plotter (overlaid)
ax = ba_h.plot_bmd(label="haunched")
ba_p.plot_bmd(ax=ax, color="0.5", ls="--", label="prismatic")
ax.legend();
../_images/notebooks_nonprismatic_8_0.png
[6]:
# Extract the interior-support (pier) moment with the .at() point query
M_pier_h = ba_h.at(Lsp)["M"]
M_pier_p = ba_p.at(Lsp)["M"]
print(f"Prismatic pier moment = {M_pier_p:8.1f} kNm  (closed form -wL^2/8 = {-w * Lsp**2 / 8:.1f})")
print(
    f"Haunched  pier moment = {M_pier_h:8.1f} kNm  "
    f"({100 * (abs(M_pier_h) - abs(M_pier_p)) / abs(M_pier_p):+.0f}% — haunch draws hogging to the pier)"
)
Prismatic pier moment =   -375.0 kNm  (closed form -wL^2/8 = -375.0)
Haunched  pier moment =   -501.0 kNm  (+34% — haunch draws hogging to the pier)