civilpy.structural.odot package

Designers built around ODOT standard bridge drawings: prestressed box beams, bridge railing, guardrail, headwalls, and rocker bolsters.

Submodules

civilpy.structural.odot.approach_slab module

ODOT AS-1-15 Reinforced Concrete Approach Slab.

Transcribed from Ohio DOT Standard Construction Drawing AS-1-15 (revised 01-20-2023, 2 sheets). The drawing remains the controlling document; this module encodes its reinforcing-steel table, bar-count and bar-length formulas, section geometry, and the sheet-2 joint/seat detail catalog so the Grasshopper component (Notebooks/Rhino Components/AS-1-15.py) and downstream quantity takeoffs can be driven from tested Python.

Design basis printed on the sheet: AASHTO LRFD Bridge Design Specifications (2014) and ODOT BDM (2007); dead load 60 lb/ft^2 (FWS), live load HL-93; concrete f’c = 4,500 psi; reinforcing steel fy = 60,000 psi (pay item: ITEM 526 - REINFORCED CONCRETE APPROACH SLABS, anchor bars paid separately under ITEM 509).

Conventions match civilpy.structural.bridge_layout: plan frame with X along stations (increasing away from the bridge), Y transverse, Z up, Z = 0 at the top of the approach slab; plan lengths in feet, section dimensions in inches (_in suffixes). Positive skew rotates the support (bridge-limit) line counterclockwise in plan, so points at +Y shift toward +X.

class civilpy.structural.odot.approach_slab.ApproachSlabDesign(length_ft: float, thickness_in: float, a_bar_spacing_in: float, a_bar_mark: str, a_bar_length_ft: float, a_bar_dimension_ft: float, b501_bottom_spacing_in: float, b501_bottom_count: int, b501_top_count: int, c_bar_mark: str, c_bar_length_ft: float)[source]

Bases: object

One row of the AS-1-15 reinforcing steel table.

Lengths in feet, spacings/thicknesses in inches. Bar counts that depend on the slab width W are computed by the module-level functions, matching the tabulated formulas (e.g. 12(W-0.5)/K + 1).

a_bar_dimension_ft: float
a_bar_length_ft: float
a_bar_mark: str
a_bar_spacing_in: float
b501_bottom_count: int
b501_bottom_spacing_in: float
b501_top_count: int
c_bar_length_ft: float
c_bar_mark: str
length_ft: float
thickness_in: float
class civilpy.structural.odot.approach_slab.ApproachSlabInput(length_ft: float, width_ft: float, skew_deg: float = 0.0, end_thickness_in: float | None = None, seat_length_in: float = 9.0, backwall_thickness_in: float = 14.0)[source]

Bases: object

The design choices an engineer makes on the project plans.

length_ft must be one of the tabulated L values. width_ft is the approach slab width W per the sheet’s width-dimension figure (out-to-out without curbs, toe-to-toe of curbs, or toe-to-toe of barrier). end_thickness_in is X (thickness at the abutment end); the sheet requires X >= T and expresses X in feet in its formulas. seat_length_in is the bearing length on the seat/backwall (6 in to 1’-0” per section B-B). backwall_thickness_in selects the anchor bar (D801 needs >= 14 in; D802 covers the 11 in PS box beam case).

backwall_thickness_in: float = 14.0
end_thickness_in: float | None = None
length_ft: float
seat_length_in: float = 9.0
skew_deg: float = 0.0
width_ft: float
class civilpy.structural.odot.approach_slab.ApproachSlabLayout(inputs: ~civilpy.structural.odot.approach_slab.ApproachSlabInput, design: ~civilpy.structural.odot.approach_slab.ApproachSlabDesign, outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], profile: tuple[tuple[float, float], ...], bars: tuple[~civilpy.structural.odot.approach_slab.BarRun, ...], anchor_mark: str, anchor_length_ft: float, pay_area_sy: float, notes: tuple[str, ...] = <factory>)[source]

Bases: object

Everything the Grasshopper component draws.

outline is the counterclockwise plan parallelogram at z = 0 (top of slab), starting at the bridge-limit / y = 0 corner. profile is the longitudinal section polyline in (u, z) feet, u measured from the bridge limit along the roadway; it is swept transversely (with the skew shear) to form the solid.

anchor_length_ft: float
anchor_mark: str
bars: tuple[BarRun, ...]
design: ApproachSlabDesign
inputs: ApproachSlabInput
notes: tuple[str, ...]
outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
pay_area_sy: float
profile: tuple[tuple[float, float], ...]
class civilpy.structural.odot.approach_slab.BarRun(mark: str, size: int, points: tuple[tuple[float, float, float], ...])[source]

Bases: object

One physical bar as a polyline of plan-frame points (feet).

mark: str
points: tuple[tuple[float, float, float], ...]
size: int
class civilpy.structural.odot.approach_slab.SeatConfiguration(support: str, wearing_surface: str, details: tuple[str, ...])[source]

Bases: object

One sheet-2 configuration: which joint details apply at the bridge limit for a support type + wearing surface combination.

details: tuple[str, ...]
support: str
wearing_surface: str
civilpy.structural.odot.approach_slab.a_bar_count(width_ft: float, design: ApproachSlabDesign) int[source]

A-bar count per slab: [12(W-0.5)/K] + 1.

civilpy.structural.odot.approach_slab.anchor_bar_mark(backwall_thickness_in: float) str[source]

Which anchor bar the sheet permits for a given backwall thickness.

D801 cannot be used on backwalls less than 14 in thick; D802 is for prestressed box beam bridges with 11 in backwalls.

civilpy.structural.odot.approach_slab.approach_slab_design(length_ft: float) ApproachSlabDesign[source]

The standard design for an approach slab length L (ft).

civilpy.structural.odot.approach_slab.b501_length_ft(width_ft: float, skew_deg: float = 0.0) float[source]

B501 bar length (W - 0.5) sec(theta) (ft).

civilpy.structural.odot.approach_slab.c_bar_count(width_ft: float) int[source]

C-bar count per slab: [12(W-0.5)/6] + 1.

civilpy.structural.odot.approach_slab.d801_length_ft(end_thickness_ft: float, skew_deg: float = 0.0) float[source]

D801 anchor bar length (ft): 1’-0” leg + (1.414X + 0.823)sec (theta) diagonal (X = slab thickness at the abutment end, ft). The 180-degree hook at the free end is included in the diagonal term as tabulated.

civilpy.structural.odot.approach_slab.d802_length_ft(end_thickness_ft: float, skew_deg: float = 0.0) float[source]

D802 anchor bar length (ft): 1’-0” + (1.414X + 0.202)sec(theta) + 1’-0”.

civilpy.structural.odot.approach_slab.d_bar_count(width_ft: float) int[source]

D801/D802 anchor-bar count: [12(W-0.5)/18] + 1.

civilpy.structural.odot.approach_slab.layout_approach_slab(inp: ApproachSlabInput) ApproachSlabLayout[source]

Generate the AS-1-15 approach slab layout.

Raises ValueError when inputs leave the drawing’s assumptions (untabulated length, X < T, seat length outside 6-12 in, skew >= 60 degrees, or a backwall too thin for either anchor bar).

civilpy.structural.odot.approach_slab.pay_area_sy(length_ft: float, width_ft: float) float[source]

Estimated ITEM 526 quantity (square yards): plan area L x W.

civilpy.structural.odot.bikeway_railing module

Ohio DOT bikeway railing (SCD RM-5.2): a treated-wood post-and-rail fence along bicycle paths.

Transcribed from Standard Roadway Construction Drawing RM-5.2, “Bikeway Railing” (rev. 07-21-2023, 1 sheet). A wood system — 6x6 posts with a 2x8 top rail and two 2x12 face rails — not a crashworthy barrier; it pairs with the structures-side BR-2-15 sidewalk railing only in role, not in section. The drawing remains the controlling document.

Lengths in inches unless a name says otherwise.

class civilpy.structural.odot.bikeway_railing.BikewayRailingInput(length_ft: float, flared_ends: bool = True, low_shoulder: bool = False)[source]

Bases: object

One straight bikeway railing run. length_ft is the fence length between flares (as shown on plans); flared ends add FLARED_END_LENGTH_FT each when flared_ends.

flared_ends: bool = True
length_ft: float
low_shoulder: bool = False

< 1 ft graded shoulder (note 4)

class civilpy.structural.odot.bikeway_railing.BikewayRailingLayout(inputs: BikewayRailingInput, post_stations_ft: tuple[float, ...], midspan_stations_ft: tuple[float, ...], post_length_in: float, embedment_in: float, n_rail_pieces: int, total_length_ft: float, notes: tuple[str, ...] = ())[source]

Bases: object

Members of one bikeway railing run.

post_stations_ft are full-post centers from the run start; midspan_stations_ft the 18 in rail-stiffener posts centered in each bay. Rails run the full length in <= 20 ft pieces butt- jointed on posts (top rail and lower face rail staggered to alternate posts, note 6).

embedment_in: float
inputs: BikewayRailingInput
midspan_stations_ft: tuple[float, ...]
n_rail_pieces: int
notes: tuple[str, ...] = ()
post_length_in: float
post_stations_ft: tuple[float, ...]
total_length_ft: float
civilpy.structural.odot.bikeway_railing.FLARED_END_LENGTH_FT = 20.0

each end, turned away from the path

civilpy.structural.odot.bikeway_railing.LOWER_FACE_RAIL_GAP_IN = 6.0

lower face rail clears grade by 6 in

civilpy.structural.odot.bikeway_railing.LOW_SHOULDER_EMBEDMENT_IN = 60.0

1 or flatter), use longer posts giving 5 ft-0 in embedment (note 4).

Type:

With less than 1 ft of graded shoulder beyond the rail face (10

civilpy.structural.odot.bikeway_railing.MIDSPAN_POST_LENGTH_IN = 18.0

1 ft-6 in, 45 deg top cut, rails only

civilpy.structural.odot.bikeway_railing.OFFSET_PREFERRED_IN = 24.0

face of rail to edge of pavement

civilpy.structural.odot.bikeway_railing.POST_EMBEDMENT_MIN_IN = 36.0

3 ft-0 in min (see LOW_SHOULDER note)

civilpy.structural.odot.bikeway_railing.POST_LENGTH_IN = 78.0

6 ft-6 in standard post

civilpy.structural.odot.bikeway_railing.POST_REVEAL_IN = 36.0

grade to underside of the top rail zone

civilpy.structural.odot.bikeway_railing.POST_SPACING_MAX_IN = 120.0

10 ft-0 in max

civilpy.structural.odot.bikeway_railing.RAILING_HEIGHT_IN = 42.0

Rail top height above grade (3 ft reveal + top-rail zone).

civilpy.structural.odot.bikeway_railing.RAIL_LENGTH_MAX_FT = 20.0

max piece length, butt joints on posts

civilpy.structural.odot.bikeway_railing.layout_bikeway_railing(inp: BikewayRailingInput) BikewayRailingLayout[source]

Lay out posts and rails for one RM-5.2 bikeway railing run.

Full posts at up to 10 ft centers with a mid-span stiffener post in each bay; each flared end (20 ft at 30 degrees away from the path) is treated as additional railing length with the same spacing. Raises ValueError for a non-positive length.

civilpy.structural.odot.box_beam module

Ohio DOT prestressed concrete box beam construction details (PSBD-1-25).

Transcribed from the Ohio DOT Standard Bridge Drawing PSBD-1-25, “Prestressed Concrete Box Beam Details” (Office of Structural Engineering, 2025-07-18, rev. 2026-01-16, 6 sheets). Captured here: design-stress and material specs, transverse tie rod and anchor dowel details, shear-key grouting, intermediate-diaphragm placement rules, the available beam depths, and the standard steel-reinforced elastomeric bearing pads (B1/B2) with their design data.

The standard box-beam strand patterns, eccentricities, camber, and load ratings live on the companion design data sheet PSBDD-1-25 (DESIGN_DATA_SHEET); those are carried in civilpy.structural.odot.box_beam_design.

Lengths are in inches, forces in kips, stresses/moduli in ksi unless a field name says otherwise. Values are spot-checked against the drawing in the test suite; the drawing remains the controlling document.

civilpy.structural.odot.box_beam.ANCHOR_DOWEL = AnchorDowelDetail(diameter=1.0, beam_hole_diameter=2.0, beam_hole_diameter_compression_seal=2.5, fixed_substructure_hole_min=1.0625, expansion_substructure_hole_min=1.25)

Anchor dowel detail (PSBD-1-25).

class civilpy.structural.odot.box_beam.AnchorDowelDetail(diameter: float = 1.0, beam_hole_diameter: float = 2.0, beam_hole_diameter_compression_seal: float = 2.5, fixed_substructure_hole_min: float = 1.0625, expansion_substructure_hole_min: float = 1.25)[source]

Bases: object

Anchor dowel details (PSBD-1-25 sheets 1 & 5).

beam_hole_diameter: float = 2.0
beam_hole_diameter_compression_seal: float = 2.5
diameter: float = 1.0
expansion_substructure_hole_min: float = 1.25
fixed_substructure_hole_min: float = 1.0625
civilpy.structural.odot.box_beam.BDM_ASPHALT_MIN_IN = 3.0

Asphalt concrete wearing surface on NON-composite box beams, inches: 3 in minimum (BDM 309.1.B, two 1.5 in lifts of Item 441), 8 in maximum (BDM 308.2.3.3). The first lift is placed at variable thickness to take up camber and grade, so the mean is often thicker than 3 in – use the computed topping depth (BDM 308.2.3.3.e) for a real design.

civilpy.structural.odot.box_beam.BDM_ASPHALT_PCF = 145.0

Unit weights, pcf, from BDM 909 (“assumptions … while performing the load rating analysis unless more accurate site information is available”). Note asphalt is 145 pcf, not the 140 pcf of LRFD Table 3.5.1-1.

civilpy.structural.odot.box_beam.BDM_COMPOSITE_DECK_MIN_IN = 6.0

Minimum composite deck slab on prestressed box beams, inches (BDM 308.2.3.3.c, “#6 bars, longitudinal at 18-in max, transverse at 9-in max”).

civilpy.structural.odot.box_beam.BDM_FUTURE_WEARING_SURFACE_KSF = 0.06

“Design all new bridges that carry highway traffic for a future wearing surface (FWS) of 0.060-ksf.” Unqualified – it applies whether or not the bridge also carries an asphalt wearing surface today. Two exceptions in the manual: temporary structures take 0.0 ksf (BDM 501), and FWS is excluded from the dead load used for shop camber (BDM 308.2.2.1.f).

Type:

Future wearing surface allowance, ksf. BDM 303.1.2

civilpy.structural.odot.box_beam.BEARING_DESIGN_DATA = BearingDesignData(durometer=50, allowable_compressive_stress=1.25, shear_modulus_compressive=0.095, shear_modulus_horizontal=0.13, creep_deflection_percent=25.0, bearings_per_beam=4, spec_edition='AASHTO LRFD BDS 10th Edition (2024)')

Elastomeric bearing design data (PSBD-1-25 sheet 6/6).

civilpy.structural.odot.box_beam.BEARING_PADS: dict[str, BearingPad] = {'B1': BearingPad(name='B1', length=7.0, width=11.0, total_thickness=1.409, t_external=0.35, t_internal=0.5, t_steel=0.1046, n_laminates=2, max_total_load=36.0, max_expansion_length=92.0, max_movement=0.53, rotation_capacity=0.024), 'B2': BearingPad(name='B2', length=9.0, width=14.0, total_thickness=2.014, t_external=0.35, t_internal=0.5, t_steel=0.1046, n_laminates=3, max_total_load=74.0, max_expansion_length=147.0, max_movement=0.847, rotation_capacity=0.024)}

Standard elastomeric bearing pads B1 and B2 (PSBD-1-25 sheet 6/6).

civilpy.structural.odot.box_beam.BEVELED_LOAD_PLATE = BeveledLoadPlate(min_thickness=1.5, plate_grade='ASTM A709 Gr 50', anchor_rod_diameter=0.75, plate_washer='3 x 3 x 1/2', expansion_anchor_hole=1.25, stud_yield=50.0)

Beveled load plate detail (BD-1-11).

civilpy.structural.odot.box_beam.BOX_BEAM_DEPTHS: tuple[int, ...] = (17, 21, 27, 33, 42)

Standard box-beam depths, inches (PSBD-1-25 sheet 4/6).

civilpy.structural.odot.box_beam.BOX_BOTTOM_CHAMFER_IN = 0.75

3/4 in x 3/4 in chamfer at each bottom (soffit) corner (ODOT’s standard chamfer), so the soffit is 46.5 in wide on a 48 in beam. The top corners are square. Not dimensioned on sheet 2/6 – recovered from the published areas, which it reproduces to +-0.01% at all five depths (1 in gives -0.07%, 1 1/2 in gives -0.25%).

civilpy.structural.odot.box_beam.BOX_FLANGE_THICKNESS_IN = 5.5

Top/bottom flange thickness, inches – PSBD-1-25 sheet 2/6 LEFT dimension chain (5 1/2” | void | 5 1/2”), identical at every depth, so the void is centred on the beam. Verified: this geometry reproduces the sheet 4/6 published Ab, Yb and Ib to 0.2% at all five depths.

civilpy.structural.odot.box_beam.BOX_SECTION_PROPERTIES: dict[int, BoxSectionProperties] = {17: BoxSectionProperties(depth=17, width=48.0, area=580.8, i=18652, yb=8.42, zt=2175, zb=2214, ic=39506, ybc=11.59, ztc=7302, zbc=3409), 21: BoxSectionProperties(depth=21, width=48.0, area=632.3, i=33551, yb=10.4, zt=3165, zb=3226, ic=63190, ybc=13.92, ztc=8925, zbc=4540), 27: BoxSectionProperties(depth=27, width=48.0, area=689.3, i=65398, yb=13.38, zt=4802, zb=4888, ic=111083, ybc=17.44, ztc=11620, zbc=6369), 33: BoxSectionProperties(depth=33, width=48.0, area=746.2, i=109652, yb=16.5, zt=6646, zb=6646, ic=175131, ybc=20.9, ztc=14474, zbc=8379), 42: BoxSectionProperties(depth=42, width=48.0, area=831.8, i=201537, yb=20.82, zt=9515, zb=9680, ic=303890, ybc=26.0, ztc=18993, zbc=11688)}

48 in wide box-beam section properties by depth, as published on PSBD-1-25 sheet 4/6.

VERIFIED (2026-07-28) against the section dimensioned on sheet 2/6: recomputing Ab, Yb and Ib from that geometry reproduces every value in this table to within 0.2% (the residual is the small exterior corner chamfers, which the polygon does not draw). The table is internally self-consistent as well – S = I/c closes both beam-only and composite.

civilpy.structural.odot.box_beam.BOX_VOID_FILLET_IN = 3.0

Void corner fillet, inches (square). Only the 17 in beam uses 1 1/2” x 1 1/2”; every deeper beam uses 3” x 3”.

civilpy.structural.odot.box_beam.BOX_WEB_THICKNESS_IN = 6.0

6” | 3’-0” | 6” bottom chain).

Type:

Side web thickness, inches (sheet 2/6

civilpy.structural.odot.box_beam.BOX_WIDTH_IN = 48.0

Standard (and only current) box-beam width, inches. Earlier editions of this drawing (PSBD-2-07) also cataloged a 36 in wide beam; PSBD-1-25 carries 48 in wide adjacent box beams only.

class civilpy.structural.odot.box_beam.BearingDesignData(durometer: int = 50, allowable_compressive_stress: float = 1.25, shear_modulus_compressive: float = 0.095, shear_modulus_horizontal: float = 0.13, creep_deflection_percent: float = 25.0, bearings_per_beam: int = 4, spec_edition: str = 'AASHTO LRFD BDS 10th Edition (2024)')[source]

Bases: object

Elastomeric bearing design data (PSBD-1-25 sheet 6/6).

allowable_compressive_stress: float = 1.25

Allowable compressive stress, ksi.

bearings_per_beam: int = 4

Bearings required per beam.

creep_deflection_percent: float = 25.0

25-year creep deflection / instantaneous deflection, percent.

durometer: int = 50
shear_modulus_compressive: float = 0.095

Shear modulus at 73 F for maximum compressive strength, ksi.

shear_modulus_horizontal: float = 0.13

Shear modulus at 73 F for horizontal forces, ksi.

spec_edition: str = 'AASHTO LRFD BDS 10th Edition (2024)'

Governing spec edition.

class civilpy.structural.odot.box_beam.BearingPad(name: str, length: float, width: float, total_thickness: float, t_external: float, t_internal: float, t_steel: float, n_laminates: int, max_total_load: float, max_expansion_length: float, max_movement: float, rotation_capacity: float = 0.024)[source]

Bases: object

A standard steel-reinforced elastomeric bearing pad (PSBD-1-25 sheet 6/6 table). Lengths in inches, load in kips, expansion length in feet.

length: float
max_expansion_length: float
max_movement: float
max_total_load: float
n_laminates: int
name: str
rotation_capacity: float = 0.024
t_external: float
t_internal: float
t_steel: float
total_thickness: float
width: float
class civilpy.structural.odot.box_beam.BeveledLoadPlate(min_thickness: float = 1.5, plate_grade: str = 'ASTM A709 Gr 50', anchor_rod_diameter: float = 0.75, plate_washer: str = '3 x 3 x 1/2', expansion_anchor_hole: float = 1.25, stud_yield: float = 50.0)[source]

Bases: object

Beveled steel load plate detail (BD-1-11).

anchor_rod_diameter: float = 0.75
expansion_anchor_hole: float = 1.25
min_thickness: float = 1.5
plate_grade: str = 'ASTM A709 Gr 50'
plate_washer: str = '3 x 3 x 1/2'
stud_yield: float = 50.0
class civilpy.structural.odot.box_beam.BoxBeamDesignSpec(fc_28day_range: tuple[float, float] = (5.5, 7.0), fci_release_range: tuple[float, float] = (4.0, 5.0), fc_cast_in_place: float = 4.5, fy_reinforcing: float = 60.0, strand_grade: int = 270, strand_diameter: float = 0.5, strand_area_options: tuple[float, ...] = (0.153, 0.167))[source]

Bases: object

Design-stress and material specifications (PSBD-1-25 sheet 1/6).

Concrete strengths are designer-selected ranges; the strand and reinforcing values are fixed by the standard. Stresses in ksi.

fc_28day_range: tuple[float, float] = (5.5, 7.0)

Designer-selected 28-day concrete strength range, ksi.

fc_cast_in_place: float = 4.5

Cast-in-place (composite topping) concrete strength, ksi.

fci_release_range: tuple[float, float] = (4.0, 5.0)

Designer-selected release strength range, ksi.

fy_reinforcing: float = 60.0

Reinforcing steel minimum yield, ksi (C&MS 709.00).

strand_area_options: tuple[float, ...] = (0.153, 0.167)

Nominal strand cross-sectional area options, in^2.

strand_diameter: float = 0.5

Strand diameter, inches (0.5 in, 7-wire low-relaxation).

strand_grade: int = 270

Prestressing strand grade (ASTM A416, C&MS 711.27).

class civilpy.structural.odot.box_beam.BoxSectionProperties(depth: int, width: float = 48.0, area: float = 0.0, i: float = 0.0, yb: float = 0.0, zt: float = 0.0, zb: float = 0.0, ic: float = 0.0, ybc: float = 0.0, ztc: float = 0.0, zbc: float = 0.0)[source]

Bases: object

Non-composite (“beam only”) and composite section properties for one standard box-beam depth (PSBD-1-25 sheet 4/6 tables). Lengths in inches; area in in^2, i/ic in in^4, zt/zb/ztc/zbc in in^3. The composite values assume the standard COMPOSITE_SLAB_STRUCTURAL_THICKNESS_IN topping at COMPOSITE_MODULAR_RATIO; they apply to any beam of this depth when a CIP composite slab is cast, independent of which design table (composite vs. non-composite strand pattern) governs the beam itself.

area: float = 0.0
depth: int
i: float = 0.0
ic: float = 0.0
width: float = 48.0
yb: float = 0.0
ybc: float = 0.0
zb: float = 0.0
zbc: float = 0.0
zt: float = 0.0
ztc: float = 0.0
civilpy.structural.odot.box_beam.COMPOSITE_MODULAR_RATIO = 0.9

E_slab / E_beam used to compute the tabulated composite section properties (PSBD-1-25 sheet 4/6 note).

civilpy.structural.odot.box_beam.COMPOSITE_SLAB_STRUCTURAL_THICKNESS_IN = 5.0

structural thickness carried in the composite section properties, plus a non-structural monolithic wearing surface on top of it (PSBD-1-25 sheet 4/6 section-properties note).

Type:

Composite (CIP) topping

civilpy.structural.odot.box_beam.DESIGN_DATA_SHEET = 'PSBDD-1-25'

Companion design data sheet (strand tables, camber, load ratings), transcribed in civilpy.structural.odot.box_beam_design.

civilpy.structural.odot.box_beam.DESIGN_SPEC = BoxBeamDesignSpec(fc_28day_range=(5.5, 7.0), fci_release_range=(4.0, 5.0), fc_cast_in_place=4.5, fy_reinforcing=60.0, strand_grade=270, strand_diameter=0.5, strand_area_options=(0.153, 0.167))

Box-beam design/material specification (PSBD-1-25 sheet 1/6).

civilpy.structural.odot.box_beam.KEYWAY_BOTTOM_BAND_IN = 5.0

Height of the full-width band at the soffit, inches.

civilpy.structural.odot.box_beam.KEYWAY_LOWER_CHAMFER_IN = 1.25

Lower chamfer leg into the keyway recess, inches.

civilpy.structural.odot.box_beam.KEYWAY_RECESS_DEPTH_IN = 1.25

Depth of the keyway recess from the nominal face, inches.

civilpy.structural.odot.box_beam.KEYWAY_TOP_BAND_IN = 5.0

Height of the top band, inches, and how far it is set in per side.

civilpy.structural.odot.box_beam.KEYWAY_UPPER_CHAMFER_IN = 0.5

Upper chamfer leg out of the keyway recess, inches.

class civilpy.structural.odot.box_beam.LoadPlateLayout(bevel_plate: BeveledLoadPlate, bottom_face: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], top_face: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], notes: tuple[str, ...] = ())[source]

Bases: object

The generated BD-1-11 beveled load plate, sized to a bearing pad’s plan footprint (bearing_pad(name).length x .width).

top_face carries the bevel: each corner’s Z is offset by its (x, y) distance from plate center times the transverse/longitudinal bevel slope, so the plate top is a single tilted plane (not warped).

bevel_plate: BeveledLoadPlate
bottom_face: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
notes: tuple[str, ...] = ()
top_face: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
civilpy.structural.odot.box_beam.MAX_SKEW_DEG = 30.0

Maximum structure skew this standard applies to, degrees.

civilpy.structural.odot.box_beam.PSBD_2_07_SECTION_PROPERTIES: dict[int, BoxSectionProperties] = {17: BoxSectionProperties(depth=17, width=48.0, area=590.3, i=18819, yb=8.44, zt=2198, zb=2230, ic=38620, ybc=11.4, ztc=6898, zbc=3387), 21: BoxSectionProperties(depth=21, width=48.0, area=647.8, i=33884, yb=10.42, zt=3202, zb=3253, ic=62057, ybc=13.69, ztc=8489, zbc=4533), 27: BoxSectionProperties(depth=27, width=48.0, area=713.8, i=66222, yb=13.39, zt=4866, zb=4945, ic=109704, ybc=17.13, ztc=11119, zbc=6403), 33: BoxSectionProperties(depth=33, width=48.0, area=774.5, i=111342, yb=16.33, zt=6681, zb=6816, ic=173831, ybc=20.51, ztc=13922, zbc=8474), 42: BoxSectionProperties(depth=42, width=48.0, area=873.5, i=205459, yb=20.78, zt=9684, zb=9886, ic=303315, ybc=25.49, ztc=18367, zbc=11901)}

The superseded PSBD-2-07 (2007) sheet 4/4 “48 in wide box beam” table. That standard’s section is geometrically DIFFERENT from PSBD-1-25: 5 1/2 in uniform walls and a 37 in wide void. Use these when rating existing bridges built under PSBD-2-07 and earlier; the 12 in depth of that table is omitted because PSBD-1-25 dropped it.

civilpy.structural.odot.box_beam.SHEAR_KEY = ShearKeyDetail(grout_depth_from_top=5.0, composite_backer_rod_min=2.0, end_shear_key_depth=1.0, end_shear_key_width=38.0)

Shear-key detail (PSBD-1-25).

civilpy.structural.odot.box_beam.SOLID_DIAPHRAGM_BLOCK_IN = 18.0

Longitudinal length of the solid block at an intermediate diaphragm, inches, at zero skew (PSBD-1-25 sheet 4). Skewed beams widen it to X/2 + 6 where X = width * tan(theta).

civilpy.structural.odot.box_beam.SOLID_END_BLOCK_IN = 39.0

3’-3” on the 27/33/42 in beams, 2’-9” on the 17/21 in beams (PSBD-1-25 sheet 3).

Type:

Length of the solid block at each beam end, inches

class civilpy.structural.odot.box_beam.ShearKeyDetail(grout_depth_from_top: float = 5.0, composite_backer_rod_min: float = 2.0, end_shear_key_depth: float = 1.0, end_shear_key_width: float = 38.0)[source]

Bases: object

Shear-key details between adjacent box beams (PSBD-1-25 sheets 1 & 5).

composite_backer_rod_min: float = 2.0

Backer rod diameter for composite beams, inches (min).

end_shear_key_depth: float = 1.0

End shear key depth at integral/semi-integral abutments, inches.

end_shear_key_width: float = 38.0

End shear key width at integral/semi-integral abutments, inches.

grout_depth_from_top: float = 5.0

Grout fill depth from top of beam to bottom of throat, inches.

civilpy.structural.odot.box_beam.TIE_ROD = TieRodDetail(diameter=1.0, thread_root_min_diameter=0.838, torque_ft_lb=250.0, plate_washer='4 x 4 x 1/2', hole_min_diameter=2.0, hole_max_diameter=3.0, max_beams_per_rod=3)

Transverse tie rod detail (PSBD-1-25).

class civilpy.structural.odot.box_beam.TieRodDetail(diameter: float = 1.0, thread_root_min_diameter: float = 0.838, torque_ft_lb: float = 250.0, plate_washer: str = '4 x 4 x 1/2', hole_min_diameter: float = 2.0, hole_max_diameter: float = 3.0, max_beams_per_rod: int = 3)[source]

Bases: object

Transverse tie rod details (PSBD-1-25 sheets 1 & 4).

diameter: float = 1.0
hole_max_diameter: float = 3.0
hole_min_diameter: float = 2.0
max_beams_per_rod: int = 3
plate_washer: str = '4 x 4 x 1/2'
thread_root_min_diameter: float = 0.838
torque_ft_lb: float = 250.0
vertical_position(beam_depth: int) float[source]

Tie-rod height above the beam soffit, inches: 9 in for 17-27 in deep beams, 14 in for 33-42 in deep beams (sheet 4/6).

civilpy.structural.odot.box_beam.bearing_pad(name: str) BearingPad[source]

Look up a standard bearing pad by name ("B1" or "B2").

civilpy.structural.odot.box_beam.box_section_properties(depth_in: int) BoxSectionProperties[source]

Look up the 48 in wide box-beam section properties for a standard depth (17/21/27/33/42 in).

civilpy.structural.odot.box_beam.box_void_dimensions(depth_in: float, width_in: float = 48.0) tuple[float, float][source]

Void (width, height) in inches for a box beam of depth_in / width_in: BOX_WEB_THICKNESS_IN webs each side, BOX_FLANGE_THICKNESS_IN flanges top and bottom (PSBD-1-25 sheet 2/6 dimension chains).

civilpy.structural.odot.box_beam.diaphragm_count(span_ft: float) int[source]

Number of intermediate diaphragms for a span, per PSBD-1-25 sheet 4/6: 1 for spans <= 50 ft, 2 for 50 ft < span <= 75 ft, 3 for spans > 75 ft.

civilpy.structural.odot.box_beam.diaphragm_end_offset(beam_depth: int) float[source]

Distance from beam end to the end diaphragm, inches (PSBD-1-25 sheet 4/6): 24 in for 17/21 in deep beams, 30 in for 27/33/42 in deep beams.

civilpy.structural.odot.box_beam.diaphragm_stations_ft(span_ft: float, beam_depth: int) tuple[float, ...][source]

Station (ft, from the beam start) of every diaphragm, sorted: the two end diaphragms plus diaphragm_count() intermediate ones.

A 70 ft CB27-48 therefore has four – ends at 2.5 and 67.5 ft, intermediates at 24.17 and 45.83 – which is what PSBD-1-25 sheet 4/6 details and what the beam is cast solid at.

civilpy.structural.odot.box_beam.end_diaphragm_stations_ft(span_ft: float, beam_depth: int) tuple[float, float][source]

Station (ft) of the two end diaphragms, one diaphragm_end_offset() in from each beam end (PSBD-1-25 sheet 4/6). These are cast inside the solid end blocks – see solid_end_block_in() – not in the voided length.

civilpy.structural.odot.box_beam.intermediate_diaphragm_stations_ft(span_ft: float, beam_depth: int) tuple[float, ...][source]

Station (ft) of each intermediate diaphragm.

diaphragm_count() of them, dividing the length between the two end diaphragms into equal bays: one lands at midspan, two at the third points of that length, three at the quarter points. The drawing states the count and the end offset but not an explicit multi-diaphragm spacing rule; equal bays is the standard detailing assumption.

Note

This used to be folded into diaphragm_stations_ft with an k / (n - 1) interpolation, which for two diaphragms returned the two end stations and so produced no intermediate diaphragms at all – a 70 ft span came back as (2.5, 67.5). A model built on that had its tie rods buried in the end blocks and no diaphragm anywhere in the span.

civilpy.structural.odot.box_beam.layout_load_plate(bearing_pad_name: str, longitudinal_grade: float = 0.0, skew_deg: float = 0.0, plate: BeveledLoadPlate = BeveledLoadPlate(min_thickness=1.5, plate_grade='ASTM A709 Gr 50', anchor_rod_diameter=0.75, plate_washer='3 x 3 x 1/2', expansion_anchor_hole=1.25, stud_yield=50.0)) LoadPlateLayout[source]

Generate the BD-1-11 beveled load plate sized to bearing_pad_name ("B1" or "B2", bearing_pad()), tilted per load_plate_bevel(). Origin at plate-bottom center, z = 0 at the bottom face; x = bearing length (beam axis), y = bearing width.

civilpy.structural.odot.box_beam.load_plate_bevel(longitudinal_grade: float, skew_deg: float) tuple[float, float][source]

Transverse and longitudinal bevels of the BD-1-11 load plate.

The plate top is beveled to match the roadway grade resolved into the bearing’s local axes (BD-1-11 bevel notes): the component across the bearing width is grade * sin(skew) and the component along the bearing length is grade * cos(skew). longitudinal_grade is the roadway grade (rise/run, e.g. 0.04 for 4%); skew_deg is the structure skew angle in degrees. Returns (transverse, longitudinal) bevel slopes in the same rise/run units as the grade.

civilpy.structural.odot.box_beam.solid_diaphragm_block_in(skew_deg: float = 0.0, width_in: float = 48.0) float[source]

Longitudinal length of an intermediate diaphragm’s solid block.

Zero skew gives SOLID_DIAPHRAGM_BLOCK_IN; a skewed beam needs X/2 + 6 inches, X = width * tan(skew), so the block still contains the full diaphragm once it runs on the bias.

civilpy.structural.odot.box_beam.solid_end_block_in(depth_in: int) float[source]

Length of the solid end block for a beam of depth_in.

civilpy.structural.odot.box_beam_design module

Ohio DOT prestressed box beam standard designs and load ratings (PSBDD-1-25).

Design data and load ratings transcribed from the Ohio DOT Design Data Sheet PSBDD-1-25, “Prestressed Concrete Composite / Non-Composite Adjacent Box Beams” (Office of Structural Engineering, 2025-07-18, rev. 2026-01-16, 4 sheets). This is the companion to the construction-detail drawing PSBD-1-25 (see civilpy.structural.odot.box_beam).

The drawing covers two families – composite (CB, sheets 1-2) and non-composite (B, sheets 3-4) – of 48 in wide adjacent box beams at five depths (17, 21, 27, 33, 42 in). Two tables are carried here:

design (PSBDD-1-25 sheets 1 & 3)

Per box and span: strand eccentricity (beam, and for composite the composite section), number of strands and their placement (rows at 2, 4, 6 in from the bottom), stirrup-zone layout, camber at release (D0) and erection (D30), residual deflection, and the bearing pad type. The tensile-bar schedule and debonding lengths on the drawing are not carried here.

load rating (PSBDD-1-25 sheets 2 & 4)

LRFR rating factors (adjusted load factors, mainline interstate) for each box, span, and bridge width (24/28/32 ft = 6/7/8 beams), across the 16 rating vehicles tabulated on the sheet: HL-93 inventory and operating, the emergency (EV2/EV3) and specialized-hauling (SU4-SU7) vehicles, the AASHTO legal types (Type 3, 3-3, 3S2), and the Ohio permit/legal trucks (S-2F1, S-3F1, S-5C1, S-PL60T, S-PL65T).

Lengths in inches, spans in feet. The values were extracted from the drawing’s text layer and validated (strand placement sums to the strand count; operating exceeds inventory on every line); the drawing remains the controlling document.

Design assumptions (per the sheet’s design notes): AASHTO LRFD BDS 10th Ed. (2024) + ODOT BDM, HL-93, skew <= 30 deg, roadway width 24-32 ft, f’c = 7 ksi (f’ci = 5 ksi), Grade 60 reinforcing, 0.5 in 270 ksi low-relaxation strand (0.167 sq in).

civilpy.structural.odot.box_beam_design.BOX_BEAM_DESIGNS: list[BoxBeamDesign] = [BoxBeamDesign(beam_type='composite', box='CB17-48', depth=17, width=48, span=20, e_beam=5.78, e_composite=8.07, n_strands=12, strands_2in=8, strands_4in=4, strands_6in=0, stirrup_w_pairs=9, stirrup_zone_x=32.0, stirrup_y=12.0, stirrup_z=12.0, camber_d0=0.125, camber_d30=0.25, deflection=0.0, bearing_type='B1'), BoxBeamDesign(beam_type='composite', box='CB17-48', depth=17, width=48, span=25, e_beam=5.88, e_composite=8.17, n_strands=14, strands_2in=10, strands_4in=4, strands_6in=0, stirrup_w_pairs=9, stirrup_zone_x=32.0, stirrup_y=12.0, stirrup_z=12.0, camber_d0=0.25, camber_d30=0.375, deflection=0.0, bearing_type='B1'), BoxBeamDesign(beam_type='composite', box='CB17-48', depth=17, width=48, span=30, e_beam=5.45, e_composite=7.74, n_strands=16, strands_2in=10, strands_4in=6, strands_6in=0, stirrup_w_pairs=9, stirrup_zone_x=32.0, stirrup_y=12.0, stirrup_z=12.0, camber_d0=0.5, camber_d30=0.875, deflection=0.125, bearing_type='B1'), BoxBeamDesign(beam_type='composite', box='CB17-48', depth=17, width=48, span=35, e_beam=5.78, e_composite=8.07, n_strands=18, strands_2in=12, strands_4in=6, strands_6in=0, stirrup_w_pairs=9, stirrup_zone_x=32.0, stirrup_y=12.0, stirrup_z=12.0, camber_d0=0.625, camber_d30=1.0, deflection=0.125, bearing_type='B1'), BoxBeamDesign(beam_type='composite', box='CB17-48', depth=17, width=48, span=40, e_beam=5.54, e_composite=7.83, n_strands=22, strands_2in=12, strands_4in=10, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=12.0, stirrup_z=12.0, camber_d0=0.875, camber_d30=1.5, deflection=0.25, bearing_type='B1'), BoxBeamDesign(beam_type='composite', box='CB17-48', depth=17, width=48, span=45, e_beam=5.45, e_composite=7.74, n_strands=24, strands_2in=12, strands_4in=12, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=12.0, stirrup_z=12.0, camber_d0=1.125, camber_d30=1.875, deflection=0.375, bearing_type='B1'), BoxBeamDesign(beam_type='composite', box='CB21-48', depth=21, width=48, span=30, e_beam=7.67, e_composite=10.94, n_strands=16, strands_2in=10, strands_4in=6, strands_6in=0, stirrup_w_pairs=9, stirrup_zone_x=32.0, stirrup_y=12.0, stirrup_z=12.0, camber_d0=0.375, camber_d30=0.625, deflection=0.125, bearing_type='B1'), BoxBeamDesign(beam_type='composite', box='CB21-48', depth=21, width=48, span=35, e_beam=7.53, e_composite=10.8, n_strands=18, strands_2in=10, strands_4in=8, strands_6in=0, stirrup_w_pairs=9, stirrup_zone_x=32.0, stirrup_y=12.0, stirrup_z=12.0, camber_d0=0.5, camber_d30=0.875, deflection=0.125, bearing_type='B1'), BoxBeamDesign(beam_type='composite', box='CB21-48', depth=21, width=48, span=40, e_beam=7.75, e_composite=11.02, n_strands=18, strands_2in=12, strands_4in=6, strands_6in=0, stirrup_w_pairs=9, stirrup_zone_x=32.0, stirrup_y=12.0, stirrup_z=12.0, camber_d0=0.5, camber_d30=0.875, deflection=0.125, bearing_type='B1'), BoxBeamDesign(beam_type='composite', box='CB21-48', depth=21, width=48, span=45, e_beam=7.75, e_composite=11.02, n_strands=18, strands_2in=12, strands_4in=6, strands_6in=0, stirrup_w_pairs=9, stirrup_zone_x=32.0, stirrup_y=12.0, stirrup_z=12.0, camber_d0=0.625, camber_d30=1.0, deflection=0.25, bearing_type='B1'), BoxBeamDesign(beam_type='composite', box='CB21-48', depth=21, width=48, span=50, e_beam=7.69, e_composite=10.96, n_strands=22, strands_2in=14, strands_4in=8, strands_6in=0, stirrup_w_pairs=9, stirrup_zone_x=32.0, stirrup_y=12.0, stirrup_z=12.0, camber_d0=1.375, camber_d30=2.375, deflection=0.5, bearing_type='B1'), BoxBeamDesign(beam_type='composite', box='CB21-48', depth=21, width=48, span=55, e_beam=7.65, e_composite=10.92, n_strands=26, strands_2in=16, strands_4in=10, strands_6in=0, stirrup_w_pairs=9, stirrup_zone_x=32.0, stirrup_y=12.0, stirrup_z=12.0, camber_d0=1.375, camber_d30=2.375, deflection=0.5, bearing_type='B2'), BoxBeamDesign(beam_type='composite', box='CB21-48', depth=21, width=48, span=60, e_beam=7.49, e_composite=10.76, n_strands=30, strands_2in=16, strands_4in=14, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=12.0, stirrup_z=12.0, camber_d0=1.75, camber_d30=3.0, deflection=0.75, bearing_type='B2'), BoxBeamDesign(beam_type='composite', box='CB27-48', depth=27, width=48, span=40, e_beam=10.88, e_composite=14.61, n_strands=16, strands_2in=12, strands_4in=4, strands_6in=0, stirrup_w_pairs=9, stirrup_zone_x=32.0, stirrup_y=9.0, stirrup_z=18.0, camber_d0=0.375, camber_d30=0.625, deflection=0.125, bearing_type='B1'), BoxBeamDesign(beam_type='composite', box='CB27-48', depth=27, width=48, span=45, e_beam=10.88, e_composite=14.61, n_strands=16, strands_2in=12, strands_4in=4, strands_6in=0, stirrup_w_pairs=9, stirrup_zone_x=32.0, stirrup_y=9.0, stirrup_z=18.0, camber_d0=0.5, camber_d30=0.875, deflection=0.125, bearing_type='B1'), BoxBeamDesign(beam_type='composite', box='CB27-48', depth=27, width=48, span=50, e_beam=10.71, e_composite=14.44, n_strands=18, strands_2in=12, strands_4in=6, strands_6in=0, stirrup_w_pairs=9, stirrup_zone_x=32.0, stirrup_y=9.0, stirrup_z=18.0, camber_d0=0.625, camber_d30=1.0, deflection=0.25, bearing_type='B1'), BoxBeamDesign(beam_type='composite', box='CB27-48', depth=27, width=48, span=55, e_beam=10.78, e_composite=14.51, n_strands=20, strands_2in=14, strands_4in=6, strands_6in=0, stirrup_w_pairs=9, stirrup_zone_x=32.0, stirrup_y=9.0, stirrup_z=18.0, camber_d0=0.75, camber_d30=1.25, deflection=0.25, bearing_type='B2'), BoxBeamDesign(beam_type='composite', box='CB27-48', depth=27, width=48, span=60, e_beam=10.83, e_composite=14.56, n_strands=24, strands_2in=16, strands_4in=8, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=9.0, stirrup_z=18.0, camber_d0=1.125, camber_d30=1.875, deflection=0.375, bearing_type='B2'), BoxBeamDesign(beam_type='composite', box='CB27-48', depth=27, width=48, span=65, e_beam=10.52, e_composite=14.25, n_strands=28, strands_2in=16, strands_4in=12, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=9.0, stirrup_z=18.0, camber_d0=1.375, camber_d30=2.375, deflection=0.625, bearing_type='B2'), BoxBeamDesign(beam_type='composite', box='CB27-48', depth=27, width=48, span=70, e_beam=10.38, e_composite=14.11, n_strands=32, strands_2in=16, strands_4in=16, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=9.0, stirrup_z=18.0, camber_d0=1.75, camber_d30=3.0, deflection=0.75, bearing_type='B2'), BoxBeamDesign(beam_type='composite', box='CB33-48', depth=33, width=48, span=50, e_beam=13.73, e_composite=17.99, n_strands=14, strands_2in=10, strands_4in=4, strands_6in=0, stirrup_w_pairs=9, stirrup_zone_x=32.0, stirrup_y=9.0, stirrup_z=18.0, camber_d0=0.375, camber_d30=0.625, deflection=0.125, bearing_type='B2'), BoxBeamDesign(beam_type='composite', box='CB33-48', depth=33, width=48, span=55, e_beam=13.55, e_composite=17.81, n_strands=16, strands_2in=10, strands_4in=6, strands_6in=0, stirrup_w_pairs=9, stirrup_zone_x=32.0, stirrup_y=9.0, stirrup_z=18.0, camber_d0=0.5, camber_d30=0.875, deflection=0.25, bearing_type='B2'), BoxBeamDesign(beam_type='composite', box='CB33-48', depth=33, width=48, span=60, e_beam=13.63, e_composite=17.89, n_strands=18, strands_2in=12, strands_4in=6, strands_6in=0, stirrup_w_pairs=9, stirrup_zone_x=32.0, stirrup_y=9.0, stirrup_z=18.0, camber_d0=0.625, camber_d30=1.0, deflection=0.25, bearing_type='B2'), BoxBeamDesign(beam_type='composite', box='CB33-48', depth=33, width=48, span=65, e_beam=13.57, e_composite=17.83, n_strands=22, strands_2in=14, strands_4in=8, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=9.0, stirrup_z=18.0, camber_d0=0.875, camber_d30=1.5, deflection=0.375, bearing_type='B2'), BoxBeamDesign(beam_type='composite', box='CB33-48', depth=33, width=48, span=70, e_beam=13.38, e_composite=17.64, n_strands=26, strands_2in=14, strands_4in=12, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=9.0, stirrup_z=18.0, camber_d0=1.125, camber_d30=1.875, deflection=0.5, bearing_type='B2'), BoxBeamDesign(beam_type='composite', box='CB33-48', depth=33, width=48, span=75, e_beam=13.37, e_composite=17.63, n_strands=30, strands_2in=16, strands_4in=14, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=9.0, stirrup_z=18.0, camber_d0=1.5, camber_d30=2.5, deflection=0.625, bearing_type='B2'), BoxBeamDesign(beam_type='composite', box='CB33-48', depth=33, width=48, span=80, e_beam=13.24, e_composite=17.5, n_strands=34, strands_2in=16, strands_4in=18, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=9.0, stirrup_z=18.0, camber_d0=1.75, camber_d30=3.0, deflection=0.875, bearing_type='B2'), BoxBeamDesign(beam_type='composite', box='CB33-48', depth=33, width=48, span=85, e_beam=13.08, e_composite=17.34, n_strands=36, strands_2in=16, strands_4in=18, strands_6in=2, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=9.0, stirrup_z=18.0, camber_d0=2.0, camber_d30=3.375, deflection=1.125, bearing_type='B2'), BoxBeamDesign(beam_type='composite', box='CB42-48', depth=42, width=48, span=65, e_beam=18.32, e_composite=23.05, n_strands=16, strands_2in=12, strands_4in=4, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=9.0, stirrup_z=18.0, camber_d0=0.375, camber_d30=0.625, deflection=0.25, bearing_type='B2'), BoxBeamDesign(beam_type='composite', box='CB42-48', depth=42, width=48, span=70, e_beam=18.22, e_composite=22.95, n_strands=20, strands_2in=14, strands_4in=6, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=9.0, stirrup_z=18.0, camber_d0=0.625, camber_d30=1.0, deflection=0.25, bearing_type='B2'), BoxBeamDesign(beam_type='composite', box='CB42-48', depth=42, width=48, span=75, e_beam=18.09, e_composite=22.82, n_strands=22, strands_2in=14, strands_4in=8, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=9.0, stirrup_z=18.0, camber_d0=0.75, camber_d30=1.25, deflection=0.375, bearing_type='B2'), BoxBeamDesign(beam_type='composite', box='CB42-48', depth=42, width=48, span=80, e_beam=17.82, e_composite=22.55, n_strands=28, strands_2in=14, strands_4in=14, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=9.0, stirrup_z=18.0, camber_d0=1.125, camber_d30=1.875, deflection=0.5, bearing_type='B2'), BoxBeamDesign(beam_type='composite', box='CB42-48', depth=42, width=48, span=85, e_beam=17.82, e_composite=22.55, n_strands=32, strands_2in=16, strands_4in=16, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=9.0, stirrup_z=18.0, camber_d0=1.375, camber_d30=2.375, deflection=0.625, bearing_type='B2'), BoxBeamDesign(beam_type='composite', box='CB42-48', depth=42, width=48, span=90, e_beam=17.76, e_composite=22.49, n_strands=34, strands_2in=16, strands_4in=18, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=9.0, stirrup_z=18.0, camber_d0=1.625, camber_d30=2.75, deflection=0.75, bearing_type='B2'), BoxBeamDesign(beam_type='composite', box='CB42-48', depth=42, width=48, span=95, e_beam=17.6, e_composite=22.33, n_strands=36, strands_2in=16, strands_4in=18, strands_6in=2, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=9.0, stirrup_z=18.0, camber_d0=1.75, camber_d30=3.0, deflection=1.0, bearing_type='B2'), BoxBeamDesign(beam_type='non_composite', box='B17-48', depth=17, width=48, span=20, e_beam=6.45, e_composite=None, n_strands=12, strands_2in=12, strands_4in=0, strands_6in=0, stirrup_w_pairs=9, stirrup_zone_x=32.0, stirrup_y=10.0, stirrup_z=10.0, camber_d0=0.25, camber_d30=0.375, deflection=0.0, bearing_type='B1'), BoxBeamDesign(beam_type='non_composite', box='B17-48', depth=17, width=48, span=25, e_beam=6.45, e_composite=None, n_strands=14, strands_2in=14, strands_4in=0, strands_6in=0, stirrup_w_pairs=9, stirrup_zone_x=32.0, stirrup_y=10.0, stirrup_z=10.0, camber_d0=0.375, camber_d30=0.625, deflection=0.0, bearing_type='B1'), BoxBeamDesign(beam_type='non_composite', box='B17-48', depth=17, width=48, span=30, e_beam=5.85, e_composite=None, n_strands=20, strands_2in=14, strands_4in=6, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=10.0, stirrup_z=10.0, camber_d0=0.625, camber_d30=1.0, deflection=0.0, bearing_type='B1'), BoxBeamDesign(beam_type='non_composite', box='B17-48', depth=17, width=48, span=35, e_beam=6.05, e_composite=None, n_strands=20, strands_2in=16, strands_4in=4, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=10.0, stirrup_z=10.0, camber_d0=0.75, camber_d30=1.25, deflection=0.125, bearing_type='B1'), BoxBeamDesign(beam_type='non_composite', box='B21-48', depth=21, width=48, span=30, e_beam=7.62, e_composite=None, n_strands=16, strands_2in=12, strands_4in=4, strands_6in=0, stirrup_w_pairs=9, stirrup_zone_x=32.0, stirrup_y=12.0, stirrup_z=12.0, camber_d0=0.375, camber_d30=0.625, deflection=0.0, bearing_type='B1'), BoxBeamDesign(beam_type='non_composite', box='B21-48', depth=21, width=48, span=35, e_beam=7.98, e_composite=None, n_strands=18, strands_2in=14, strands_4in=4, strands_6in=0, stirrup_w_pairs=9, stirrup_zone_x=32.0, stirrup_y=12.0, stirrup_z=12.0, camber_d0=0.625, camber_d30=1.0, deflection=0.125, bearing_type='B1'), BoxBeamDesign(beam_type='non_composite', box='B21-48', depth=21, width=48, span=40, e_beam=7.98, e_composite=None, n_strands=18, strands_2in=14, strands_4in=4, strands_6in=0, stirrup_w_pairs=9, stirrup_zone_x=32.0, stirrup_y=12.0, stirrup_z=12.0, camber_d0=0.625, camber_d30=1.0, deflection=0.125, bearing_type='B1'), BoxBeamDesign(beam_type='non_composite', box='B21-48', depth=21, width=48, span=45, e_beam=7.82, e_composite=None, n_strands=22, strands_2in=14, strands_4in=8, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=12.0, stirrup_z=12.0, camber_d0=0.875, camber_d30=1.5, deflection=0.125, bearing_type='B1'), BoxBeamDesign(beam_type='non_composite', box='B21-48', depth=21, width=48, span=50, e_beam=7.87, e_composite=None, n_strands=22, strands_2in=16, strands_4in=6, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=12.0, stirrup_z=12.0, camber_d0=1.0, camber_d30=1.75, deflection=0.25, bearing_type='B2'), BoxBeamDesign(beam_type='non_composite', box='B27-48', depth=27, width=48, span=40, e_beam=10.49, e_composite=None, n_strands=14, strands_2in=10, strands_4in=4, strands_6in=0, stirrup_w_pairs=9, stirrup_zone_x=32.0, stirrup_y=12.0, stirrup_z=12.0, camber_d0=0.5, camber_d30=0.875, deflection=0.0, bearing_type='B1'), BoxBeamDesign(beam_type='non_composite', box='B27-48', depth=27, width=48, span=45, e_beam=10.88, e_composite=None, n_strands=16, strands_2in=12, strands_4in=4, strands_6in=0, stirrup_w_pairs=9, stirrup_zone_x=32.0, stirrup_y=12.0, stirrup_z=12.0, camber_d0=0.5, camber_d30=0.875, deflection=0.125, bearing_type='B1'), BoxBeamDesign(beam_type='non_composite', box='B27-48', depth=27, width=48, span=50, e_beam=10.71, e_composite=None, n_strands=18, strands_2in=12, strands_4in=6, strands_6in=0, stirrup_w_pairs=9, stirrup_zone_x=32.0, stirrup_y=12.0, stirrup_z=12.0, camber_d0=0.625, camber_d30=1.0, deflection=0.125, bearing_type='B1'), BoxBeamDesign(beam_type='non_composite', box='B27-48', depth=27, width=48, span=55, e_beam=10.78, e_composite=None, n_strands=20, strands_2in=14, strands_4in=6, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=12.0, stirrup_z=12.0, camber_d0=0.625, camber_d30=1.0, deflection=0.25, bearing_type='B2'), BoxBeamDesign(beam_type='non_composite', box='B27-48', depth=27, width=48, span=60, e_beam=10.71, e_composite=None, n_strands=24, strands_2in=16, strands_4in=8, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=12.0, stirrup_z=12.0, camber_d0=1.125, camber_d30=1.875, deflection=0.375, bearing_type='B2'), BoxBeamDesign(beam_type='non_composite', box='B27-48', depth=27, width=48, span=65, e_beam=10.45, e_composite=None, n_strands=30, strands_2in=16, strands_4in=14, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=12.0, stirrup_z=12.0, camber_d0=1.5, camber_d30=2.5, deflection=0.5, bearing_type='B2'), BoxBeamDesign(beam_type='non_composite', box='B33-48', depth=33, width=48, span=50, e_beam=13.73, e_composite=None, n_strands=14, strands_2in=10, strands_4in=4, strands_6in=0, stirrup_w_pairs=9, stirrup_zone_x=32.0, stirrup_y=12.0, stirrup_z=18.0, camber_d0=0.375, camber_d30=0.625, deflection=0.125, bearing_type='B1'), BoxBeamDesign(beam_type='non_composite', box='B33-48', depth=33, width=48, span=55, e_beam=13.55, e_composite=None, n_strands=16, strands_2in=10, strands_4in=6, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=12.0, stirrup_z=18.0, camber_d0=0.5, camber_d30=0.875, deflection=0.125, bearing_type='B2'), BoxBeamDesign(beam_type='non_composite', box='B33-48', depth=33, width=48, span=60, e_beam=13.39, e_composite=None, n_strands=22, strands_2in=12, strands_4in=10, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=12.0, stirrup_z=18.0, camber_d0=0.75, camber_d30=1.25, deflection=0.25, bearing_type='B2'), BoxBeamDesign(beam_type='non_composite', box='B33-48', depth=33, width=48, span=65, e_beam=13.57, e_composite=None, n_strands=22, strands_2in=14, strands_4in=8, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=12.0, stirrup_z=18.0, camber_d0=0.875, camber_d30=1.5, deflection=0.25, bearing_type='B2'), BoxBeamDesign(beam_type='non_composite', box='B33-48', depth=33, width=48, span=70, e_beam=13.53, e_composite=None, n_strands=26, strands_2in=16, strands_4in=10, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=12.0, stirrup_z=18.0, camber_d0=1.125, camber_d30=1.875, deflection=0.375, bearing_type='B2'), BoxBeamDesign(beam_type='non_composite', box='B33-48', depth=33, width=48, span=75, e_beam=13.37, e_composite=None, n_strands=30, strands_2in=16, strands_4in=14, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=12.0, stirrup_z=18.0, camber_d0=1.5, camber_d30=2.5, deflection=0.5, bearing_type='B2'), BoxBeamDesign(beam_type='non_composite', box='B33-48', depth=33, width=48, span=80, e_beam=13.24, e_composite=None, n_strands=34, strands_2in=16, strands_4in=18, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=12.0, stirrup_z=18.0, camber_d0=1.875, camber_d30=3.125, deflection=0.625, bearing_type='B2'), BoxBeamDesign(beam_type='non_composite', box='B42-48', depth=42, width=48, span=65, e_beam=18.15, e_composite=None, n_strands=18, strands_2in=12, strands_4in=6, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=12.0, stirrup_z=18.0, camber_d0=0.5, camber_d30=0.875, deflection=0.125, bearing_type='B2'), BoxBeamDesign(beam_type='non_composite', box='B42-48', depth=42, width=48, span=70, e_beam=18.22, e_composite=None, n_strands=20, strands_2in=14, strands_4in=6, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=12.0, stirrup_z=18.0, camber_d0=0.625, camber_d30=1.0, deflection=0.25, bearing_type='B2'), BoxBeamDesign(beam_type='non_composite', box='B42-48', depth=42, width=48, span=75, e_beam=18.09, e_composite=None, n_strands=22, strands_2in=14, strands_4in=8, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=12.0, stirrup_z=18.0, camber_d0=0.75, camber_d30=1.25, deflection=0.25, bearing_type='B2'), BoxBeamDesign(beam_type='non_composite', box='B42-48', depth=42, width=48, span=80, e_beam=17.9, e_composite=None, n_strands=26, strands_2in=14, strands_4in=12, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=12.0, stirrup_z=18.0, camber_d0=1.0, camber_d30=1.75, deflection=0.375, bearing_type='B2'), BoxBeamDesign(beam_type='non_composite', box='B42-48', depth=42, width=48, span=85, e_beam=17.89, e_composite=None, n_strands=30, strands_2in=16, strands_4in=14, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=12.0, stirrup_z=18.0, camber_d0=1.25, camber_d30=2.125, deflection=0.5, bearing_type='B2'), BoxBeamDesign(beam_type='non_composite', box='B42-48', depth=42, width=48, span=90, e_beam=17.76, e_composite=None, n_strands=34, strands_2in=16, strands_4in=18, strands_6in=0, stirrup_w_pairs=16, stirrup_zone_x=60.0, stirrup_y=12.0, stirrup_z=18.0, camber_d0=1.625, camber_d30=2.75, deflection=0.625, bearing_type='B2')]

All standard box-beam designs (PSBDD-1-25 sheets 1 & 3).

civilpy.structural.odot.box_beam_design.BOX_BEAM_RATINGS: list[BoxBeamRating] = [BoxBeamRating(beam_type='composite', box='CB17-48', width_ft=24, n_beams=6, span=20, rating_factors={'inv': 2.3, 'op': 2.98, 'ev2': 3.78, 'ev3': 2.94, 's2f1': 5.57, 's3f1': 4.23, 's5c1': 4.44, 'spl60t': 4.18, 'spl65t': 3.91, 'su4': 3.92, 'su5': 3.7, 'su6': 3.7, 'su7': 3.7, 'type3': 4.44, 'type33': 5.4, 'type3s2': 4.76}), BoxBeamRating(beam_type='composite', box='CB17-48', width_ft=28, n_beams=7, span=20, rating_factors={'inv': 2.3, 'op': 2.98, 'ev2': 3.78, 'ev3': 2.95, 's2f1': 5.57, 's3f1': 4.23, 's5c1': 4.44, 'spl60t': 4.18, 'spl65t': 3.91, 'su4': 3.92, 'su5': 3.7, 'su6': 3.7, 'su7': 3.7, 'type3': 4.44, 'type33': 5.4, 'type3s2': 4.77}), BoxBeamRating(beam_type='composite', box='CB17-48', width_ft=24, n_beams=6, span=25, rating_factors={'inv': 2.06, 'op': 2.67, 'ev2': 3.14, 'ev3': 2.63, 's2f1': 4.95, 's3f1': 3.62, 's5c1': 3.75, 'spl60t': 3.59, 'spl65t': 3.33, 'su4': 3.38, 'su5': 3.21, 'su6': 3.24, 'su7': 3.24, 'type3': 3.94, 'type33': 4.91, 'type3s2': 4.07}), BoxBeamRating(beam_type='composite', box='CB17-48', width_ft=28, n_beams=7, span=25, rating_factors={'inv': 2.06, 'op': 2.67, 'ev2': 3.14, 'ev3': 2.63, 's2f1': 4.96, 's3f1': 3.62, 's5c1': 3.75, 'spl60t': 3.6, 'spl65t': 3.33, 'su4': 3.38, 'su5': 3.21, 'su6': 3.24, 'su7': 3.24, 'type3': 3.95, 'type33': 4.92, 'type3s2': 4.08}), BoxBeamRating(beam_type='composite', box='CB17-48', width_ft=24, n_beams=6, span=30, rating_factors={'inv': 1.94, 'op': 2.51, 'ev2': 2.84, 'ev3': 2.36, 's2f1': 4.67, 's3f1': 3.34, 's5c1': 3.43, 'spl60t': 3.31, 'spl65t': 3.0, 'su4': 3.06, 'su5': 2.91, 'su6': 2.96, 'su7': 2.96, 'type3': 3.5, 'type33': 4.26, 'type3s2': 3.75}), BoxBeamRating(beam_type='composite', box='CB17-48', width_ft=28, n_beams=7, span=30, rating_factors={'inv': 1.94, 'op': 2.51, 'ev2': 2.84, 'ev3': 2.36, 's2f1': 4.67, 's3f1': 3.34, 's5c1': 3.43, 'spl60t': 3.31, 'spl65t': 3.0, 'su4': 3.06, 'su5': 2.91, 'su6': 2.96, 'su7': 2.96, 'type3': 3.5, 'type33': 4.26, 'type3s2': 3.75}), BoxBeamRating(beam_type='composite', box='CB17-48', width_ft=24, n_beams=6, span=35, rating_factors={'inv': 1.56, 'op': 2.02, 'ev2': 2.38, 'ev3': 1.96, 's2f1': 4.08, 's3f1': 2.84, 's5c1': 2.9, 'spl60t': 2.81, 'spl65t': 2.5, 'su4': 2.55, 'su5': 2.36, 'su6': 2.36, 'su7': 2.36, 'type3': 2.87, 'type33': 3.42, 'type3s2': 3.2}), BoxBeamRating(beam_type='composite', box='CB17-48', width_ft=28, n_beams=7, span=35, rating_factors={'inv': 1.56, 'op': 2.02, 'ev2': 2.38, 'ev3': 1.96, 's2f1': 4.08, 's3f1': 2.85, 's5c1': 2.9, 'spl60t': 2.81, 'spl65t': 2.5, 'su4': 2.55, 'su5': 2.36, 'su6': 2.36, 'su7': 2.36, 'type3': 2.87, 'type33': 3.42, 'type3s2': 3.2}), BoxBeamRating(beam_type='composite', box='CB17-48', width_ft=24, n_beams=6, span=40, rating_factors={'inv': 1.65, 'op': 2.14, 'ev2': 2.53, 'ev3': 2.08, 's2f1': 4.35, 's3f1': 3.03, 's5c1': 3.09, 'spl60t': 2.97, 'spl65t': 2.64, 'su4': 2.71, 'su5': 2.51, 'su6': 2.5, 'su7': 2.54, 'type3': 3.05, 'type33': 3.63, 'type3s2': 3.4}), BoxBeamRating(beam_type='composite', box='CB17-48', width_ft=28, n_beams=7, span=40, rating_factors={'inv': 1.65, 'op': 2.14, 'ev2': 2.53, 'ev3': 2.08, 's2f1': 4.36, 's3f1': 3.03, 's5c1': 3.09, 'spl60t': 2.97, 'spl65t': 2.65, 'su4': 2.71, 'su5': 2.51, 'su6': 2.5, 'su7': 2.54, 'type3': 3.05, 'type33': 3.63, 'type3s2': 3.41}), BoxBeamRating(beam_type='composite', box='CB17-48', width_ft=24, n_beams=6, span=45, rating_factors={'inv': 1.51, 'op': 1.99, 'ev2': 2.42, 'ev3': 1.99, 's2f1': 4.23, 's3f1': 2.92, 's5c1': 2.97, 'spl60t': 2.72, 'spl65t': 2.42, 'su4': 2.6, 'su5': 2.38, 'su6': 2.33, 'su7': 2.32, 'type3': 2.9, 'type33': 3.4, 'type3s2': 3.18}), BoxBeamRating(beam_type='composite', box='CB17-48', width_ft=28, n_beams=7, span=45, rating_factors={'inv': 1.54, 'op': 2.0, 'ev2': 2.42, 'ev3': 1.99, 's2f1': 4.23, 's3f1': 2.92, 's5c1': 2.97, 'spl60t': 2.72, 'spl65t': 2.42, 'su4': 2.6, 'su5': 2.38, 'su6': 2.34, 'su7': 2.32, 'type3': 2.9, 'type33': 3.4, 'type3s2': 3.18}), BoxBeamRating(beam_type='composite', box='CB21-48', width_ft=24, n_beams=6, span=30, rating_factors={'inv': 1.94, 'op': 2.51, 'ev2': 2.84, 'ev3': 2.36, 's2f1': 4.67, 's3f1': 3.34, 's5c1': 3.43, 'spl60t': 3.31, 'spl65t': 3.0, 'su4': 3.06, 'su5': 2.91, 'su6': 2.96, 'su7': 2.96, 'type3': 3.5, 'type33': 4.26, 'type3s2': 3.75}), BoxBeamRating(beam_type='composite', box='CB21-48', width_ft=28, n_beams=7, span=30, rating_factors={'inv': 1.94, 'op': 2.51, 'ev2': 2.84, 'ev3': 2.36, 's2f1': 4.67, 's3f1': 3.34, 's5c1': 3.43, 'spl60t': 3.31, 'spl65t': 3.0, 'su4': 3.06, 'su5': 2.91, 'su6': 2.96, 'su7': 2.96, 'type3': 3.5, 'type33': 4.26, 'type3s2': 3.75}), BoxBeamRating(beam_type='composite', box='CB21-48', width_ft=24, n_beams=6, span=35, rating_factors={'inv': 2.07, 'op': 2.68, 'ev2': 3.15, 'ev3': 2.6, 's2f1': 5.41, 's3f1': 3.77, 's5c1': 3.85, 'spl60t': 3.72, 'spl65t': 3.32, 'su4': 3.38, 'su5': 3.13, 'su6': 3.13, 'su7': 3.13, 'type3': 3.8, 'type33': 4.53, 'type3s2': 4.24}), BoxBeamRating(beam_type='composite', box='CB21-48', width_ft=28, n_beams=7, span=35, rating_factors={'inv': 2.07, 'op': 2.68, 'ev2': 3.15, 'ev3': 2.6, 's2f1': 5.42, 's3f1': 3.77, 's5c1': 3.85, 'spl60t': 3.72, 'spl65t': 3.32, 'su4': 3.38, 'su5': 3.13, 'su6': 3.13, 'su7': 3.13, 'type3': 3.8, 'type33': 4.53, 'type3s2': 4.24}), BoxBeamRating(beam_type='composite', box='CB21-48', width_ft=24, n_beams=6, span=40, rating_factors={'inv': 1.69, 'op': 2.19, 'ev2': 2.67, 'ev3': 2.19, 's2f1': 4.65, 's3f1': 3.21, 's5c1': 3.26, 'spl60t': 3.14, 'spl65t': 2.79, 'su4': 2.86, 'su5': 2.62, 'su6': 2.57, 'su7': 2.55, 'type3': 3.19, 'type33': 3.74, 'type3s2': 3.5}), BoxBeamRating(beam_type='composite', box='CB21-48', width_ft=28, n_beams=7, span=40, rating_factors={'inv': 1.69, 'op': 2.19, 'ev2': 2.67, 'ev3': 2.19, 's2f1': 4.65, 's3f1': 3.21, 's5c1': 3.27, 'spl60t': 3.14, 'spl65t': 2.79, 'su4': 2.86, 'su5': 2.62, 'su6': 2.57, 'su7': 2.55, 'type3': 3.19, 'type33': 3.74, 'type3s2': 3.5}), BoxBeamRating(beam_type='composite', box='CB21-48', width_ft=24, n_beams=6, span=45, rating_factors={'inv': 1.57, 'op': 2.03, 'ev2': 2.53, 'ev3': 2.08, 's2f1': 4.47, 's3f1': 3.07, 's5c1': 3.11, 'spl60t': 2.85, 'spl65t': 2.37, 'su4': 2.71, 'su5': 2.47, 'su6': 2.39, 'su7': 2.34, 'type3': 3.02, 'type33': 3.35, 'type3s2': 3.15}), BoxBeamRating(beam_type='composite', box='CB21-48', width_ft=28, n_beams=7, span=45, rating_factors={'inv': 1.57, 'op': 2.03, 'ev2': 2.54, 'ev3': 2.08, 's2f1': 4.48, 's3f1': 3.07, 's5c1': 3.11, 'spl60t': 2.85, 'spl65t': 2.37, 'su4': 2.71, 'su5': 2.47, 'su6': 2.39, 'su7': 2.34, 'type3': 3.02, 'type33': 3.35, 'type3s2': 3.16}), BoxBeamRating(beam_type='composite', box='CB21-48', width_ft=24, n_beams=6, span=50, rating_factors={'inv': 1.44, 'op': 1.87, 'ev2': 2.4, 'ev3': 1.96, 's2f1': 4.27, 's3f1': 2.91, 's5c1': 2.95, 'spl60t': 2.68, 'spl65t': 2.07, 'su4': 2.56, 'su5': 2.32, 'su6': 2.22, 'su7': 2.14, 'type3': 2.84, 'type33': 2.95, 'type3s2': 2.79}), BoxBeamRating(beam_type='composite', box='CB21-48', width_ft=28, n_beams=7, span=50, rating_factors={'inv': 1.45, 'op': 1.88, 'ev2': 2.4, 'ev3': 1.96, 's2f1': 4.27, 's3f1': 2.91, 's5c1': 2.95, 'spl60t': 2.69, 'spl65t': 2.07, 'su4': 2.57, 'su5': 2.33, 'su6': 2.22, 'su7': 2.15, 'type3': 2.85, 'type33': 2.96, 'type3s2': 2.8}), BoxBeamRating(beam_type='composite', box='CB21-48', width_ft=24, n_beams=6, span=55, rating_factors={'inv': 1.31, 'op': 1.69, 'ev2': 2.22, 'ev3': 1.81, 's2f1': 3.98, 's3f1': 2.7, 's5c1': 2.67, 'spl60t': 2.45, 'spl65t': 1.8, 'su4': 2.37, 'su5': 2.14, 'su6': 2.03, 'su7': 1.94, 'type3': 2.62, 'type33': 2.6, 'type3s2': 2.45}), BoxBeamRating(beam_type='composite', box='CB21-48', width_ft=28, n_beams=7, span=55, rating_factors={'inv': 1.3, 'op': 1.69, 'ev2': 2.21, 'ev3': 1.8, 's2f1': 3.97, 's3f1': 2.69, 's5c1': 2.66, 'spl60t': 2.44, 'spl65t': 1.79, 'su4': 2.36, 'su5': 2.13, 'su6': 2.02, 'su7': 1.93, 'type3': 2.61, 'type33': 2.59, 'type3s2': 2.44}), BoxBeamRating(beam_type='composite', box='CB21-48', width_ft=24, n_beams=6, span=60, rating_factors={'inv': 1.32, 'op': 1.71, 'ev2': 2.26, 'ev3': 1.84, 's2f1': 4.07, 's3f1': 2.75, 's5c1': 2.63, 'spl60t': 2.4, 'spl65t': 1.77, 'su4': 2.41, 'su5': 2.17, 'su6': 2.05, 'su7': 1.95, 'type3': 2.66, 'type33': 2.59, 'type3s2': 2.45}), BoxBeamRating(beam_type='composite', box='CB21-48', width_ft=28, n_beams=7, span=60, rating_factors={'inv': 1.32, 'op': 1.71, 'ev2': 2.26, 'ev3': 1.84, 's2f1': 4.07, 's3f1': 2.76, 's5c1': 2.64, 'spl60t': 2.21, 'spl65t': 1.78, 'su4': 2.41, 'su5': 2.17, 'su6': 2.05, 'su7': 1.96, 'type3': 2.66, 'type33': 2.59, 'type3s2': 2.45}), BoxBeamRating(beam_type='composite', box='CB27-48', width_ft=24, n_beams=6, span=40, rating_factors={'inv': 2.2, 'op': 2.85, 'ev2': 3.47, 'ev3': 2.85, 's2f1': 6.05, 's3f1': 4.17, 's5c1': 4.24, 'spl60t': 4.08, 'spl65t': 3.63, 'su4': 3.71, 'su5': 3.41, 'su6': 3.34, 'su7': 3.32, 'type3': 4.15, 'type33': 4.86, 'type3s2': 4.55}), BoxBeamRating(beam_type='composite', box='CB27-48', width_ft=28, n_beams=7, span=40, rating_factors={'inv': 2.2, 'op': 2.85, 'ev2': 3.47, 'ev3': 2.85, 's2f1': 6.05, 's3f1': 4.18, 's5c1': 4.25, 'spl60t': 4.08, 'spl65t': 3.63, 'su4': 3.71, 'su5': 3.41, 'su6': 3.34, 'su7': 3.32, 'type3': 4.15, 'type33': 4.86, 'type3s2': 4.55}), BoxBeamRating(beam_type='composite', box='CB27-48', width_ft=24, n_beams=6, span=45, rating_factors={'inv': 1.79, 'op': 2.32, 'ev2': 2.9, 'ev3': 2.38, 's2f1': 5.12, 's3f1': 3.51, 's5c1': 3.56, 'spl60t': 3.26, 'spl65t': 2.71, 'su4': 3.11, 'su5': 2.83, 'su6': 2.74, 'su7': 2.68, 'type3': 3.45, 'type33': 3.83, 'type3s2': 3.61}), BoxBeamRating(beam_type='composite', box='CB27-48', width_ft=28, n_beams=7, span=45, rating_factors={'inv': 1.79, 'op': 2.33, 'ev2': 2.9, 'ev3': 2.38, 's2f1': 5.12, 's3f1': 3.51, 's5c1': 3.56, 'spl60t': 3.26, 'spl65t': 2.71, 'su4': 3.11, 'su5': 2.83, 'su6': 2.74, 'su7': 2.68, 'type3': 3.46, 'type33': 3.84, 'type3s2': 3.61}), BoxBeamRating(beam_type='composite', box='CB27-48', width_ft=24, n_beams=6, span=50, rating_factors={'inv': 1.67, 'op': 2.16, 'ev2': 2.76, 'ev3': 2.26, 's2f1': 4.92, 's3f1': 3.35, 's5c1': 3.39, 'spl60t': 3.09, 'spl65t': 2.4, 'su4': 2.95, 'su5': 2.67, 'su6': 2.56, 'su7': 2.48, 'type3': 3.27, 'type33': 3.42, 'type3s2': 3.23}), BoxBeamRating(beam_type='composite', box='CB27-48', width_ft=28, n_beams=7, span=50, rating_factors={'inv': 1.67, 'op': 2.16, 'ev2': 2.76, 'ev3': 2.26, 's2f1': 4.92, 's3f1': 3.35, 's5c1': 3.4, 'spl60t': 3.09, 'spl65t': 2.4, 'su4': 2.95, 'su5': 2.68, 'su6': 2.56, 'su7': 2.48, 'type3': 3.27, 'type33': 3.42, 'type3s2': 3.24}), BoxBeamRating(beam_type='composite', box='CB27-48', width_ft=24, n_beams=6, span=55, rating_factors={'inv': 1.52, 'op': 1.97, 'ev2': 2.57, 'ev3': 2.1, 's2f1': 4.63, 's3f1': 3.14, 's5c1': 3.11, 'spl60t': 2.84, 'spl65t': 2.09, 'su4': 2.75, 'su5': 2.48, 'su6': 2.35, 'su7': 2.25, 'type3': 3.04, 'type33': 3.02, 'type3s2': 2.85}), BoxBeamRating(beam_type='composite', box='CB27-48', width_ft=28, n_beams=7, span=55, rating_factors={'inv': 1.52, 'op': 1.97, 'ev2': 2.58, 'ev3': 2.1, 's2f1': 4.63, 's3f1': 3.14, 's5c1': 3.11, 'spl60t': 2.84, 'spl65t': 2.09, 'su4': 2.75, 'su5': 2.48, 'su6': 2.35, 'su7': 2.25, 'type3': 3.04, 'type33': 3.02, 'type3s2': 2.85}), BoxBeamRating(beam_type='composite', box='CB27-48', width_ft=24, n_beams=6, span=60, rating_factors={'inv': 1.64, 'op': 2.41, 'ev2': 3.12, 'ev3': 2.55, 's2f1': 5.58, 's3f1': 3.79, 's5c1': 3.74, 'spl60t': 3.14, 'spl65t': 2.52, 'su4': 3.33, 'su5': 3.01, 'su6': 2.87, 'su7': 2.75, 'type3': 3.69, 'type33': 3.69, 'type3s2': 3.49}), BoxBeamRating(beam_type='composite', box='CB27-48', width_ft=28, n_beams=7, span=60, rating_factors={'inv': 1.69, 'op': 2.41, 'ev2': 3.12, 'ev3': 2.55, 's2f1': 5.58, 's3f1': 3.79, 's5c1': 3.74, 'spl60t': 3.14, 'spl65t': 2.53, 'su4': 3.34, 'su5': 3.01, 'su6': 2.87, 'su7': 2.76, 'type3': 3.69, 'type33': 3.7, 'type3s2': 3.49}), BoxBeamRating(beam_type='composite', box='CB27-48', width_ft=24, n_beams=6, span=65, rating_factors={'inv': 1.55, 'op': 2.05, 'ev2': 2.77, 'ev3': 2.26, 's2f1': 5.02, 's3f1': 3.38, 's5c1': 3.03, 'spl60t': 2.54, 'spl65t': 2.07, 'su4': 2.96, 'su5': 2.65, 'su6': 2.49, 'su7': 2.35, 'type3': 3.25, 'type33': 3.0, 'type3s2': 2.89}), BoxBeamRating(beam_type='composite', box='CB27-48', width_ft=28, n_beams=7, span=65, rating_factors={'inv': 1.58, 'op': 2.05, 'ev2': 2.77, 'ev3': 2.26, 's2f1': 5.03, 's3f1': 3.39, 's5c1': 3.03, 'spl60t': 2.54, 'spl65t': 2.07, 'su4': 2.96, 'su5': 2.65, 'su6': 2.49, 'su7': 2.36, 'type3': 3.26, 'type33': 3.0, 'type3s2': 2.9}), BoxBeamRating(beam_type='composite', box='CB27-48', width_ft=24, n_beams=6, span=70, rating_factors={'inv': 1.3, 'op': 1.68, 'ev2': 2.31, 'ev3': 1.88, 's2f1': 4.21, 's3f1': 2.83, 's5c1': 2.43, 'spl60t': 2.04, 'spl65t': 1.68, 'su4': 2.47, 'su5': 2.21, 'su6': 2.07, 'su7': 1.95, 'type3': 2.72, 'type33': 2.41, 'type3s2': 2.36}), BoxBeamRating(beam_type='composite', box='CB27-48', width_ft=28, n_beams=7, span=70, rating_factors={'inv': 1.3, 'op': 1.68, 'ev2': 2.32, 'ev3': 1.89, 's2f1': 4.22, 's3f1': 2.84, 's5c1': 2.43, 'spl60t': 2.04, 'spl65t': 1.68, 'su4': 2.47, 'su5': 2.21, 'su6': 2.07, 'su7': 1.95, 'type3': 2.72, 'type33': 2.41, 'type3s2': 2.36}), BoxBeamRating(beam_type='composite', box='CB33-48', width_ft=24, n_beams=6, span=50, rating_factors={'inv': 1.88, 'op': 2.75, 'ev2': 3.51, 'ev3': 2.87, 's2f1': 6.08, 's3f1': 4.11, 's5c1': 4.22, 'spl60t': 3.71, 'spl65t': 3.05, 'su4': 3.66, 'su5': 3.38, 'su6': 3.04, 'su7': 2.81, 'type3': 4.16, 'type33': 4.35, 'type3s2': 4.11}), BoxBeamRating(beam_type='composite', box='CB33-48', width_ft=28, n_beams=7, span=50, rating_factors={'inv': 1.94, 'op': 2.85, 'ev2': 3.79, 'ev3': 2.96, 's2f1': 6.28, 's3f1': 4.25, 's5c1': 4.36, 'spl60t': 3.84, 'spl65t': 3.4, 'su4': 3.78, 'su5': 3.49, 'su6': 3.14, 'su7': 2.9, 'type3': 4.34, 'type33': 5.18, 'type3s2': 4.74}), BoxBeamRating(beam_type='composite', box='CB33-48', width_ft=24, n_beams=6, span=55, rating_factors={'inv': 1.64, 'op': 2.58, 'ev2': 3.4, 'ev3': 2.75, 's2f1': 5.91, 's3f1': 3.98, 's5c1': 4.07, 'spl60t': 3.61, 'spl65t': 2.79, 'su4': 3.52, 'su5': 3.23, 'su6': 2.9, 'su7': 2.68, 'type3': 4.01, 'type33': 4.02, 'type3s2': 3.8}), BoxBeamRating(beam_type='composite', box='CB33-48', width_ft=28, n_beams=7, span=55, rating_factors={'inv': 1.69, 'op': 2.61, 'ev2': 3.4, 'ev3': 2.78, 's2f1': 6.1, 's3f1': 4.11, 's5c1': 4.14, 'spl60t': 3.73, 'spl65t': 2.79, 'su4': 3.63, 'su5': 3.28, 'su6': 3.0, 'su7': 2.76, 'type3': 4.02, 'type33': 4.02, 'type3s2': 3.8}), BoxBeamRating(beam_type='composite', box='CB33-48', width_ft=24, n_beams=6, span=60, rating_factors={'inv': 1.48, 'op': 2.45, 'ev2': 3.26, 'ev3': 2.66, 's2f1': 5.82, 's3f1': 3.91, 's5c1': 3.75, 'spl60t': 3.15, 'spl65t': 2.54, 'su4': 3.44, 'su5': 3.13, 'su6': 2.82, 'su7': 2.6, 'type3': 3.84, 'type33': 3.71, 'type3s2': 3.51}), BoxBeamRating(beam_type='composite', box='CB33-48', width_ft=28, n_beams=7, span=60, rating_factors={'inv': 1.54, 'op': 2.45, 'ev2': 3.26, 'ev3': 2.66, 's2f1': 5.88, 's3f1': 3.98, 's5c1': 3.76, 'spl60t': 3.15, 'spl65t': 2.54, 'su4': 3.48, 'su5': 3.13, 'su6': 2.92, 'su7': 2.68, 'type3': 3.84, 'type33': 3.71, 'type3s2': 3.51}), BoxBeamRating(beam_type='composite', box='CB33-48', width_ft=24, n_beams=6, span=65, rating_factors={'inv': 1.58, 'op': 2.62, 'ev2': 3.7, 'ev3': 2.92, 's2f1': 6.38, 's3f1': 4.27, 's5c1': 4.3, 'spl60t': 3.61, 'spl65t': 2.94, 'su4': 3.76, 'su5': 3.42, 'su6': 3.06, 'su7': 2.81, 'type3': 4.24, 'type33': 4.26, 'type3s2': 4.03}), BoxBeamRating(beam_type='composite', box='CB33-48', width_ft=28, n_beams=7, span=65, rating_factors={'inv': 1.64, 'op': 2.71, 'ev2': 3.82, 'ev3': 3.02, 's2f1': 6.59, 's3f1': 4.41, 's5c1': 4.31, 'spl60t': 3.61, 'spl65t': 2.95, 'su4': 3.88, 'su5': 3.53, 'su6': 3.16, 'su7': 2.9, 'type3': 4.38, 'type33': 4.27, 'type3s2': 4.11}), BoxBeamRating(beam_type='composite', box='CB33-48', width_ft=24, n_beams=6, span=70, rating_factors={'inv': 1.62, 'op': 2.52, 'ev2': 3.46, 'ev3': 2.82, 's2f1': 6.3, 's3f1': 4.24, 's5c1': 3.64, 'spl60t': 3.05, 'spl65t': 2.51, 'su4': 3.69, 'su5': 3.31, 'su6': 3.09, 'su7': 2.91, 'type3': 4.06, 'type33': 3.61, 'type3s2': 3.53}), BoxBeamRating(beam_type='composite', box='CB33-48', width_ft=28, n_beams=7, span=70, rating_factors={'inv': 1.67, 'op': 2.52, 'ev2': 3.46, 'ev3': 2.82, 's2f1': 6.31, 's3f1': 4.24, 's5c1': 3.64, 'spl60t': 3.05, 'spl65t': 2.51, 'su4': 3.7, 'su5': 3.31, 'su6': 3.09, 'su7': 2.91, 'type3': 4.07, 'type33': 3.61, 'type3s2': 3.53}), BoxBeamRating(beam_type='composite', box='CB33-48', width_ft=24, n_beams=6, span=75, rating_factors={'inv': 1.56, 'op': 2.07, 'ev2': 2.9, 'ev3': 2.36, 's2f1': 5.3, 's3f1': 3.55, 's5c1': 2.94, 'spl60t': 2.45, 'spl65t': 2.05, 'su4': 3.09, 'su5': 2.76, 'su6': 2.57, 'su7': 2.41, 'type3': 3.39, 'type33': 2.92, 'type3s2': 2.9}), BoxBeamRating(beam_type='composite', box='CB33-48', width_ft=28, n_beams=7, span=75, rating_factors={'inv': 1.6, 'op': 2.07, 'ev2': 2.9, 'ev3': 2.36, 's2f1': 5.3, 's3f1': 3.56, 's5c1': 2.95, 'spl60t': 2.45, 'spl65t': 2.05, 'su4': 3.1, 'su5': 2.76, 'su6': 2.57, 'su7': 2.41, 'type3': 3.4, 'type33': 2.93, 'type3s2': 2.9}), BoxBeamRating(beam_type='composite', box='CB33-48', width_ft=24, n_beams=6, span=80, rating_factors={'inv': 1.45, 'op': 1.94, 'ev2': 2.75, 'ev3': 2.24, 's2f1': 5.05, 's3f1': 3.38, 's5c1': 2.72, 'spl60t': 2.24, 'spl65t': 1.9, 'su4': 2.94, 'su5': 2.62, 'su6': 2.43, 'su7': 2.27, 'type3': 3.22, 'type33': 2.7, 'type3s2': 2.7}), BoxBeamRating(beam_type='composite', box='CB33-48', width_ft=28, n_beams=7, span=80, rating_factors={'inv': 1.5, 'op': 1.94, 'ev2': 2.75, 'ev3': 2.24, 's2f1': 5.05, 's3f1': 3.38, 's5c1': 2.72, 'spl60t': 2.24, 'spl65t': 1.91, 'su4': 2.94, 'su5': 2.62, 'su6': 2.43, 'su7': 2.27, 'type3': 3.22, 'type33': 2.7, 'type3s2': 2.71}), BoxBeamRating(beam_type='composite', box='CB33-48', width_ft=24, n_beams=6, span=85, rating_factors={'inv': 1.4, 'op': 1.82, 'ev2': 2.62, 'ev3': 2.13, 's2f1': 4.81, 's3f1': 3.22, 's5c1': 2.53, 'spl60t': 2.06, 'spl65t': 1.78, 'su4': 2.79, 'su5': 2.48, 'su6': 2.3, 'su7': 2.15, 'type3': 3.06, 'type33': 2.51, 'type3s2': 2.53}), BoxBeamRating(beam_type='composite', box='CB33-48', width_ft=28, n_beams=7, span=85, rating_factors={'inv': 1.4, 'op': 1.82, 'ev2': 2.62, 'ev3': 2.13, 's2f1': 4.82, 's3f1': 3.22, 's5c1': 2.53, 'spl60t': 2.06, 'spl65t': 1.78, 'su4': 2.8, 'su5': 2.49, 'su6': 2.31, 'su7': 2.15, 'type3': 3.06, 'type33': 2.51, 'type3s2': 2.54}), BoxBeamRating(beam_type='composite', box='CB42-48', width_ft=24, n_beams=6, span=65, rating_factors={'inv': 1.45, 'op': 2.4, 'ev2': 3.39, 'ev3': 2.67, 's2f1': 5.84, 's3f1': 3.91, 's5c1': 3.98, 'spl60t': 3.3, 'spl65t': 2.73, 'su4': 3.43, 'su5': 3.12, 'su6': 2.8, 'su7': 2.57, 'type3': 3.88, 'type33': 3.93, 'type3s2': 3.69}), BoxBeamRating(beam_type='composite', box='CB42-48', width_ft=28, n_beams=7, span=65, rating_factors={'inv': 1.5, 'op': 2.48, 'ev2': 3.5, 'ev3': 2.76, 's2f1': 6.03, 's3f1': 4.04, 's5c1': 4.11, 'spl60t': 3.41, 'spl65t': 2.83, 'su4': 3.55, 'su5': 3.23, 'su6': 2.89, 'su7': 2.66, 'type3': 4.01, 'type33': 4.07, 'type3s2': 3.81}), BoxBeamRating(beam_type='composite', box='CB42-48', width_ft=24, n_beams=6, span=70, rating_factors={'inv': 1.62, 'op': 2.7, 'ev2': 3.87, 'ev3': 3.06, 's2f1': 6.74, 's3f1': 4.5, 's5c1': 4.41, 'spl60t': 3.81, 'spl65t': 3.01, 'su4': 3.95, 'su5': 3.58, 'su6': 3.2, 'su7': 2.93, 'type3': 4.44, 'type33': 4.32, 'type3s2': 4.09}), BoxBeamRating(beam_type='composite', box='CB42-48', width_ft=28, n_beams=7, span=70, rating_factors={'inv': 1.67, 'op': 2.79, 'ev2': 4.0, 'ev3': 3.16, 's2f1': 6.96, 's3f1': 4.65, 's5c1': 4.56, 'spl60t': 3.94, 'spl65t': 3.11, 'su4': 4.08, 'su5': 3.69, 'su6': 3.31, 'su7': 3.03, 'type3': 4.59, 'type33': 4.47, 'type3s2': 4.23}), BoxBeamRating(beam_type='composite', box='CB42-48', width_ft=24, n_beams=6, span=75, rating_factors={'inv': 1.47, 'op': 2.57, 'ev2': 3.76, 'ev3': 2.97, 's2f1': 6.58, 's3f1': 4.39, 's5c1': 4.13, 'spl60t': 3.57, 'spl65t': 2.82, 'su4': 3.84, 'su5': 3.47, 'su6': 3.11, 'su7': 2.84, 'type3': 4.31, 'type33': 4.02, 'type3s2': 3.87}), BoxBeamRating(beam_type='composite', box='CB42-48', width_ft=28, n_beams=7, span=75, rating_factors={'inv': 1.49, 'op': 2.66, 'ev2': 3.88, 'ev3': 3.07, 's2f1': 6.8, 's3f1': 4.54, 's5c1': 4.27, 'spl60t': 3.57, 'spl65t': 2.91, 'su4': 3.97, 'su5': 3.58, 'su6': 3.21, 'su7': 2.94, 'type3': 4.45, 'type33': 4.15, 'type3s2': 4.0}), BoxBeamRating(beam_type='composite', box='CB42-48', width_ft=24, n_beams=6, span=80, rating_factors={'inv': 1.66, 'op': 2.73, 'ev2': 3.87, 'ev3': 3.15, 's2f1': 7.11, 's3f1': 4.76, 's5c1': 3.83, 'spl60t': 3.15, 'spl65t': 2.68, 'su4': 4.14, 'su5': 3.69, 'su6': 3.42, 'su7': 3.2, 'type3': 4.54, 'type33': 3.81, 'type3s2': 3.81}), BoxBeamRating(beam_type='composite', box='CB42-48', width_ft=28, n_beams=7, span=80, rating_factors={'inv': 1.72, 'op': 2.73, 'ev2': 3.88, 'ev3': 3.16, 's2f1': 7.12, 's3f1': 4.77, 's5c1': 3.84, 'spl60t': 3.16, 'spl65t': 2.68, 'su4': 4.14, 'su5': 3.69, 'su6': 3.43, 'su7': 3.2, 'type3': 4.54, 'type33': 3.81, 'type3s2': 3.81}), BoxBeamRating(beam_type='composite', box='CB42-48', width_ft=24, n_beams=6, span=85, rating_factors={'inv': 1.7, 'op': 2.52, 'ev2': 3.63, 'ev3': 2.95, 's2f1': 6.67, 's3f1': 4.46, 's5c1': 3.5, 'spl60t': 2.86, 'spl65t': 2.46, 'su4': 3.87, 'su5': 3.44, 'su6': 3.19, 'su7': 2.97, 'type3': 4.24, 'type33': 3.48, 'type3s2': 3.51}), BoxBeamRating(beam_type='composite', box='CB42-48', width_ft=28, n_beams=7, span=85, rating_factors={'inv': 1.77, 'op': 2.52, 'ev2': 3.63, 'ev3': 2.95, 's2f1': 6.68, 's3f1': 4.46, 's5c1': 3.5, 'spl60t': 2.86, 'spl65t': 2.47, 'su4': 3.87, 'su5': 3.45, 'su6': 3.19, 'su7': 2.98, 'type3': 4.24, 'type33': 3.48, 'type3s2': 3.52}), BoxBeamRating(beam_type='composite', box='CB42-48', width_ft=24, n_beams=6, span=90, rating_factors={'inv': 1.51, 'op': 2.42, 'ev2': 3.54, 'ev3': 2.88, 's2f1': 6.53, 's3f1': 4.36, 's5c1': 3.35, 'spl60t': 2.71, 'spl65t': 2.36, 'su4': 3.78, 'su5': 3.36, 'su6': 3.1, 'su7': 2.88, 'type3': 4.13, 'type33': 3.33, 'type3s2': 3.39}), BoxBeamRating(beam_type='composite', box='CB42-48', width_ft=28, n_beams=7, span=90, rating_factors={'inv': 1.57, 'op': 2.43, 'ev2': 3.54, 'ev3': 2.88, 's2f1': 6.53, 's3f1': 4.36, 's5c1': 3.35, 'spl60t': 2.71, 'spl65t': 2.37, 'su4': 3.78, 'su5': 3.36, 'su6': 3.1, 'su7': 2.89, 'type3': 4.14, 'type33': 3.33, 'type3s2': 3.39}), BoxBeamRating(beam_type='composite', box='CB42-48', width_ft=24, n_beams=6, span=95, rating_factors={'inv': 1.5, 'op': 2.32, 'ev2': 3.44, 'ev3': 2.79, 's2f1': 6.35, 's3f1': 4.24, 's5c1': 3.2, 'spl60t': 2.57, 'spl65t': 2.27, 'su4': 3.67, 'su5': 3.26, 'su6': 3.0, 'su7': 2.79, 'type3': 4.01, 'type33': 3.18, 'type3s2': 3.25}), BoxBeamRating(beam_type='composite', box='CB42-48', width_ft=28, n_beams=7, span=95, rating_factors={'inv': 1.55, 'op': 2.33, 'ev2': 3.44, 'ev3': 2.8, 's2f1': 6.36, 's3f1': 4.24, 's5c1': 3.2, 'spl60t': 2.57, 'spl65t': 2.27, 'su4': 3.67, 'su5': 3.26, 'su6': 3.01, 'su7': 2.79, 'type3': 4.02, 'type33': 3.18, 'type3s2': 3.26}), BoxBeamRating(beam_type='composite', box='CB17-48', width_ft=32, n_beams=8, span=20, rating_factors={'inv': 2.3, 'op': 2.98, 'ev2': 3.78, 'ev3': 2.95, 's2f1': 5.57, 's3f1': 4.23, 's5c1': 4.45, 'spl60t': 4.18, 'spl65t': 3.91, 'su4': 3.92, 'su5': 3.7, 'su6': 3.7, 'su7': 3.7, 'type3': 4.45, 'type33': 5.4, 'type3s2': 4.77}), BoxBeamRating(beam_type='composite', box='CB17-48', width_ft=32, n_beams=8, span=25, rating_factors={'inv': 2.06, 'op': 2.67, 'ev2': 3.14, 'ev3': 2.63, 's2f1': 4.96, 's3f1': 3.62, 's5c1': 3.76, 'spl60t': 3.6, 'spl65t': 3.33, 'su4': 3.39, 'su5': 3.21, 'su6': 3.24, 'su7': 3.24, 'type3': 3.95, 'type33': 4.92, 'type3s2': 4.08}), BoxBeamRating(beam_type='composite', box='CB17-48', width_ft=32, n_beams=8, span=30, rating_factors={'inv': 1.94, 'op': 2.51, 'ev2': 2.84, 'ev3': 2.36, 's2f1': 4.67, 's3f1': 3.34, 's5c1': 3.43, 'spl60t': 3.31, 'spl65t': 3.0, 'su4': 3.06, 'su5': 2.91, 'su6': 2.96, 'su7': 2.96, 'type3': 3.5, 'type33': 4.26, 'type3s2': 3.75}), BoxBeamRating(beam_type='composite', box='CB17-48', width_ft=32, n_beams=8, span=35, rating_factors={'inv': 1.56, 'op': 2.02, 'ev2': 2.38, 'ev3': 1.96, 's2f1': 4.09, 's3f1': 2.85, 's5c1': 2.91, 'spl60t': 2.81, 'spl65t': 2.5, 'su4': 2.55, 'su5': 2.36, 'su6': 2.36, 'su7': 2.36, 'type3': 2.87, 'type33': 3.42, 'type3s2': 3.2}), BoxBeamRating(beam_type='composite', box='CB17-48', width_ft=32, n_beams=8, span=40, rating_factors={'inv': 1.65, 'op': 2.14, 'ev2': 2.53, 'ev3': 2.08, 's2f1': 4.36, 's3f1': 3.03, 's5c1': 3.09, 'spl60t': 2.97, 'spl65t': 2.65, 'su4': 2.72, 'su5': 2.51, 'su6': 2.5, 'su7': 2.54, 'type3': 3.05, 'type33': 3.63, 'type3s2': 3.41}), BoxBeamRating(beam_type='composite', box='CB17-48', width_ft=32, n_beams=8, span=45, rating_factors={'inv': 1.54, 'op': 2.0, 'ev2': 2.43, 'ev3': 1.99, 's2f1': 4.23, 's3f1': 2.92, 's5c1': 2.97, 'spl60t': 2.72, 'spl65t': 2.42, 'su4': 2.6, 'su5': 2.38, 'su6': 2.34, 'su7': 2.32, 'type3': 2.9, 'type33': 3.4, 'type3s2': 3.19}), BoxBeamRating(beam_type='composite', box='CB21-48', width_ft=32, n_beams=8, span=30, rating_factors={'inv': 1.94, 'op': 2.51, 'ev2': 2.84, 'ev3': 2.36, 's2f1': 4.67, 's3f1': 3.34, 's5c1': 3.43, 'spl60t': 3.31, 'spl65t': 3.0, 'su4': 3.06, 'su5': 2.91, 'su6': 2.96, 'su7': 2.96, 'type3': 3.5, 'type33': 4.26, 'type3s2': 3.75}), BoxBeamRating(beam_type='composite', box='CB21-48', width_ft=32, n_beams=8, span=35, rating_factors={'inv': 2.07, 'op': 2.68, 'ev2': 3.15, 'ev3': 2.6, 's2f1': 5.42, 's3f1': 3.77, 's5c1': 3.85, 'spl60t': 3.72, 'spl65t': 3.32, 'su4': 3.38, 'su5': 3.13, 'su6': 3.13, 'su7': 3.13, 'type3': 3.81, 'type33': 4.53, 'type3s2': 4.24}), BoxBeamRating(beam_type='composite', box='CB21-48', width_ft=32, n_beams=8, span=40, rating_factors={'inv': 1.69, 'op': 2.2, 'ev2': 2.67, 'ev3': 2.19, 's2f1': 4.66, 's3f1': 3.21, 's5c1': 3.27, 'spl60t': 3.14, 'spl65t': 2.79, 'su4': 2.86, 'su5': 2.62, 'su6': 2.57, 'su7': 2.56, 'type3': 3.19, 'type33': 3.74, 'type3s2': 3.5}), BoxBeamRating(beam_type='composite', box='CB21-48', width_ft=32, n_beams=8, span=45, rating_factors={'inv': 1.57, 'op': 2.03, 'ev2': 2.54, 'ev3': 2.08, 's2f1': 4.48, 's3f1': 3.07, 's5c1': 3.12, 'spl60t': 2.85, 'spl65t': 2.37, 'su4': 2.72, 'su5': 2.47, 'su6': 2.39, 'su7': 2.34, 'type3': 3.02, 'type33': 3.35, 'type3s2': 3.16}), BoxBeamRating(beam_type='composite', box='CB21-48', width_ft=32, n_beams=8, span=50, rating_factors={'inv': 1.45, 'op': 1.88, 'ev2': 2.4, 'ev3': 1.96, 's2f1': 4.28, 's3f1': 2.92, 's5c1': 2.95, 'spl60t': 2.69, 'spl65t': 2.08, 'su4': 2.57, 'su5': 2.33, 'su6': 2.23, 'su7': 2.15, 'type3': 2.85, 'type33': 2.96, 'type3s2': 2.8}), BoxBeamRating(beam_type='composite', box='CB21-48', width_ft=32, n_beams=8, span=55, rating_factors={'inv': 1.3, 'op': 1.69, 'ev2': 2.21, 'ev3': 1.8, 's2f1': 3.97, 's3f1': 2.69, 's5c1': 2.66, 'spl60t': 2.44, 'spl65t': 1.79, 'su4': 2.36, 'su5': 2.13, 'su6': 2.02, 'su7': 1.93, 'type3': 2.61, 'type33': 2.59, 'type3s2': 2.45}), BoxBeamRating(beam_type='composite', box='CB21-48', width_ft=32, n_beams=8, span=60, rating_factors={'inv': 1.32, 'op': 1.71, 'ev2': 2.26, 'ev3': 1.85, 's2f1': 4.08, 's3f1': 2.76, 's5c1': 2.64, 'spl60t': 2.22, 'spl65t': 1.78, 'su4': 2.42, 'su5': 2.17, 'su6': 2.05, 'su7': 1.96, 'type3': 2.67, 'type33': 2.6, 'type3s2': 2.45}), BoxBeamRating(beam_type='composite', box='CB27-48', width_ft=32, n_beams=8, span=40, rating_factors={'inv': 2.2, 'op': 2.85, 'ev2': 3.47, 'ev3': 2.85, 's2f1': 6.05, 's3f1': 4.18, 's5c1': 4.25, 'spl60t': 4.08, 'spl65t': 3.63, 'su4': 3.72, 'su5': 3.41, 'su6': 3.34, 'su7': 3.32, 'type3': 4.15, 'type33': 4.86, 'type3s2': 4.56}), BoxBeamRating(beam_type='composite', box='CB27-48', width_ft=32, n_beams=8, span=45, rating_factors={'inv': 1.8, 'op': 2.33, 'ev2': 2.9, 'ev3': 2.38, 's2f1': 5.13, 's3f1': 3.51, 's5c1': 3.57, 'spl60t': 3.27, 'spl65t': 2.71, 'su4': 3.11, 'su5': 2.83, 'su6': 2.74, 'su7': 2.68, 'type3': 3.46, 'type33': 3.84, 'type3s2': 3.62}), BoxBeamRating(beam_type='composite', box='CB27-48', width_ft=32, n_beams=8, span=50, rating_factors={'inv': 1.67, 'op': 2.16, 'ev2': 2.76, 'ev3': 2.26, 's2f1': 4.92, 's3f1': 3.35, 's5c1': 3.4, 'spl60t': 3.1, 'spl65t': 2.4, 'su4': 2.96, 'su5': 2.68, 'su6': 2.56, 'su7': 2.48, 'type3': 3.28, 'type33': 3.43, 'type3s2': 3.24}), BoxBeamRating(beam_type='composite', box='CB27-48', width_ft=32, n_beams=8, span=55, rating_factors={'inv': 1.52, 'op': 1.97, 'ev2': 2.58, 'ev3': 2.11, 's2f1': 4.63, 's3f1': 3.14, 's5c1': 3.11, 'spl60t': 2.85, 'spl65t': 2.09, 'su4': 2.76, 'su5': 2.48, 'su6': 2.36, 'su7': 2.25, 'type3': 3.04, 'type33': 3.02, 'type3s2': 2.86}), BoxBeamRating(beam_type='composite', box='CB27-48', width_ft=32, n_beams=8, span=60, rating_factors={'inv': 1.74, 'op': 2.41, 'ev2': 3.12, 'ev3': 2.55, 's2f1': 5.59, 's3f1': 3.8, 's5c1': 3.74, 'spl60t': 3.14, 'spl65t': 2.53, 'su4': 3.34, 'su5': 3.01, 'su6': 2.87, 'su7': 2.76, 'type3': 3.69, 'type33': 3.7, 'type3s2': 3.5}), BoxBeamRating(beam_type='composite', box='CB27-48', width_ft=32, n_beams=8, span=65, rating_factors={'inv': 1.58, 'op': 2.05, 'ev2': 2.77, 'ev3': 2.26, 's2f1': 5.03, 's3f1': 3.39, 's5c1': 3.04, 'spl60t': 2.55, 'spl65t': 2.08, 'su4': 2.96, 'su5': 2.65, 'su6': 2.49, 'su7': 2.36, 'type3': 3.26, 'type33': 3.01, 'type3s2': 2.9}), BoxBeamRating(beam_type='composite', box='CB27-48', width_ft=32, n_beams=8, span=70, rating_factors={'inv': 1.3, 'op': 1.69, 'ev2': 2.32, 'ev3': 1.89, 's2f1': 4.22, 's3f1': 2.84, 's5c1': 2.44, 'spl60t': 2.04, 'spl65t': 1.68, 'su4': 2.48, 'su5': 2.21, 'su6': 2.07, 'su7': 1.95, 'type3': 2.72, 'type33': 2.42, 'type3s2': 2.37}), BoxBeamRating(beam_type='composite', box='CB33-48', width_ft=32, n_beams=8, span=50, rating_factors={'inv': 2.0, 'op': 2.93, 'ev2': 3.9, 'ev3': 3.05, 's2f1': 6.46, 's3f1': 4.37, 's5c1': 4.48, 'spl60t': 3.94, 'spl65t': 3.5, 'su4': 3.88, 'su5': 3.59, 'su6': 3.23, 'su7': 2.99, 'type3': 4.46, 'type33': 5.33, 'type3s2': 4.88}), BoxBeamRating(beam_type='composite', box='CB33-48', width_ft=32, n_beams=8, span=55, rating_factors={'inv': 1.74, 'op': 2.61, 'ev2': 3.4, 'ev3': 2.78, 's2f1': 6.1, 's3f1': 4.14, 's5c1': 4.14, 'spl60t': 3.78, 'spl65t': 2.79, 'su4': 3.64, 'su5': 3.28, 'su6': 3.08, 'su7': 2.84, 'type3': 4.02, 'type33': 4.02, 'type3s2': 3.8}), BoxBeamRating(beam_type='composite', box='CB33-48', width_ft=32, n_beams=8, span=60, rating_factors={'inv': 1.58, 'op': 2.45, 'ev2': 3.26, 'ev3': 2.66, 's2f1': 5.89, 's3f1': 3.98, 's5c1': 3.76, 'spl60t': 3.15, 'spl65t': 2.54, 'su4': 3.49, 'su5': 3.13, 'su6': 2.96, 'su7': 2.76, 'type3': 3.84, 'type33': 3.72, 'type3s2': 3.51}), BoxBeamRating(beam_type='composite', box='CB33-48', width_ft=32, n_beams=8, span=65, rating_factors={'inv': 1.69, 'op': 2.79, 'ev2': 3.84, 'ev3': 3.1, 's2f1': 6.78, 's3f1': 4.54, 's5c1': 4.31, 'spl60t': 3.62, 'spl65t': 2.95, 'su4': 3.99, 'su5': 3.63, 'su6': 3.25, 'su7': 2.99, 'type3': 4.51, 'type33': 4.27, 'type3s2': 4.11}), BoxBeamRating(beam_type='composite', box='CB33-48', width_ft=32, n_beams=8, span=70, rating_factors={'inv': 1.72, 'op': 2.52, 'ev2': 3.46, 'ev3': 2.82, 's2f1': 6.31, 's3f1': 4.24, 's5c1': 3.64, 'spl60t': 3.05, 'spl65t': 2.51, 'su4': 3.7, 'su5': 3.31, 'su6': 3.09, 'su7': 2.91, 'type3': 4.07, 'type33': 3.61, 'type3s2': 3.54}), BoxBeamRating(beam_type='composite', box='CB33-48', width_ft=32, n_beams=8, span=75, rating_factors={'inv': 1.6, 'op': 2.08, 'ev2': 2.9, 'ev3': 2.36, 's2f1': 5.31, 's3f1': 3.56, 's5c1': 2.95, 'spl60t': 2.45, 'spl65t': 2.05, 'su4': 3.1, 'su5': 2.77, 'su6': 2.58, 'su7': 2.42, 'type3': 3.4, 'type33': 2.93, 'type3s2': 2.9}), BoxBeamRating(beam_type='composite', box='CB33-48', width_ft=32, n_beams=8, span=80, rating_factors={'inv': 1.5, 'op': 1.94, 'ev2': 2.76, 'ev3': 2.24, 's2f1': 5.06, 's3f1': 3.39, 's5c1': 2.73, 'spl60t': 2.24, 'spl65t': 1.91, 'su4': 2.94, 'su5': 2.62, 'su6': 2.44, 'su7': 2.28, 'type3': 3.23, 'type33': 2.71, 'type3s2': 2.71}), BoxBeamRating(beam_type='composite', box='CB33-48', width_ft=32, n_beams=8, span=85, rating_factors={'inv': 1.41, 'op': 1.82, 'ev2': 2.62, 'ev3': 2.13, 's2f1': 4.82, 's3f1': 3.23, 's5c1': 2.53, 'spl60t': 2.06, 'spl65t': 1.78, 'su4': 2.8, 'su5': 2.49, 'su6': 2.31, 'su7': 2.15, 'type3': 3.07, 'type33': 2.52, 'type3s2': 2.54}), BoxBeamRating(beam_type='composite', box='CB42-48', width_ft=32, n_beams=8, span=65, rating_factors={'inv': 1.55, 'op': 2.55, 'ev2': 3.6, 'ev3': 2.84, 's2f1': 6.2, 's3f1': 4.15, 's5c1': 4.23, 'spl60t': 3.51, 'spl65t': 2.91, 'su4': 3.65, 'su5': 3.32, 'su6': 2.98, 'su7': 2.73, 'type3': 4.12, 'type33': 4.18, 'type3s2': 3.92}), BoxBeamRating(beam_type='composite', box='CB42-48', width_ft=32, n_beams=8, span=70, rating_factors={'inv': 1.72, 'op': 2.87, 'ev2': 4.12, 'ev3': 3.25, 's2f1': 7.16, 's3f1': 4.78, 's5c1': 4.69, 'spl60t': 3.94, 'spl65t': 3.2, 'su4': 4.19, 'su5': 3.8, 'su6': 3.41, 'su7': 3.12, 'type3': 4.72, 'type33': 4.6, 'type3s2': 4.35}), BoxBeamRating(beam_type='composite', box='CB42-48', width_ft=32, n_beams=8, span=75, rating_factors={'inv': 1.53, 'op': 2.74, 'ev2': 3.99, 'ev3': 3.16, 's2f1': 7.0, 's3f1': 4.67, 's5c1': 4.29, 'spl60t': 3.58, 'spl65t': 2.97, 'su4': 4.08, 'su5': 3.69, 'su6': 3.3, 'su7': 3.02, 'type3': 4.58, 'type33': 4.26, 'type3s2': 4.11}), BoxBeamRating(beam_type='composite', box='CB42-48', width_ft=32, n_beams=8, span=80, rating_factors={'inv': 1.77, 'op': 2.74, 'ev2': 3.88, 'ev3': 3.16, 's2f1': 7.12, 's3f1': 4.77, 's5c1': 3.84, 'spl60t': 3.16, 'spl65t': 2.69, 'su4': 4.14, 'su5': 3.69, 'su6': 3.43, 'su7': 3.21, 'type3': 4.54, 'type33': 3.81, 'type3s2': 3.82}), BoxBeamRating(beam_type='composite', box='CB42-48', width_ft=32, n_beams=8, span=85, rating_factors={'inv': 1.82, 'op': 2.52, 'ev2': 3.63, 'ev3': 2.95, 's2f1': 6.68, 's3f1': 4.47, 's5c1': 3.51, 'spl60t': 2.86, 'spl65t': 2.47, 'su4': 3.88, 'su5': 3.45, 'su6': 3.2, 'su7': 2.98, 'type3': 4.25, 'type33': 3.49, 'type3s2': 3.52}), BoxBeamRating(beam_type='composite', box='CB42-48', width_ft=32, n_beams=8, span=90, rating_factors={'inv': 1.62, 'op': 2.43, 'ev2': 3.54, 'ev3': 2.88, 's2f1': 6.54, 's3f1': 4.36, 's5c1': 3.35, 'spl60t': 2.71, 'spl65t': 2.37, 'su4': 3.78, 'su5': 3.36, 'su6': 3.11, 'su7': 2.89, 'type3': 4.14, 'type33': 3.33, 'type3s2': 3.39}), BoxBeamRating(beam_type='composite', box='CB42-48', width_ft=32, n_beams=8, span=95, rating_factors={'inv': 1.6, 'op': 2.33, 'ev2': 3.44, 'ev3': 2.8, 's2f1': 6.37, 's3f1': 4.25, 's5c1': 3.2, 'spl60t': 2.57, 'spl65t': 2.27, 'su4': 3.68, 'su5': 3.26, 'su6': 3.01, 'su7': 2.79, 'type3': 4.02, 'type33': 3.19, 'type3s2': 3.26}), BoxBeamRating(beam_type='non_composite', box='B17-48', width_ft=24, n_beams=6, span=20, rating_factors={'inv': 1.94, 'op': 2.52, 'ev2': 3.19, 'ev3': 2.49, 's2f1': 4.7, 's3f1': 3.57, 's5c1': 3.75, 'spl60t': 4.02, 'spl65t': 3.75, 'su4': 3.31, 'su5': 3.12, 'su6': 3.12, 'su7': 3.12, 'type3': 3.75, 'type33': 4.56, 'type3s2': 4.02}), BoxBeamRating(beam_type='non_composite', box='B17-48', width_ft=28, n_beams=7, span=20, rating_factors={'inv': 1.94, 'op': 2.52, 'ev2': 3.19, 'ev3': 2.49, 's2f1': 4.7, 's3f1': 3.57, 's5c1': 3.75, 'spl60t': 4.02, 'spl65t': 3.75, 'su4': 3.31, 'su5': 3.12, 'su6': 3.12, 'su7': 3.12, 'type3': 3.75, 'type33': 4.56, 'type3s2': 4.02}), BoxBeamRating(beam_type='non_composite', box='B17-48', width_ft=24, n_beams=6, span=25, rating_factors={'inv': 1.79, 'op': 2.31, 'ev2': 2.72, 'ev3': 2.28, 's2f1': 4.29, 's3f1': 3.14, 's5c1': 3.25, 'spl60t': 3.58, 'spl65t': 3.31, 'su4': 2.93, 'su5': 2.78, 'su6': 2.81, 'su7': 2.81, 'type3': 3.42, 'type33': 4.26, 'type3s2': 3.53}), BoxBeamRating(beam_type='non_composite', box='B17-48', width_ft=28, n_beams=7, span=25, rating_factors={'inv': 1.79, 'op': 2.32, 'ev2': 2.72, 'ev3': 2.28, 's2f1': 4.29, 's3f1': 3.14, 's5c1': 3.25, 'spl60t': 3.58, 'spl65t': 3.32, 'su4': 2.93, 'su5': 2.78, 'su6': 2.81, 'su7': 2.81, 'type3': 3.42, 'type33': 4.26, 'type3s2': 3.53}), BoxBeamRating(beam_type='non_composite', box='B17-48', width_ft=24, n_beams=6, span=30, rating_factors={'inv': 1.54, 'op': 1.99, 'ev2': 2.25, 'ev3': 1.87, 's2f1': 3.71, 's3f1': 2.65, 's5c1': 2.73, 'spl60t': 3.05, 'spl65t': 2.76, 'su4': 2.43, 'su5': 2.31, 'su6': 2.35, 'su7': 2.35, 'type3': 2.78, 'type33': 3.38, 'type3s2': 2.98}), BoxBeamRating(beam_type='non_composite', box='B17-48', width_ft=28, n_beams=7, span=30, rating_factors={'inv': 1.54, 'op': 2.0, 'ev2': 2.26, 'ev3': 1.87, 's2f1': 3.71, 's3f1': 2.65, 's5c1': 2.73, 'spl60t': 3.05, 'spl65t': 2.76, 'su4': 2.43, 'su5': 2.31, 'su6': 2.35, 'su7': 2.35, 'type3': 2.78, 'type33': 3.38, 'type3s2': 2.98}), BoxBeamRating(beam_type='non_composite', box='B17-48', width_ft=24, n_beams=6, span=35, rating_factors={'inv': 1.43, 'op': 1.85, 'ev2': 2.11, 'ev3': 1.74, 's2f1': 3.57, 's3f1': 2.51, 's5c1': 2.57, 'spl60t': 2.9, 'spl65t': 2.59, 'su4': 2.27, 'su5': 2.12, 'su6': 2.16, 'su7': 2.17, 'type3': 2.57, 'type33': 3.08, 'type3s2': 2.82}), BoxBeamRating(beam_type='non_composite', box='B17-48', width_ft=28, n_beams=7, span=35, rating_factors={'inv': 1.41, 'op': 1.83, 'ev2': 2.09, 'ev3': 1.72, 's2f1': 3.53, 's3f1': 2.48, 's5c1': 2.54, 'spl60t': 2.87, 'spl65t': 2.56, 'su4': 2.24, 'su5': 2.1, 'su6': 2.14, 'su7': 2.14, 'type3': 2.54, 'type33': 3.05, 'type3s2': 2.79}), BoxBeamRating(beam_type='non_composite', box='B21-48', width_ft=24, n_beams=6, span=30, rating_factors={'inv': 1.94, 'op': 2.51, 'ev2': 2.84, 'ev3': 2.36, 's2f1': 4.67, 's3f1': 3.34, 's5c1': 3.43, 'spl60t': 3.84, 'spl65t': 3.48, 'su4': 3.06, 'su5': 2.91, 'su6': 2.96, 'su7': 2.96, 'type3': 3.5, 'type33': 4.26, 'type3s2': 3.75}), BoxBeamRating(beam_type='non_composite', box='B21-48', width_ft=28, n_beams=7, span=30, rating_factors={'inv': 1.94, 'op': 2.51, 'ev2': 2.84, 'ev3': 2.36, 's2f1': 4.68, 's3f1': 3.34, 's5c1': 3.43, 'spl60t': 3.85, 'spl65t': 3.48, 'su4': 3.06, 'su5': 2.91, 'su6': 2.96, 'su7': 2.96, 'type3': 3.5, 'type33': 4.26, 'type3s2': 3.76}), BoxBeamRating(beam_type='non_composite', box='B21-48', width_ft=24, n_beams=6, span=35, rating_factors={'inv': 1.5, 'op': 1.94, 'ev2': 2.29, 'ev3': 1.89, 's2f1': 3.93, 's3f1': 2.74, 's5c1': 2.79, 'spl60t': 3.16, 'spl65t': 2.82, 'su4': 2.45, 'su5': 2.27, 'su6': 2.27, 'su7': 2.27, 'type3': 2.76, 'type33': 3.29, 'type3s2': 3.08}), BoxBeamRating(beam_type='non_composite', box='B21-48', width_ft=28, n_beams=7, span=35, rating_factors={'inv': 1.5, 'op': 1.95, 'ev2': 2.29, 'ev3': 1.89, 's2f1': 3.93, 's3f1': 2.74, 's5c1': 2.8, 'spl60t': 3.16, 'spl65t': 2.82, 'su4': 2.46, 'su5': 2.27, 'su6': 2.27, 'su7': 2.27, 'type3': 2.76, 'type33': 3.29, 'type3s2': 3.08}), BoxBeamRating(beam_type='non_composite', box='B21-48', width_ft=24, n_beams=6, span=40, rating_factors={'inv': 1.29, 'op': 1.67, 'ev2': 2.03, 'ev3': 1.66, 's2f1': 3.53, 's3f1': 2.44, 's5c1': 2.48, 'spl60t': 2.81, 'spl65t': 2.5, 'su4': 2.17, 'su5': 1.99, 'su6': 1.95, 'su7': 1.94, 'type3': 2.43, 'type33': 2.84, 'type3s2': 2.66}), BoxBeamRating(beam_type='non_composite', box='B21-48', width_ft=28, n_beams=7, span=40, rating_factors={'inv': 1.29, 'op': 1.67, 'ev2': 2.03, 'ev3': 1.67, 's2f1': 3.54, 's3f1': 2.44, 's5c1': 2.48, 'spl60t': 2.81, 'spl65t': 2.5, 'su4': 2.17, 'su5': 1.99, 'su6': 1.95, 'su7': 1.94, 'type3': 2.43, 'type33': 2.84, 'type3s2': 2.66}), BoxBeamRating(beam_type='non_composite', box='B21-48', width_ft=24, n_beams=6, span=45, rating_factors={'inv': 1.44, 'op': 1.86, 'ev2': 2.26, 'ev3': 1.86, 's2f1': 3.95, 's3f1': 2.72, 's5c1': 2.77, 'spl60t': 3.0, 'spl65t': 2.67, 'su4': 2.42, 'su5': 2.22, 'su6': 2.18, 'su7': 2.17, 'type3': 2.71, 'type33': 3.17, 'type3s2': 2.97}), BoxBeamRating(beam_type='non_composite', box='B21-48', width_ft=28, n_beams=7, span=45, rating_factors={'inv': 1.44, 'op': 1.86, 'ev2': 2.26, 'ev3': 1.86, 's2f1': 3.95, 's3f1': 2.72, 's5c1': 2.77, 'spl60t': 3.0, 'spl65t': 2.67, 'su4': 2.42, 'su5': 2.22, 'su6': 2.18, 'su7': 2.17, 'type3': 2.71, 'type33': 3.17, 'type3s2': 2.97}), BoxBeamRating(beam_type='non_composite', box='B21-48', width_ft=24, n_beams=6, span=50, rating_factors={'inv': 1.25, 'op': 1.75, 'ev2': 2.18, 'ev3': 1.79, 's2f1': 3.85, 's3f1': 2.64, 's5c1': 2.68, 'spl60t': 2.58, 'spl65t': 2.29, 'su4': 2.34, 'su5': 2.13, 'su6': 2.06, 'su7': 1.96, 'type3': 2.6, 'type33': 2.91, 'type3s2': 2.73}), BoxBeamRating(beam_type='non_composite', box='B21-48', width_ft=28, n_beams=7, span=50, rating_factors={'inv': 1.3, 'op': 1.75, 'ev2': 2.18, 'ev3': 1.79, 's2f1': 3.85, 's3f1': 2.64, 's5c1': 2.68, 'spl60t': 2.67, 'spl65t': 2.37, 'su4': 2.34, 'su5': 2.13, 'su6': 2.06, 'su7': 2.02, 'type3': 2.6, 'type33': 2.91, 'type3s2': 2.73}), BoxBeamRating(beam_type='non_composite', box='B27-48', width_ft=24, n_beams=6, span=40, rating_factors={'inv': 1.89, 'op': 2.45, 'ev2': 2.98, 'ev3': 2.45, 's2f1': 5.2, 's3f1': 3.59, 's5c1': 3.65, 'spl60t': 3.46, 'spl65t': 3.12, 'su4': 3.19, 'su5': 2.93, 'su6': 2.86, 'su7': 2.68, 'type3': 3.57, 'type33': 4.18, 'type3s2': 3.91}), BoxBeamRating(beam_type='non_composite', box='B27-48', width_ft=28, n_beams=7, span=40, rating_factors={'inv': 1.89, 'op': 2.45, 'ev2': 2.98, 'ev3': 2.45, 's2f1': 5.2, 's3f1': 3.59, 's5c1': 3.65, 'spl60t': 3.51, 'spl65t': 3.12, 'su4': 3.2, 'su5': 2.93, 'su6': 2.87, 'su7': 2.77, 'type3': 3.57, 'type33': 4.18, 'type3s2': 3.92}), BoxBeamRating(beam_type='non_composite', box='B27-48', width_ft=24, n_beams=6, span=45, rating_factors={'inv': 1.76, 'op': 2.28, 'ev2': 2.85, 'ev3': 2.34, 's2f1': 5.03, 's3f1': 3.45, 's5c1': 3.5, 'spl60t': 3.2, 'spl65t': 2.66, 'su4': 3.05, 'su5': 2.78, 'su6': 2.67, 'su7': 2.49, 'type3': 3.4, 'type33': 3.77, 'type3s2': 3.55}), BoxBeamRating(beam_type='non_composite', box='B27-48', width_ft=28, n_beams=7, span=45, rating_factors={'inv': 1.76, 'op': 2.29, 'ev2': 2.85, 'ev3': 2.34, 's2f1': 5.04, 's3f1': 3.45, 's5c1': 3.5, 'spl60t': 3.21, 'spl65t': 2.67, 'su4': 3.05, 'su5': 2.78, 'su6': 2.69, 'su7': 2.57, 'type3': 3.4, 'type33': 3.77, 'type3s2': 3.55}), BoxBeamRating(beam_type='non_composite', box='B27-48', width_ft=24, n_beams=6, span=50, rating_factors={'inv': 1.55, 'op': 2.08, 'ev2': 2.65, 'ev3': 2.17, 's2f1': 4.73, 's3f1': 3.22, 's5c1': 3.26, 'spl60t': 2.97, 'spl65t': 2.31, 'su4': 2.84, 'su5': 2.57, 'su6': 2.46, 'su7': 2.29, 'type3': 3.15, 'type33': 3.29, 'type3s2': 3.11}), BoxBeamRating(beam_type='non_composite', box='B27-48', width_ft=28, n_beams=7, span=50, rating_factors={'inv': 1.62, 'op': 2.1, 'ev2': 2.68, 'ev3': 2.19, 's2f1': 4.77, 's3f1': 3.25, 's5c1': 3.29, 'spl60t': 3.0, 'spl65t': 2.33, 'su4': 2.86, 'su5': 2.59, 'su6': 2.48, 'su7': 2.39, 'type3': 3.17, 'type33': 3.32, 'type3s2': 3.14}), BoxBeamRating(beam_type='non_composite', box='B27-48', width_ft=24, n_beams=6, span=55, rating_factors={'inv': 1.38, 'op': 2.08, 'ev2': 2.83, 'ev3': 2.22, 's2f1': 4.77, 's3f1': 3.21, 's5c1': 3.29, 'spl60t': 2.92, 'spl65t': 2.53, 'su4': 2.84, 'su5': 2.61, 'su6': 2.34, 'su7': 2.16, 'type3': 3.24, 'type33': 3.61, 'type3s2': 3.35}), BoxBeamRating(beam_type='non_composite', box='B27-48', width_ft=28, n_beams=7, span=55, rating_factors={'inv': 1.43, 'op': 2.15, 'ev2': 2.93, 'ev3': 2.3, 's2f1': 4.93, 's3f1': 3.32, 's5c1': 3.4, 'spl60t': 3.02, 'spl65t': 2.61, 'su4': 2.94, 'su5': 2.7, 'su6': 2.42, 'su7': 2.24, 'type3': 3.35, 'type33': 3.73, 'type3s2': 3.46}), BoxBeamRating(beam_type='non_composite', box='B27-48', width_ft=24, n_beams=6, span=60, rating_factors={'inv': 1.4, 'op': 2.14, 'ev2': 2.97, 'ev3': 2.34, 's2f1': 5.07, 's3f1': 3.4, 's5c1': 3.45, 'spl60t': 2.86, 'spl65t': 2.33, 'su4': 3.0, 'su5': 2.74, 'su6': 2.46, 'su7': 2.26, 'type3': 3.4, 'type33': 3.41, 'type3s2': 3.23}), BoxBeamRating(beam_type='non_composite', box='B27-48', width_ft=28, n_beams=7, span=60, rating_factors={'inv': 1.45, 'op': 2.21, 'ev2': 3.0, 'ev3': 2.42, 's2f1': 5.24, 's3f1': 3.52, 's5c1': 3.45, 'spl60t': 2.9, 'spl65t': 2.33, 'su4': 3.1, 'su5': 2.83, 'su6': 2.54, 'su7': 2.34, 'type3': 3.52, 'type33': 3.42, 'type3s2': 3.23}), BoxBeamRating(beam_type='non_composite', box='B27-48', width_ft=24, n_beams=6, span=65, rating_factors={'inv': 1.39, 'op': 1.8, 'ev2': 2.44, 'ev3': 1.99, 's2f1': 4.42, 's3f1': 2.98, 's5c1': 2.67, 'spl60t': 2.24, 'spl65t': 1.82, 'su4': 2.6, 'su5': 2.33, 'su6': 2.19, 'su7': 2.07, 'type3': 2.87, 'type33': 2.64, 'type3s2': 2.55}), BoxBeamRating(beam_type='non_composite', box='B27-48', width_ft=28, n_beams=7, span=65, rating_factors={'inv': 1.39, 'op': 1.8, 'ev2': 2.44, 'ev3': 1.99, 's2f1': 4.43, 's3f1': 2.98, 's5c1': 2.67, 'spl60t': 2.24, 'spl65t': 1.83, 'su4': 2.61, 'su5': 2.34, 'su6': 2.19, 'su7': 2.08, 'type3': 2.87, 'type33': 2.65, 'type3s2': 2.55}), BoxBeamRating(beam_type='non_composite', box='B33-48', width_ft=24, n_beams=6, span=50, rating_factors={'inv': 1.63, 'op': 2.25, 'ev2': 2.96, 'ev3': 2.34, 's2f1': 4.97, 's3f1': 3.36, 's5c1': 3.44, 'spl60t': 3.03, 'spl65t': 2.57, 'su4': 2.99, 'su5': 2.76, 'su6': 2.48, 'su7': 2.3, 'type3': 3.43, 'type33': 3.67, 'type3s2': 3.47}), BoxBeamRating(beam_type='non_composite', box='B33-48', width_ft=28, n_beams=7, span=50, rating_factors={'inv': 1.69, 'op': 2.32, 'ev2': 2.96, 'ev3': 2.42, 's2f1': 5.14, 's3f1': 3.47, 's5c1': 3.56, 'spl60t': 3.13, 'spl65t': 2.57, 'su4': 3.09, 'su5': 2.85, 'su6': 2.56, 'su7': 2.37, 'type3': 3.51, 'type33': 3.67, 'type3s2': 3.47}), BoxBeamRating(beam_type='non_composite', box='B33-48', width_ft=24, n_beams=6, span=55, rating_factors={'inv': 1.45, 'op': 2.12, 'ev2': 2.88, 'ev3': 2.26, 's2f1': 4.86, 's3f1': 3.27, 's5c1': 3.34, 'spl60t': 2.97, 'spl65t': 2.57, 'su4': 2.89, 'su5': 2.66, 'su6': 2.39, 'su7': 2.2, 'type3': 3.3, 'type33': 3.68, 'type3s2': 3.41}), BoxBeamRating(beam_type='non_composite', box='B33-48', width_ft=28, n_beams=7, span=55, rating_factors={'inv': 1.5, 'op': 2.19, 'ev2': 2.98, 'ev3': 2.34, 's2f1': 5.02, 's3f1': 3.38, 's5c1': 3.46, 'spl60t': 3.07, 'spl65t': 2.66, 'su4': 2.99, 'su5': 2.75, 'su6': 2.47, 'su7': 2.27, 'type3': 3.41, 'type33': 3.8, 'type3s2': 3.52}), BoxBeamRating(beam_type='non_composite', box='B33-48', width_ft=24, n_beams=6, span=60, rating_factors={'inv': 1.63, 'op': 2.12, 'ev2': 2.8, 'ev3': 2.29, 's2f1': 5.05, 's3f1': 3.42, 's5c1': 3.27, 'spl60t': 2.75, 'spl65t': 2.2, 'su4': 2.99, 'su5': 2.69, 'su6': 2.55, 'su7': 2.43, 'type3': 3.31, 'type33': 3.22, 'type3s2': 3.04}), BoxBeamRating(beam_type='non_composite', box='B33-48', width_ft=28, n_beams=7, span=60, rating_factors={'inv': 1.63, 'op': 2.12, 'ev2': 2.8, 'ev3': 2.29, 's2f1': 5.06, 's3f1': 3.42, 's5c1': 3.27, 'spl60t': 2.75, 'spl65t': 2.2, 'su4': 3.0, 'su5': 2.7, 'su6': 2.55, 'su7': 2.43, 'type3': 3.31, 'type33': 3.22, 'type3s2': 3.04}), BoxBeamRating(beam_type='non_composite', box='B33-48', width_ft=24, n_beams=6, span=65, rating_factors={'inv': 1.43, 'op': 2.16, 'ev2': 2.89, 'ev3': 2.36, 's2f1': 5.23, 's3f1': 3.53, 's5c1': 3.27, 'spl60t': 2.75, 'spl65t': 2.22, 'su4': 3.09, 'su5': 2.78, 'su6': 2.58, 'su7': 2.36, 'type3': 3.41, 'type33': 3.23, 'type3s2': 3.08}), BoxBeamRating(beam_type='non_composite', box='B33-48', width_ft=28, n_beams=7, span=65, rating_factors={'inv': 1.47, 'op': 2.15, 'ev2': 2.87, 'ev3': 2.34, 's2f1': 5.19, 's3f1': 3.51, 's5c1': 3.25, 'spl60t': 2.73, 'spl65t': 2.21, 'su4': 3.07, 'su5': 2.76, 'su6': 2.6, 'su7': 2.42, 'type3': 3.38, 'type33': 3.2, 'type3s2': 3.06}), BoxBeamRating(beam_type='non_composite', box='B33-48', width_ft=24, n_beams=6, span=70, rating_factors={'inv': 1.48, 'op': 1.94, 'ev2': 2.67, 'ev3': 2.18, 's2f1': 4.87, 's3f1': 3.27, 's5c1': 2.81, 'spl60t': 2.35, 'spl65t': 1.94, 'su4': 2.85, 'su5': 2.55, 'su6': 2.39, 'su7': 2.25, 'type3': 3.14, 'type33': 2.79, 'type3s2': 2.73}), BoxBeamRating(beam_type='non_composite', box='B33-48', width_ft=28, n_beams=7, span=70, rating_factors={'inv': 1.5, 'op': 1.94, 'ev2': 2.67, 'ev3': 2.18, 's2f1': 4.87, 's3f1': 3.28, 's5c1': 2.81, 'spl60t': 2.36, 'spl65t': 1.94, 'su4': 2.86, 'su5': 2.55, 'su6': 2.39, 'su7': 2.25, 'type3': 3.14, 'type33': 2.79, 'type3s2': 2.73}), BoxBeamRating(beam_type='non_composite', box='B33-48', width_ft=24, n_beams=6, span=75, rating_factors={'inv': 1.34, 'op': 1.73, 'ev2': 2.42, 'ev3': 1.97, 's2f1': 4.43, 's3f1': 2.97, 's5c1': 2.46, 'spl60t': 2.04, 'spl65t': 1.71, 'su4': 2.59, 'su5': 2.31, 'su6': 2.15, 'su7': 2.02, 'type3': 2.84, 'type33': 2.44, 'type3s2': 2.42}), BoxBeamRating(beam_type='non_composite', box='B33-48', width_ft=28, n_beams=7, span=75, rating_factors={'inv': 1.34, 'op': 1.73, 'ev2': 2.43, 'ev3': 1.97, 's2f1': 4.44, 's3f1': 2.98, 's5c1': 2.46, 'spl60t': 2.04, 'spl65t': 1.71, 'su4': 2.59, 'su5': 2.31, 'su6': 2.15, 'su7': 2.02, 'type3': 2.84, 'type33': 2.44, 'type3s2': 2.42}), BoxBeamRating(beam_type='non_composite', box='B33-48', width_ft=24, n_beams=6, span=80, rating_factors={'inv': 1.24, 'op': 1.61, 'ev2': 2.28, 'ev3': 1.85, 's2f1': 4.18, 's3f1': 2.8, 's5c1': 2.25, 'spl60t': 1.85, 'spl65t': 1.58, 'su4': 2.43, 'su5': 2.17, 'su6': 2.01, 'su7': 1.88, 'type3': 2.67, 'type33': 2.24, 'type3s2': 2.24}), BoxBeamRating(beam_type='non_composite', box='B33-48', width_ft=28, n_beams=7, span=80, rating_factors={'inv': 1.24, 'op': 1.61, 'ev2': 2.28, 'ev3': 1.86, 's2f1': 4.18, 's3f1': 2.8, 's5c1': 2.25, 'spl60t': 1.86, 'spl65t': 1.58, 'su4': 2.43, 'su5': 2.17, 'su6': 2.01, 'su7': 1.88, 'type3': 2.67, 'type33': 2.24, 'type3s2': 2.24}), BoxBeamRating(beam_type='non_composite', box='B42-48', width_ft=24, n_beams=6, span=65, rating_factors={'inv': 1.64, 'op': 2.43, 'ev2': 3.43, 'ev3': 2.71, 's2f1': 5.92, 's3f1': 3.96, 's5c1': 4.03, 'spl60t': 3.35, 'spl65t': 2.77, 'su4': 3.48, 'su5': 3.17, 'su6': 2.84, 'su7': 2.6, 'type3': 3.93, 'type33': 3.99, 'type3s2': 3.74}), BoxBeamRating(beam_type='non_composite', box='B42-48', width_ft=28, n_beams=7, span=65, rating_factors={'inv': 1.7, 'op': 2.51, 'ev2': 3.55, 'ev3': 2.8, 's2f1': 6.11, 's3f1': 4.09, 's5c1': 4.17, 'spl60t': 3.46, 'spl65t': 2.86, 'su4': 3.6, 'su5': 3.27, 'su6': 2.93, 'su7': 2.69, 'type3': 4.06, 'type33': 4.12, 'type3s2': 3.87}), BoxBeamRating(beam_type='non_composite', box='B42-48', width_ft=24, n_beams=6, span=70, rating_factors={'inv': 1.54, 'op': 2.37, 'ev2': 3.41, 'ev3': 2.7, 's2f1': 5.93, 's3f1': 3.96, 's5c1': 3.89, 'spl60t': 3.36, 'spl65t': 2.65, 'su4': 3.47, 'su5': 3.15, 'su6': 2.82, 'su7': 2.58, 'type3': 3.91, 'type33': 3.81, 'type3s2': 3.6}), BoxBeamRating(beam_type='non_composite', box='B42-48', width_ft=28, n_beams=7, span=70, rating_factors={'inv': 1.58, 'op': 2.43, 'ev2': 3.49, 'ev3': 2.76, 's2f1': 6.07, 's3f1': 4.06, 's5c1': 3.98, 'spl60t': 3.44, 'spl65t': 2.71, 'su4': 3.56, 'su5': 3.22, 'su6': 2.89, 'su7': 2.65, 'type3': 4.0, 'type33': 3.9, 'type3s2': 3.69}), BoxBeamRating(beam_type='non_composite', box='B42-48', width_ft=24, n_beams=6, span=75, rating_factors={'inv': 1.43, 'op': 2.29, 'ev2': 3.35, 'ev3': 2.65, 's2f1': 5.86, 's3f1': 3.91, 's5c1': 3.59, 'spl60t': 2.99, 'spl65t': 2.5, 'su4': 3.42, 'su5': 3.09, 'su6': 2.77, 'su7': 2.53, 'type3': 3.83, 'type33': 3.56, 'type3s2': 3.45}), BoxBeamRating(beam_type='non_composite', box='B42-48', width_ft=28, n_beams=7, span=75, rating_factors={'inv': 1.49, 'op': 2.37, 'ev2': 3.46, 'ev3': 2.74, 's2f1': 6.06, 's3f1': 4.04, 's5c1': 3.59, 'spl60t': 2.99, 'spl65t': 2.5, 'su4': 3.54, 'su5': 3.19, 'su6': 2.86, 'su7': 2.62, 'type3': 3.96, 'type33': 3.56, 'type3s2': 3.53}), BoxBeamRating(beam_type='non_composite', box='B42-48', width_ft=24, n_beams=6, span=80, rating_factors={'inv': 1.43, 'op': 2.38, 'ev2': 3.38, 'ev3': 2.75, 's2f1': 6.2, 's3f1': 4.15, 's5c1': 3.34, 'spl60t': 2.75, 'spl65t': 2.34, 'su4': 3.61, 'su5': 3.21, 'su6': 2.94, 'su7': 2.68, 'type3': 3.95, 'type33': 3.32, 'type3s2': 3.32}), BoxBeamRating(beam_type='non_composite', box='B42-48', width_ft=28, n_beams=7, span=80, rating_factors={'inv': 1.48, 'op': 2.38, 'ev2': 3.38, 'ev3': 2.75, 's2f1': 6.2, 's3f1': 4.15, 's5c1': 3.34, 'spl60t': 2.75, 'spl65t': 2.34, 'su4': 3.61, 'su5': 3.22, 'su6': 2.99, 'su7': 2.78, 'type3': 3.96, 'type33': 3.32, 'type3s2': 3.32}), BoxBeamRating(beam_type='non_composite', box='B42-48', width_ft=24, n_beams=6, span=85, rating_factors={'inv': 1.51, 'op': 2.24, 'ev2': 3.22, 'ev3': 2.62, 's2f1': 5.92, 's3f1': 3.96, 's5c1': 3.11, 'spl60t': 2.53, 'spl65t': 2.19, 'su4': 3.43, 'su5': 3.06, 'su6': 2.83, 'su7': 2.64, 'type3': 3.76, 'type33': 3.09, 'type3s2': 3.12}), BoxBeamRating(beam_type='non_composite', box='B42-48', width_ft=28, n_beams=7, span=85, rating_factors={'inv': 1.56, 'op': 2.24, 'ev2': 3.22, 'ev3': 2.62, 's2f1': 5.93, 's3f1': 3.96, 's5c1': 3.11, 'spl60t': 2.54, 'spl65t': 2.19, 'su4': 3.44, 'su5': 3.06, 'su6': 2.83, 'su7': 2.64, 'type3': 3.77, 'type33': 3.09, 'type3s2': 3.12}), BoxBeamRating(beam_type='non_composite', box='B42-48', width_ft=24, n_beams=6, span=90, rating_factors={'inv': 1.54, 'op': 2.13, 'ev2': 3.1, 'ev3': 2.52, 's2f1': 5.72, 's3f1': 3.82, 's5c1': 2.94, 'spl60t': 2.38, 'spl65t': 2.07, 'su4': 3.31, 'su5': 2.94, 'su6': 2.72, 'su7': 2.53, 'type3': 3.63, 'type33': 2.92, 'type3s2': 2.97}), BoxBeamRating(beam_type='non_composite', box='B42-48', width_ft=28, n_beams=7, span=90, rating_factors={'inv': 1.6, 'op': 2.13, 'ev2': 2.92, 'ev3': 2.38, 's2f1': 5.39, 's3f1': 3.6, 's5c1': 2.76, 'spl60t': 2.24, 'spl65t': 1.95, 'su4': 3.12, 'su5': 2.77, 'su6': 2.56, 'su7': 2.38, 'type3': 3.41, 'type33': 2.75, 'type3s2': 2.79}), BoxBeamRating(beam_type='non_composite', box='B17-48', width_ft=32, n_beams=8, span=20, rating_factors={'inv': 1.94, 'op': 2.52, 'ev2': 3.19, 'ev3': 2.49, 's2f1': 4.7, 's3f1': 3.57, 's5c1': 3.75, 'spl60t': 4.02, 'spl65t': 3.76, 'su4': 3.31, 'su5': 3.12, 'su6': 3.12, 'su7': 3.12, 'type3': 3.75, 'type33': 4.56, 'type3s2': 4.02}), BoxBeamRating(beam_type='non_composite', box='B17-48', width_ft=32, n_beams=8, span=25, rating_factors={'inv': 1.79, 'op': 2.32, 'ev2': 2.72, 'ev3': 2.28, 's2f1': 4.3, 's3f1': 3.14, 's5c1': 3.25, 'spl60t': 3.58, 'spl65t': 3.32, 'su4': 2.93, 'su5': 2.78, 'su6': 2.81, 'su7': 2.81, 'type3': 3.42, 'type33': 4.26, 'type3s2': 3.53}), BoxBeamRating(beam_type='non_composite', box='B17-48', width_ft=32, n_beams=8, span=30, rating_factors={'inv': 1.54, 'op': 2.0, 'ev2': 2.26, 'ev3': 1.87, 's2f1': 3.71, 's3f1': 2.65, 's5c1': 2.73, 'spl60t': 3.05, 'spl65t': 2.76, 'su4': 2.43, 'su5': 2.31, 'su6': 2.35, 'su7': 2.35, 'type3': 2.78, 'type33': 3.39, 'type3s2': 2.98}), BoxBeamRating(beam_type='non_composite', box='B17-48', width_ft=32, n_beams=8, span=35, rating_factors={'inv': 1.41, 'op': 1.83, 'ev2': 2.09, 'ev3': 1.73, 's2f1': 3.53, 's3f1': 2.48, 's5c1': 2.54, 'spl60t': 2.87, 'spl65t': 2.56, 'su4': 2.24, 'su5': 2.1, 'su6': 2.14, 'su7': 2.15, 'type3': 2.54, 'type33': 3.05, 'type3s2': 2.79}), BoxBeamRating(beam_type='non_composite', box='B21-48', width_ft=32, n_beams=8, span=30, rating_factors={'inv': 1.94, 'op': 2.51, 'ev2': 2.84, 'ev3': 2.36, 's2f1': 4.68, 's3f1': 3.34, 's5c1': 3.44, 'spl60t': 3.85, 'spl65t': 3.48, 'su4': 3.06, 'su5': 2.91, 'su6': 2.96, 'su7': 2.96, 'type3': 3.5, 'type33': 4.26, 'type3s2': 3.76}), BoxBeamRating(beam_type='non_composite', box='B21-48', width_ft=32, n_beams=8, span=35, rating_factors={'inv': 1.5, 'op': 1.95, 'ev2': 2.29, 'ev3': 1.89, 's2f1': 3.94, 's3f1': 2.74, 's5c1': 2.8, 'spl60t': 3.16, 'spl65t': 2.82, 'su4': 2.46, 'su5': 2.28, 'su6': 2.27, 'su7': 2.27, 'type3': 2.76, 'type33': 3.29, 'type3s2': 3.08}), BoxBeamRating(beam_type='non_composite', box='B21-48', width_ft=32, n_beams=8, span=40, rating_factors={'inv': 1.29, 'op': 1.67, 'ev2': 3.54, 'ev3': 2.44, 's2f1': 2.49, 's3f1': 2.81, 's5c1': 2.5, 'spl60t': 2.81, 'spl65t': 2.5, 'su4': 2.17, 'su5': 1.99, 'su6': 1.95, 'su7': 1.94, 'type3': 2.43, 'type33': 2.84, 'type3s2': 2.66}), BoxBeamRating(beam_type='non_composite', box='B21-48', width_ft=32, n_beams=8, span=45, rating_factors={'inv': 1.44, 'op': 1.86, 'ev2': 2.26, 'ev3': 1.86, 's2f1': 3.95, 's3f1': 2.73, 's5c1': 2.77, 'spl60t': 3.01, 'spl65t': 2.67, 'su4': 2.43, 'su5': 2.23, 'su6': 2.18, 'su7': 2.17, 'type3': 2.71, 'type33': 3.17, 'type3s2': 2.97}), BoxBeamRating(beam_type='non_composite', box='B21-48', width_ft=32, n_beams=8, span=50, rating_factors={'inv': 1.34, 'op': 1.76, 'ev2': 2.18, 'ev3': 1.79, 's2f1': 3.85, 's3f1': 2.64, 's5c1': 2.68, 'spl60t': 2.75, 'spl65t': 2.44, 'su4': 2.34, 'su5': 2.13, 'su6': 2.06, 'su7': 2.02, 'type3': 2.6, 'type33': 2.91, 'type3s2': 2.73}), BoxBeamRating(beam_type='non_composite', box='B27-48', width_ft=32, n_beams=8, span=40, rating_factors={'inv': 1.89, 'op': 2.46, 'ev2': 2.98, 'ev3': 2.45, 's2f1': 5.21, 's3f1': 3.59, 's5c1': 3.66, 'spl60t': 3.51, 'spl65t': 3.12, 'su4': 3.2, 'su5': 2.93, 'su6': 2.87, 'su7': 2.85, 'type3': 3.57, 'type33': 4.18, 'type3s2': 3.92}), BoxBeamRating(beam_type='non_composite', box='B27-48', width_ft=32, n_beams=8, span=45, rating_factors={'inv': 1.76, 'op': 2.29, 'ev2': 2.85, 'ev3': 2.34, 's2f1': 5.04, 's3f1': 3.45, 's5c1': 3.51, 'spl60t': 3.21, 'spl65t': 2.67, 'su4': 3.06, 'su5': 2.78, 'su6': 2.69, 'su7': 2.63, 'type3': 3.4, 'type33': 3.77, 'type3s2': 3.55}), BoxBeamRating(beam_type='non_composite', box='B27-48', width_ft=32, n_beams=8, span=50, rating_factors={'inv': 1.62, 'op': 2.1, 'ev2': 2.68, 'ev3': 2.19, 's2f1': 4.77, 's3f1': 3.25, 's5c1': 3.29, 'spl60t': 3.0, 'spl65t': 2.33, 'su4': 2.86, 'su5': 2.59, 'su6': 2.48, 'su7': 2.4, 'type3': 3.17, 'type33': 3.32, 'type3s2': 3.14}), BoxBeamRating(beam_type='non_composite', box='B27-48', width_ft=32, n_beams=8, span=55, rating_factors={'inv': 1.47, 'op': 2.22, 'ev2': 3.01, 'ev3': 2.36, 's2f1': 5.07, 's3f1': 3.42, 's5c1': 3.49, 'spl60t': 3.1, 'spl65t': 2.69, 'su4': 3.02, 'su5': 2.78, 'su6': 2.49, 'su7': 2.3, 'type3': 3.45, 'type33': 3.84, 'type3s2': 3.56}), BoxBeamRating(beam_type='non_composite', box='B27-48', width_ft=32, n_beams=8, span=60, rating_factors={'inv': 1.49, 'op': 2.26, 'ev2': 3.0, 'ev3': 2.45, 's2f1': 5.39, 's3f1': 3.62, 's5c1': 3.46, 'spl60t': 2.9, 'spl65t': 2.34, 'su4': 3.19, 'su5': 2.88, 'su6': 2.61, 'su7': 2.4, 'type3': 3.54, 'type33': 3.42, 'type3s2': 3.23}), BoxBeamRating(beam_type='non_composite', box='B27-48', width_ft=32, n_beams=8, span=65, rating_factors={'inv': 1.39, 'op': 1.8, 'ev2': 2.44, 'ev3': 1.99, 's2f1': 4.43, 's3f1': 2.99, 's5c1': 2.67, 'spl60t': 2.24, 'spl65t': 1.83, 'su4': 2.61, 'su5': 2.34, 'su6': 2.2, 'su7': 2.08, 'type3': 2.87, 'type33': 2.65, 'type3s2': 2.55}), BoxBeamRating(beam_type='non_composite', box='B33-48', width_ft=32, n_beams=8, span=50, rating_factors={'inv': 1.74, 'op': 2.32, 'ev2': 2.96, 'ev3': 2.42, 's2f1': 5.28, 's3f1': 3.57, 's5c1': 3.65, 'spl60t': 3.22, 'spl65t': 2.58, 'su4': 3.17, 'su5': 2.87, 'su6': 2.64, 'su7': 2.44, 'type3': 3.51, 'type33': 3.67, 'type3s2': 3.47}), BoxBeamRating(beam_type='non_composite', box='B33-48', width_ft=32, n_beams=8, span=55, rating_factors={'inv': 1.54, 'op': 2.25, 'ev2': 3.07, 'ev3': 2.41, 's2f1': 5.16, 's3f1': 3.48, 's5c1': 3.56, 'spl60t': 3.16, 'spl65t': 2.73, 'su4': 3.08, 'su5': 2.83, 'su6': 2.54, 'su7': 2.34, 'type3': 3.51, 'type33': 3.91, 'type3s2': 3.62}), BoxBeamRating(beam_type='non_composite', box='B33-48', width_ft=32, n_beams=8, span=60, rating_factors={'inv': 1.64, 'op': 2.12, 'ev2': 2.81, 'ev3': 2.29, 's2f1': 5.06, 's3f1': 3.42, 's5c1': 3.28, 'spl60t': 2.75, 'spl65t': 2.21, 'su4': 3.0, 'su5': 2.7, 'su6': 2.55, 'su7': 2.43, 'type3': 3.31, 'type33': 3.22, 'type3s2': 3.05}), BoxBeamRating(beam_type='non_composite', box='B33-48', width_ft=32, n_beams=8, span=65, rating_factors={'inv': 1.53, 'op': 2.17, 'ev2': 2.89, 'ev3': 2.36, 's2f1': 5.24, 's3f1': 3.54, 's5c1': 3.28, 'spl60t': 2.75, 'spl65t': 2.23, 'su4': 3.09, 'su5': 2.78, 'su6': 2.62, 'su7': 2.49, 'type3': 3.41, 'type33': 3.23, 'type3s2': 3.09}), BoxBeamRating(beam_type='non_composite', box='B33-48', width_ft=32, n_beams=8, span=70, rating_factors={'inv': 1.5, 'op': 1.95, 'ev2': 2.68, 'ev3': 2.18, 's2f1': 4.88, 's3f1': 3.28, 's5c1': 2.81, 'spl60t': 2.36, 'spl65t': 1.94, 'su4': 2.86, 'su5': 2.56, 'su6': 2.39, 'su7': 2.25, 'type3': 3.14, 'type33': 2.79, 'type3s2': 2.73}), BoxBeamRating(beam_type='non_composite', box='B33-48', width_ft=32, n_beams=8, span=75, rating_factors={'inv': 1.59, 'op': 2.5, 'ev2': 3.49, 'ev3': 2.84, 's2f1': 6.39, 's3f1': 4.28, 's5c1': 3.54, 'spl60t': 2.94, 'spl65t': 2.46, 'su4': 3.73, 'su5': 3.33, 'su6': 3.03, 'su7': 2.77, 'type3': 4.1, 'type33': 3.51, 'type3s2': 3.49}), BoxBeamRating(beam_type='non_composite', box='B33-48', width_ft=32, n_beams=8, span=80, rating_factors={'inv': 1.24, 'op': 1.61, 'ev2': 2.28, 'ev3': 1.86, 's2f1': 4.19, 's3f1': 2.8, 's5c1': 2.26, 'spl60t': 1.86, 'spl65t': 1.58, 'su4': 2.44, 'su5': 2.17, 'su6': 2.02, 'su7': 1.89, 'type3': 2.67, 'type33': 2.24, 'type3s2': 2.24}), BoxBeamRating(beam_type='non_composite', box='B42-48', width_ft=32, n_beams=8, span=65, rating_factors={'inv': 1.75, 'op': 2.58, 'ev2': 3.65, 'ev3': 2.88, 's2f1': 6.29, 's3f1': 4.21, 's5c1': 4.29, 'spl60t': 3.56, 'spl65t': 2.94, 'su4': 3.7, 'su5': 3.37, 'su6': 3.02, 'su7': 2.77, 'type3': 4.18, 'type33': 4.24, 'type3s2': 3.98}), BoxBeamRating(beam_type='non_composite', box='B42-48', width_ft=32, n_beams=8, span=70, rating_factors={'inv': 1.65, 'op': 2.52, 'ev2': 3.63, 'ev3': 2.87, 's2f1': 6.31, 's3f1': 4.21, 's5c1': 4.14, 'spl60t': 3.48, 'spl65t': 2.82, 'su4': 3.69, 'su5': 3.35, 'su6': 3.0, 'su7': 2.75, 'type3': 4.16, 'type33': 4.05, 'type3s2': 3.83}), BoxBeamRating(beam_type='non_composite', box='B42-48', width_ft=32, n_beams=8, span=75, rating_factors={'inv': 1.53, 'op': 2.44, 'ev2': 3.53, 'ev3': 2.82, 's2f1': 6.24, 's3f1': 4.16, 's5c1': 3.59, 'spl60t': 2.99, 'spl65t': 2.5, 'su4': 3.64, 'su5': 3.29, 'su6': 2.94, 'su7': 2.69, 'type3': 4.08, 'type33': 3.57, 'type3s2': 3.53}), BoxBeamRating(beam_type='non_composite', box='B42-48', width_ft=32, n_beams=8, span=80, rating_factors={'inv': 1.53, 'op': 2.39, 'ev2': 3.38, 'ev3': 2.75, 's2f1': 6.21, 's3f1': 4.16, 's5c1': 3.35, 'spl60t': 2.75, 'spl65t': 2.34, 'su4': 3.61, 'su5': 3.22, 'su6': 2.99, 'su7': 2.8, 'type3': 3.96, 'type33': 3.32, 'type3s2': 3.33}), BoxBeamRating(beam_type='non_composite', box='B42-48', width_ft=32, n_beams=8, span=85, rating_factors={'inv': 1.61, 'op': 2.24, 'ev2': 3.22, 'ev3': 2.62, 's2f1': 5.93, 's3f1': 3.97, 's5c1': 3.11, 'spl60t': 2.54, 'spl65t': 2.19, 'su4': 3.44, 'su5': 3.06, 'su6': 2.84, 'su7': 2.64, 'type3': 3.77, 'type33': 3.09, 'type3s2': 3.12}), BoxBeamRating(beam_type='non_composite', box='B42-48', width_ft=32, n_beams=8, span=90, rating_factors={'inv': 1.64, 'op': 2.13, 'ev2': 3.11, 'ev3': 2.53, 's2f1': 5.74, 's3f1': 3.83, 's5c1': 2.94, 'spl60t': 2.38, 'spl65t': 2.08, 'su4': 3.32, 'su5': 2.95, 'su6': 2.73, 'su7': 2.53, 'type3': 3.63, 'type33': 2.93, 'type3s2': 2.98})]

All box-beam load ratings (PSBDD-1-25 sheets 2 & 4).

civilpy.structural.odot.box_beam_design.BOX_DESIGNATIONS: tuple[str, ...] = ('CB17-48', 'CB21-48', 'CB27-48', 'CB33-48', 'CB42-48', 'B17-48', 'B21-48', 'B27-48', 'B33-48', 'B42-48')

Standard box designations (e.g. "CB27-48", "B27-48").

class civilpy.structural.odot.box_beam_design.BoxBeamDesign(beam_type: str, box: str, depth: int, width: int, span: int, e_beam: float, e_composite: float | None, n_strands: int, strands_2in: int, strands_4in: int, strands_6in: int, stirrup_w_pairs: int, stirrup_zone_x: float, stirrup_y: float, stirrup_z: float, camber_d0: float, camber_d30: float, deflection: float, bearing_type: str)[source]

Bases: object

One standard box-beam design line (PSBDD-1-25 sheets 1 & 3).

e_composite is None for non-composite beams. strands_2in / strands_4in / strands_6in are the strand counts in the rows 2, 4, and 6 in above the soffit (their sum is n_strands). Camber values are at release (camber_d0) and erection (camber_d30); deflection is the residual midspan deflection under remaining dead load. All lengths in inches.

beam_type: str
bearing_type: str
box: str
camber_d0: float
camber_d30: float
deflection: float
depth: int
e_beam: float
e_composite: float | None
n_strands: int
span: int
stirrup_w_pairs: int
stirrup_y: float
stirrup_z: float
stirrup_zone_x: float
strands_2in: int
strands_4in: int
strands_6in: int
width: int
class civilpy.structural.odot.box_beam_design.BoxBeamRating(beam_type: str, box: str, width_ft: int, n_beams: int, span: int, rating_factors: dict[str, float]=<factory>)[source]

Bases: object

LRFR rating factors for one box / span / bridge width (PSBDD-1-25 sheets 2 & 4). rating_factors is keyed by RATING_VEHICLES.

beam_type: str
box: str
property inventory: float

HL-93 inventory rating factor.

n_beams: int
property operating: float

HL-93 operating rating factor.

rating_factors: dict[str, float]
span: int
width_ft: int
civilpy.structural.odot.box_beam_design.RATING_VEHICLES: tuple[str, ...] = ('inv', 'op', 'ev2', 'ev3', 's2f1', 's3f1', 's5c1', 'spl60t', 'spl65t', 'su4', 'su5', 'su6', 'su7', 'type3', 'type33', 'type3s2')

Rating vehicles in the order tabulated on PSBDD-1-25 (keys into BoxBeamRating.rating_factors).

civilpy.structural.odot.box_beam_design.STRAND_ROW_HEIGHTS_IN: tuple[float, float, float] = (2.0, 4.0, 6.0)

Strand row heights above the soffit, inches (PSBDD-1-25 sheets 1 & 3).

civilpy.structural.odot.box_beam_design.box_beam_design(box: str, span: int) BoxBeamDesign[source]

The design line for a box designation and span in feet.

civilpy.structural.odot.box_beam_design.box_beam_rating(box: str, span: int, width_ft: int) BoxBeamRating[source]

The load rating for a box, span (ft), and bridge width (24/28/32 ft).

civilpy.structural.odot.box_beam_design.designs_for_box(box: str) list[BoxBeamDesign][source]

All span designs for one box designation, shortest span first.

civilpy.structural.odot.box_beam_design.strand_group_height_in(design: BoxBeamDesign) float[source]

Height of the strand-group centroid above the soffit (in), the strand-count-weighted average of the 2/4/6 in row heights. A schematic single-height tendon path uses this; it is consistent with (Yb of the matching BoxSectionProperties) minus design.e_beam to within drawing rounding.

civilpy.structural.odot.box_culvert_headwall module

Ohio DOT precast box culvert headwall / wingwall plan insert (BCHW).

Transcribed from the Ohio DOT “BCHW” plan insert (rev. 01-21-2022, 8 sheets: culvert & wingwall layout, wingwall elevation + foreslope wall + footing plan + sections, and several “SUBSET” sheets of alternate wingwall corner configurations). The drawing remains the controlling document.

BCHW is a detailing template, not a dimensioned standard. Unlike every other SCD this package catalogs, none of its geometry is tabulated: every dimension on the sheet (wall height H, footing offsets a/b/c, foreslope-wall height hf, cutoff-wall height hcw, footing width Wf, box wall thickness t box, wingwall length L, bar spacings) is drawn as * or a blank @ _ c/c for the project engineer to fill in from the actual box culvert design – the sheet says so explicitly (“INSERT ODOT BOX CULVERT REINFORCING DESIGN HERE IF SPAN > 12’.”). There is therefore no guarded catalog lookup here: layout_wingwall() takes every dimension as a required input (no defaults, nothing to look up) and only performs the geometry the sheet’s own sections make unambiguous (civilpy.structural.odot’s ASTM C1577 precast box section catalog, if/when encoded, is a separate concern – BCHW is the cast-in-place wingwall/foreslope-wall wrap-around, not the precast box itself).

What is cataloged here: the general notes (payment items, waterproofing, porous backfill, weepholes, PEJF, lap splice lengths, epoxy coating) and the eight standard rebar bend shapes (TYPE-1 .. TYPE-8) the bar list (WW5xx wingwall, FS5xx foreslope wall, F6xx footing, Z/V/W/X/Y series) references – bend_shape() turns a type + the project-supplied leg lengths into a bend polyline, the same “shape template, project-supplied legs” split as the sheet itself.

civilpy.structural.odot.box_culvert_headwall.BOX_SPAN_RANGE_FT = (8.0, 20.0)

precast spans 8-20 ft in 2 ft increments, rises 4-10 ft in 1 ft increments; ASTM C1433 covers spans to 12 ft, larger spans need an OSE box design.

Type:

Culvert size limits (sheet 1/6)

civilpy.structural.odot.box_culvert_headwall.CUTOFF_WALL_WIDTH_FT = 1.5

1’-6” cutoff wall (Section B-B)

civilpy.structural.odot.box_culvert_headwall.FOOTING_EXTENSION_FT = 4.0

“4’-0” (MIN.)” footing run past the wall

civilpy.structural.odot.box_culvert_headwall.FOOTING_REINFORCING = {1: ((5, 18.0), (5, 18.0)), 2: ((5, 15.0), (5, 18.0)), 3: ((5, 12.0), (5, 18.0)), 4: ((5, 18.0), (5, 12.0)), 5: ((5, 15.0), (5, 9.0)), 6: ((6, 18.0), (6, 18.0)), 7: ((6, 18.0), (6, 18.0)), 8: ((6, 9.0), (6, 12.0))}

“V” transverse bars and “W”/”Z” longitudinal / cutoff bars per footing design number.

Type:

Footing reinforcing (sheet 6/6)

civilpy.structural.odot.box_culvert_headwall.FORESLOPE_WALL_HEIGHTS_IN = (6.0, 18.0)

Foreslope wall height above the top of the culvert (sheet 1/6): 6 in or 1’-6” only.

civilpy.structural.odot.box_culvert_headwall.FORESLOPE_WALL_QUANTITIES = {(1.0, 6.0): (6.7, 0.02), (1.0, 18.0): (10.87, 0.06), (1.25, 6.0): (7.22, 0.03), (1.25, 18.0): (11.39, 0.07)}

(width b ft, height in) -> (reinf lbs/ft, conc cy/ft); multiply by box span + 2 (t box, wall).

Type:

Foreslope wall quantities (sheet 6/6)

class civilpy.structural.odot.box_culvert_headwall.HeadwallDesign(inputs: HeadwallInput, H: float, H_required: float, t_wall_in: float, row: HeadwallRow, v_bar: tuple[int, float], wz_bar: tuple[int, float], foreslope_lbs_per_ft: float, foreslope_cy_per_ft: float)[source]

Bases: object

The resolved design: the table row plus the derived dimensions.

H: float
H_required: float
foreslope_cy_per_ft: float
foreslope_lbs_per_ft: float
inputs: HeadwallInput
row: HeadwallRow
t_wall_in: float
v_bar: tuple[int, float]
wz_bar: tuple[int, float]
class civilpy.structural.odot.box_culvert_headwall.HeadwallInput(headwall_type: Literal['A', 'B', 'C'], box_span_ft: float, box_rise_ft: float, box_slab_thickness_in: float = 10.0, roadway_skew_deg: float = 0.0, foreslope_wall_height_in: float = 6.0)[source]

Bases: object

Design inputs for one culvert-end headwall assembly (Design Data sheets), resolved against the tables by design_headwall().

box_rise_ft: float

Box clear rise, ft — tabulated 4-10 in 1 ft increments (BOX_RISE_RANGE_FT).

box_slab_thickness_in: float = 10.0

Box top/bottom slab thickness, in (from the box design); feeds H = rise + 2 slab + foreslope height.

box_span_ft: float

Box clear span, ft — tabulated 8-20 in 2 ft increments (BOX_SPAN_RANGE_FT).

foreslope_wall_height_in: float = 6.0

Foreslope wall height above the top of the culvert, in — the sheet allows 6 or 18 only (FORESLOPE_WALL_HEIGHTS_IN).

headwall_type: Literal['A', 'B', 'C']

"A" when the culvert is normal to the roadway (both wingwalls at 45 deg), "B" for roadway skews of 0/15/30/45 deg (one 45 deg wingwall + one straight), "C" only where site constraints keep both wingwalls parallel to the roadway.

Type:

Sheet 1/6 selection

roadway_skew_deg: float = 0.0

Roadway skew theta, deg. Type B is tabulated for TYPE_B_SKEWS (0/15/30/45) only.

class civilpy.structural.odot.box_culvert_headwall.HeadwallRow(H: float, footing_design: int, L1: float, L2: float, h1: float, h2: float, footing_w: float, footing_t: float, hcw: float, a: float, b: float, x_bar: int, x_spa_in: float, y_bar: int, y_spa_in: float, c: float, wingwall_conc_cy: float, wingwall_reinf_lbs: float, footing_conc_cy: float, footing_reinf_lbs: float, culvert_footing_cy_per_ft: float, culvert_footing_lbs_per_ft: float)[source]

Bases: object

One design-height row of a Type A/B/C table (sheets 2/6-5/6).

Lengths and heights in feet, bar spacings in inches, quantities as printed: wingwall/footing concrete in cy and reinforcing in lbs are whole-assembly (both wingwalls); culvert-footing values are per lineal foot, to be multiplied by box span + 2 (t box, wall).

H: float
L1: float
L2: float
a: float
b: float
c: float
culvert_footing_cy_per_ft: float
culvert_footing_lbs_per_ft: float
footing_conc_cy: float
footing_design: int
footing_reinf_lbs: float
footing_t: float
footing_w: float
h1: float
h2: float
hcw: float
wingwall_conc_cy: float
wingwall_reinf_lbs: float
x_bar: int
x_spa_in: float
y_bar: int
y_spa_in: float
civilpy.structural.odot.box_culvert_headwall.PAY_ITEMS = {'sealing_concrete_surfaces': ('512', '46000', 'SQ. YD.'), 'structure_removed': ('202', '11000', 'LUMP'), 'unclassified_excavation': ('503', '21100', 'LUMP'), 'unclassified_excavation_wingwall_footing': ('503', '11100', 'LUMP')}

Payment items (note block, “TOTALS CARRIED TO GENERAL SUMMARY SHEET”).

civilpy.structural.odot.box_culvert_headwall.TYPE_A_TABLE = (HeadwallRow(H=6.5, footing_design=1, L1=7.25, L2=7.25, h1=4.0, h2=4.0, footing_w=4.5, footing_t=1.5, hcw=2.5, a=1.1666666666666667, b=1.0, x_bar=5, x_spa_in=18.0, y_bar=5, y_spa_in=18.0, c=2.4166666666666665, wingwall_conc_cy=3.02, wingwall_reinf_lbs=446, footing_conc_cy=6.0, footing_reinf_lbs=598, culvert_footing_cy_per_ft=0.43, culvert_footing_lbs_per_ft=24.55), HeadwallRow(H=7.5, footing_design=1, L1=8.5, L2=8.5, h1=4.5, h2=4.5, footing_w=5.0, footing_t=1.5, hcw=2.5, a=1.5, b=1.0, x_bar=5, x_spa_in=18.0, y_bar=5, y_spa_in=18.0, c=2.4166666666666665, wingwall_conc_cy=4.01, wingwall_reinf_lbs=533, footing_conc_cy=7.38, footing_reinf_lbs=733, culvert_footing_cy_per_ft=0.48, culvert_footing_lbs_per_ft=27.58), HeadwallRow(H=8.5, footing_design=1, L1=10.0, L2=10.0, h1=5.0, h2=5.0, footing_w=5.5, footing_t=1.5, hcw=2.5, a=1.9166666666666665, b=1.0, x_bar=5, x_spa_in=16.5, y_bar=5, y_spa_in=16.5, c=2.4166666666666665, wingwall_conc_cy=5.27, wingwall_reinf_lbs=726, footing_conc_cy=9.05, footing_reinf_lbs=830, culvert_footing_cy_per_ft=0.52, culvert_footing_lbs_per_ft=28.61), HeadwallRow(H=9.5, footing_design=1, L1=11.5, L2=11.5, h1=5.5, h2=5.5, footing_w=6.25, footing_t=1.5, hcw=2.5, a=2.25, b=1.0, x_bar=5, x_spa_in=18.0, y_bar=5, y_spa_in=9.0, c=3.8333333333333335, wingwall_conc_cy=6.69, wingwall_reinf_lbs=934, footing_conc_cy=11.35, footing_reinf_lbs=911, culvert_footing_cy_per_ft=0.57, culvert_footing_lbs_per_ft=29.9), HeadwallRow(H=10.5, footing_design=1, L1=12.75, L2=12.75, h1=6.0, h2=6.0, footing_w=7.0, footing_t=2.0, hcw=2.0, a=2.9166666666666665, b=1.25, x_bar=5, x_spa_in=18.0, y_bar=5, y_spa_in=9.0, c=4.166666666666667, wingwall_conc_cy=10.25, wingwall_reinf_lbs=1104, footing_conc_cy=16.19, footing_reinf_lbs=1087, culvert_footing_cy_per_ft=0.74, culvert_footing_lbs_per_ft=33.95), HeadwallRow(H=11.5, footing_design=1, L1=14.25, L2=14.25, h1=6.5, h2=6.5, footing_w=7.5, footing_t=2.0, hcw=2.0, a=3.4166666666666665, b=1.25, x_bar=5, x_spa_in=17.0, y_bar=5, y_spa_in=8.5, c=5.0, wingwall_conc_cy=12.43, wingwall_reinf_lbs=1404, footing_conc_cy=18.87, footing_reinf_lbs=1205, culvert_footing_cy_per_ft=0.8, culvert_footing_lbs_per_ft=35.06), HeadwallRow(H=12.5, footing_design=2, L1=15.75, L2=15.75, h1=7.0, h2=7.0, footing_w=8.75, footing_t=2.0, hcw=2.0, a=3.5, b=1.25, x_bar=5, x_spa_in=17.0, y_bar=5, y_spa_in=8.5, c=5.25, wingwall_conc_cy=14.82, wingwall_reinf_lbs=1580, footing_conc_cy=24.41, footing_reinf_lbs=1511, culvert_footing_cy_per_ft=0.89, culvert_footing_lbs_per_ft=40.14), HeadwallRow(H=13.5, footing_design=6, L1=17.0, L2=17.0, h1=7.5, h2=7.5, footing_w=9.5, footing_t=2.0, hcw=2.0, a=3.9166666666666665, b=1.25, x_bar=6, x_spa_in=18.0, y_bar=6, y_spa_in=9.0, c=6.166666666666667, wingwall_conc_cy=17.18, wingwall_reinf_lbs=2139, footing_conc_cy=28.17, footing_reinf_lbs=2024, culvert_footing_cy_per_ft=0.97, culvert_footing_lbs_per_ft=50.56))

culvert normal to the roadway, both wingwalls skewed 45 degrees from the culvert centerline.

Type:

Type A headwall (sheet 2/6)

civilpy.structural.odot.box_culvert_headwall.TYPE_C_TABLE = (HeadwallRow(H=6.5, footing_design=1, L1=10.0, L2=10.0, h1=6.5, h2=6.5, footing_w=5.25, footing_t=1.5, hcw=2.5, a=1.4166666666666667, b=1.0, x_bar=5, x_spa_in=17.5, y_bar=5, y_spa_in=17.5, c=2.4166666666666665, wingwall_conc_cy=4.82, wingwall_reinf_lbs=528, footing_conc_cy=8.62, footing_reinf_lbs=587, culvert_footing_cy_per_ft=0.49, culvert_footing_lbs_per_ft=27.84), HeadwallRow(H=7.5, footing_design=1, L1=12.0, L2=12.0, h1=7.5, h2=7.5, footing_w=5.75, footing_t=1.5, hcw=2.5, a=2.0, b=1.0, x_bar=5, x_spa_in=12.0, y_bar=5, y_spa_in=12.0, c=2.4166666666666665, wingwall_conc_cy=6.67, wingwall_reinf_lbs=749, footing_conc_cy=11.0, footing_reinf_lbs=695, culvert_footing_cy_per_ft=0.55, culvert_footing_lbs_per_ft=29.04), HeadwallRow(H=8.5, footing_design=1, L1=14.0, L2=14.0, h1=8.5, h2=8.5, footing_w=6.25, footing_t=1.5, hcw=2.5, a=2.5833333333333335, b=1.0, x_bar=5, x_spa_in=17.5, y_bar=5, y_spa_in=8.75, c=3.5, wingwall_conc_cy=8.82, wingwall_reinf_lbs=1012, footing_conc_cy=13.62, footing_reinf_lbs=823, culvert_footing_cy_per_ft=0.59, culvert_footing_lbs_per_ft=30.15), HeadwallRow(H=9.5, footing_design=1, L1=16.0, L2=16.0, h1=9.5, h2=9.5, footing_w=7.0, footing_t=1.5, hcw=2.5, a=2.9166666666666665, b=1.0, x_bar=5, x_spa_in=17.5, y_bar=5, y_spa_in=8.75, c=3.6666666666666665, wingwall_conc_cy=11.26, wingwall_reinf_lbs=1261, footing_conc_cy=16.89, footing_reinf_lbs=1044, culvert_footing_cy_per_ft=0.64, culvert_footing_lbs_per_ft=33.53), HeadwallRow(H=10.5, footing_design=1, L1=18.0, L2=18.0, h1=10.5, h2=10.5, footing_w=8.0, footing_t=2.0, hcw=2.0, a=3.25, b=1.25, x_bar=5, x_spa_in=18.0, y_bar=5, y_spa_in=9.0, c=3.9166666666666665, wingwall_conc_cy=17.5, wingwall_reinf_lbs=1485, footing_conc_cy=25.34, footing_reinf_lbs=1278, culvert_footing_cy_per_ft=0.85, culvert_footing_lbs_per_ft=38.01), HeadwallRow(H=11.5, footing_design=1, L1=20.0, L2=20.0, h1=11.5, h2=11.5, footing_w=9.0, footing_t=2.0, hcw=2.0, a=3.8333333333333335, b=1.25, x_bar=6, x_spa_in=18.0, y_bar=6, y_spa_in=9.0, c=4.5, wingwall_conc_cy=21.3, wingwall_reinf_lbs=2201, footing_conc_cy=31.12, footing_reinf_lbs=1478, culvert_footing_cy_per_ft=0.92, culvert_footing_lbs_per_ft=39.56), HeadwallRow(H=12.5, footing_design=4, L1=22.0, L2=22.0, h1=12.5, h2=12.5, footing_w=9.75, footing_t=2.0, hcw=2.0, a=4.25, b=1.25, x_bar=6, x_spa_in=16.0, y_bar=6, y_spa_in=8.0, c=5.166666666666667, wingwall_conc_cy=25.47, wingwall_reinf_lbs=2775, footing_conc_cy=36.67, footing_reinf_lbs=2028, culvert_footing_cy_per_ft=1.0, culvert_footing_lbs_per_ft=49.17), HeadwallRow(H=13.5, footing_design=5, L1=24.0, L2=24.0, h1=13.5, h2=13.5, footing_w=10.5, footing_t=2.0, hcw=2.0, a=4.666666666666667, b=1.25, x_bar=6, x_spa_in=13.0, y_bar=6, y_spa_in=6.5, c=5.333333333333333, wingwall_conc_cy=30.0, wingwall_reinf_lbs=3454, footing_conc_cy=42.67, footing_reinf_lbs=2635, culvert_footing_cy_per_ft=1.06, culvert_footing_lbs_per_ft=58.62))

both wingwalls parallel to the roadway (straight extensions of the headwall line); level wall tops (note 9, designed with a 2 ft live-load surcharge).

Type:

Type C headwall (sheet 5/6)

civilpy.structural.odot.box_culvert_headwall.WINGWALL_BACKSLOPE = 2.0

1 backslope on Type A and Type B wingwall tops (sheet 6/6 note 8); Type C wingwall tops are level (note 9).

Type:

2

class civilpy.structural.odot.box_culvert_headwall.WingwallInput(length_ft: float, skew_deg: float, wall_height_ft: float, foreslope_height_ft: float, cutoff_wall_height_ft: float, footing_width_ft: float, box_wall_thickness_in: float, embankment_slope: float = 2.0)[source]

Bases: object

Project-supplied dimensions for one wingwall + foreslope wall (sheet 2/8 “WINGWALL ELEVATION” + “SECTION A-A”). All in feet unless named _in. Nothing here is cataloged – see the module docstring.

box_wall_thickness_in: float
cutoff_wall_height_ft: float
embankment_slope: float = 2.0
footing_width_ft: float
foreslope_height_ft: float
length_ft: float
skew_deg: float
wall_height_ft: float
class civilpy.structural.odot.box_culvert_headwall.WingwallLayout(inputs: ~civilpy.structural.odot.box_culvert_headwall.WingwallInput, wingwall_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], foreslope_section: tuple[tuple[float, float, float], ...], footing_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], notes: tuple[str, ...] = <factory>)[source]

Bases: object

The generated wingwall + foreslope wall.

wingwall_outline is the wingwall’s flared elevation (top of footing at z = 0, box-face height H tapering to hf at y = L); foreslope_section is the Section A-A profile (cutoff wall, footing top, foreslope-wall stem with its t box thickness, 2:1 embankment line off the back face) in the Y-Z plane; footing_outline is the footing plan rectangle drawn at the bottom-of-cutoff elevation -hcw.

footing_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
foreslope_section: tuple[tuple[float, float, float], ...]
inputs: WingwallInput
notes: tuple[str, ...]
wingwall_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
civilpy.structural.odot.box_culvert_headwall.bend_shape(type_: str, **legs: float) tuple[tuple[float, float], ...][source]

The bend polyline for one of the BCHW legend shapes.

type_ is "TYPE-1" .. "TYPE-8"; legs supplies the leg lengths the sheet leaves blank (A, B, C, D as applicable, theta_deg for TYPE-2, skew_deg for TYPE-8). Raises ValueError naming the valid types and required legs.

civilpy.structural.odot.box_culvert_headwall.box_wall_thickness_in(span_ft: float) float[source]

Precast box wall thickness t box, wall (sheet 6/6 note 11): 8 in for 8 ft spans, 10 in for 10 ft spans, 12 in for spans of 12 ft and over.

civilpy.structural.odot.box_culvert_headwall.design_headwall(inp: HeadwallInput) HeadwallDesign[source]

Resolve a HeadwallInput against the Design Data tables: compute H = box rise + 2 (box slab thickness) + foreslope wall height (sheet 1/6), round up to the next tabulated design height, and return the row with its footing reinforcing and foreslope quantities.

civilpy.structural.odot.box_culvert_headwall.layout_wingwall(inp: WingwallInput) WingwallLayout[source]

Generate one wingwall + foreslope wall from fully project-supplied dimensions (no catalog lookup – see the module docstring).

Raises ValueError for a non-positive length/height/width.

civilpy.structural.odot.bridge_railing module

Ohio DOT standard bridge railings and barriers.

Geometry, reinforcement, and design data transcribed from the Ohio DOT Standard Bridge Drawings (Office of Structural Engineering). Each entry records the crash test level stated on the drawing’s design-criteria note; that key indexes the Table A13.2-1 design forces carried in civilpy.structural.aashto.lrfd.railing, so a cataloged railing can be fed straight into the yield-line and deck-overhang checks there.

Lengths are in inches and areas in square inches unless a field name says otherwise. Concrete strength f_c and reinforcing/structural-steel yields are in ksi. Values are spot-checked against the cited drawings in the test suite; the drawings remain the controlling document for detailing.

Sources (SCD number — drawing date / latest cited revision):

BR-1-13 New Jersey shape concrete bridge railing (rev. 2014-01-17) BR-2-15 Bridge sidewalk railing with concrete barrier (rev. 2024-07-19) SBR-1-20 Single slope concrete bridge railing, 42 in (rev. 2024-07-19) SBR-2-20 Single slope concrete median railing, 57 in (rev. 2024-07-19) SBR-3-20 Single slope concrete bridge railing, 36 in (rev. 2024-07-19) TST-1-99 Twin steel tube bridge railing (rev. 2021-01-15) TST-2-21 Three steel tube bridge railing (rev. 2025-01-17) DBR-2-73 Deep beam bridge guardrail (rev. 2002-07-19) DBR-3-11 Deep beam bridge retrofit railing (2011-07-15) TBR-1-11 Thrie beam retrofit railing (rev. 2013-01-18) PCB-91 Portable concrete barrier (rev. 2020-07-17)

civilpy.structural.odot.bridge_railing.BRIDGE_RAILINGS: dict[str, BridgeRailing] = {'BR-1 (36 in)': BridgeRailing(scd='BR-1-13', scd_date='2014-01-17', designation='BR-1 (36 in)', name='New Jersey shape concrete bridge railing, 36 in', shape='New Jersey', material='reinforced concrete', test_level='TL-4', height=36.0, base_width=18.0, top_width=8.0, section_area=423.25, f_c=4.5, f_y=60.0, vertical_bar_spacing=12.0, bar_sizes=(5, 6), transition_length_ft=14.0, transition_volume_cy=1.63, post_shape='', post_spacing=None, rail_element='', f_y_steel=None, weight_per_ft=None, segment_length_ft=(), rail_height_above_in=None, notes='GFRP deflection-joint stiffening at sawcut joints <= 15 ft o.c.'), 'BR-1 (42 in)': BridgeRailing(scd='BR-1-13', scd_date='2014-01-17', designation='BR-1 (42 in)', name='New Jersey shape concrete bridge railing, 42 in', shape='New Jersey', material='reinforced concrete', test_level='TL-5', height=42.0, base_width=18.0, top_width=8.0, section_area=474.5, f_c=4.5, f_y=60.0, vertical_bar_spacing=12.0, bar_sizes=(5, 6), transition_length_ft=14.0, transition_volume_cy=1.71, post_shape='', post_spacing=None, rail_element='', f_y_steel=None, weight_per_ft=None, segment_length_ft=(), rail_height_above_in=None, notes='Taller TL-5 variant of the 36 in BR-1; transition vertical bars at 9 in o.c.'), 'BR-2 (sidewalk barrier + twin tube)': BridgeRailing(scd='BR-2-15', scd_date='2024-07-19', designation='BR-2 (sidewalk barrier + twin tube)', name='Bridge sidewalk railing with concrete barrier (twin steel tube)', shape='combination (barrier + steel tube)', material='reinforced concrete + steel', test_level='TL-4', height=42.0, base_width=12.0, top_width=12.0, section_area=None, f_c=4.5, f_y=60.0, vertical_bar_spacing=12.0, bar_sizes=(5,), transition_length_ft=None, transition_volume_cy=None, post_shape='HSS 4x4x3/16', post_spacing=78.0, rail_element='2 - HSS 4x3x1/4', f_y_steel=46.0, weight_per_ft=None, segment_length_ft=(), rail_height_above_in=24.0, notes='The 42 in rectangular concrete barrier is the TL-4 crashworthy element; a twin steel tube pedestrian rail mounts on top, extending 2\'-0" above the barrier (combined height 5\'-6"). Optional vandal protection fence (VPF-1-24).'), 'DBR-2 (deep beam)': BridgeRailing(scd='DBR-2-73', scd_date='1973-04-10', designation='DBR-2 (deep beam)', name='Deep beam bridge guardrail', shape='post-and-beam (deep beam)', material='steel', test_level='', height=None, base_width=None, top_width=None, section_area=None, f_c=None, f_y=None, vertical_bar_spacing=None, bar_sizes=(), transition_length_ft=None, transition_volume_cy=None, post_shape='W6x25', post_spacing=75.0, rail_element='deep beam rail + TS 8x4x0.1875', f_y_steel=36.0, weight_per_ft=None, segment_length_ft=(), rail_height_above_in=None, notes='Legacy 1973 guardrail; drawing states no numeric crash test level. See DBR-3-11 for the NCHRP 350 TL-3 retrofit upgrade.'), 'DBR-3 (deep beam retrofit)': BridgeRailing(scd='DBR-3-11', scd_date='2011-07-15', designation='DBR-3 (deep beam retrofit)', name='Deep beam bridge retrofit railing', shape='post-and-beam (deep beam retrofit)', material='steel', test_level='TL-3', height=29.0, base_width=None, top_width=None, section_area=None, f_c=None, f_y=None, vertical_bar_spacing=None, bar_sizes=(), transition_length_ft=None, transition_volume_cy=None, post_shape='W6x25', post_spacing=75.0, rail_element='W-beam rail + HSS 8x4x3/16', f_y_steel=36.0, weight_per_ft=None, segment_length_ft=(), rail_height_above_in=None, notes='NCHRP 350 TL-3 retrofit of DBR-2-73 (FHWA HSSD/B-207). HSS rubrail continuous over >= 3 posts.'), 'PCB (portable, anchored)': BridgeRailing(scd='PCB-91', scd_date='1992-04-24', designation='PCB (portable, anchored)', name='Portable concrete barrier, fully anchored (traffic side)', shape='New Jersey', material='precast concrete', test_level='TL-4', height=32.0, base_width=24.0, top_width=None, section_area=None, f_c=4.0, f_y=None, vertical_bar_spacing=None, bar_sizes=(5,), transition_length_ft=None, transition_volume_cy=None, post_shape='', post_spacing=None, rail_element='', f_y_steel=None, weight_per_ft=None, segment_length_ft=(10.0, 12.0), rail_height_above_in=None, notes='Same barrier as the unanchored PCB; fully anchored on the traffic side it satisfies NCHRP 350 TL-4.'), 'PCB (portable, unanchored)': BridgeRailing(scd='PCB-91', scd_date='1992-04-24', designation='PCB (portable, unanchored)', name='Portable concrete barrier, unanchored', shape='New Jersey', material='precast concrete', test_level='TL-3', height=32.0, base_width=24.0, top_width=None, section_area=None, f_c=4.0, f_y=None, vertical_bar_spacing=None, bar_sizes=(5,), transition_length_ft=None, transition_volume_cy=None, post_shape='', post_spacing=None, rail_element='', f_y_steel=None, weight_per_ft=None, segment_length_ft=(10.0, 12.0), rail_height_above_in=None, notes='Pin-and-loop hinge connection; #8/#5 reinforcement per 509.02. Anchor fully on the traffic side for TL-4 (see PCB anchored entry).'), 'SBR-1 (42 in)': BridgeRailing(scd='SBR-1-20', scd_date='2020-01-17', designation='SBR-1 (42 in)', name='Single slope concrete bridge railing, 42 in', shape='single slope', material='reinforced concrete', test_level='TL-5', height=42.0, base_width=18.0, top_width=None, section_area=588.0, f_c=4.5, f_y=60.0, vertical_bar_spacing=12.0, bar_sizes=(4, 5, 6), transition_length_ft=14.0, transition_volume_cy=1.82, post_shape='', post_spacing=None, rail_element='', f_y_steel=None, weight_per_ft=None, segment_length_ft=(), rail_height_above_in=None, notes='GFRP horizontal (X4) and stiffening (Y401/Y402) bars; steel vertical bars.'), 'SBR-2 (57 in median)': BridgeRailing(scd='SBR-2-20', scd_date='2020-07-17', designation='SBR-2 (57 in median)', name='Single slope concrete median bridge railing, 57 in, Type B1', shape='single slope median', material='reinforced concrete', test_level='TL-3', height=57.0, base_width=33.75, top_width=12.0, section_area=1303.2, f_c=4.5, f_y=60.0, vertical_bar_spacing=24.0, bar_sizes=(4, 5, 8), transition_length_ft=None, transition_volume_cy=None, post_shape='', post_spacing=None, rail_element='', f_y_steel=None, weight_per_ft=None, segment_length_ft=(), rail_height_above_in=None, notes='Single (Type B1) median barrier; #8 dowels in the unreinforced median run. Vertical bars at 24 in o.c. for Type B1.'), 'SBR-2 (57 in median, back-to-back)': BridgeRailing(scd='SBR-2-20', scd_date='2020-07-17', designation='SBR-2 (57 in median, back-to-back)', name='Single slope back-to-back concrete median bridge railing, 57 in', shape='single slope median', material='reinforced concrete', test_level='TL-5', height=57.0, base_width=33.75, top_width=12.0, section_area=1303.2, f_c=4.5, f_y=60.0, vertical_bar_spacing=7.0, bar_sizes=(4, 5, 6), transition_length_ft=None, transition_volume_cy=None, post_shape='', post_spacing=None, rail_element='', f_y_steel=None, weight_per_ft=None, segment_length_ft=(), rail_height_above_in=None, notes='Two SBR-2 barriers back-to-back with 6 in max gap; vertical bars at 7 in o.c.'), 'SBR-3 (36 in)': BridgeRailing(scd='SBR-3-20', scd_date='2020-01-17', designation='SBR-3 (36 in)', name='Single slope concrete bridge railing, 36 in', shape='single slope', material='reinforced concrete', test_level='TL-4', height=36.0, base_width=18.0, top_width=None, section_area=524.0, f_c=4.5, f_y=60.0, vertical_bar_spacing=12.0, bar_sizes=(4, 5, 6), transition_length_ft=14.0, transition_volume_cy=1.74, post_shape='', post_spacing=None, rail_element='', f_y_steel=None, weight_per_ft=None, segment_length_ft=(), rail_height_above_in=None, notes='GFRP horizontal (X4) and stiffening (Y401/Y402) bars; steel vertical bars.'), 'TBR-1 (thrie beam retrofit)': BridgeRailing(scd='TBR-1-11', scd_date='2011-10-21', designation='TBR-1 (thrie beam retrofit)', name='Thrie beam retrofit railing', shape='post-and-beam (thrie beam)', material='steel on concrete curb', test_level='', height=25.5, base_width=None, top_width=None, section_area=None, f_c=4.0, f_y=None, vertical_bar_spacing=None, bar_sizes=(), transition_length_ft=None, transition_volume_cy=None, post_shape='W6x25', post_spacing=75.0, rail_element='thrie beam (M180 Type II Class B)', f_y_steel=None, weight_per_ft=None, segment_length_ft=(), rail_height_above_in=None, notes='Retrofit for AR-1-57 / BR-1-65 railings with 1 ft or 2 ft safety curbs. NHS-acceptable; no numeric crash test level stated.'), 'TST-1 (twin steel tube)': BridgeRailing(scd='TST-1-99', scd_date='1999-07-06', designation='TST-1 (twin steel tube)', name='Twin steel tube bridge railing', shape='post-and-beam (twin tube)', material='steel', test_level='TL-4', height=None, base_width=None, top_width=None, section_area=None, f_c=None, f_y=60.0, vertical_bar_spacing=None, bar_sizes=(), transition_length_ft=None, transition_volume_cy=None, post_shape='W6x25', post_spacing=75.0, rail_element='2 - TS 8x4x5/16', f_y_steel=46.0, weight_per_ft=None, segment_length_ft=(), rail_height_above_in=None, notes='NCHRP 350 TL-4. Measurement = flush-post length + 4 ft-11 in. Not for box-beam bridges with overhang > 2 in or top flange < 5 in.'), 'TST-2 (three steel tube)': BridgeRailing(scd='TST-2-21', scd_date='2021-07-16', designation='TST-2 (three steel tube)', name='Three steel tube bridge railing', shape='post-and-beam (three tube)', material='steel', test_level='TL-4', height=None, base_width=None, top_width=None, section_area=None, f_c=4.5, f_y=60.0, vertical_bar_spacing=None, bar_sizes=(), transition_length_ft=None, transition_volume_cy=None, post_shape='', post_spacing=96.0, rail_element='3 - HSS tube', f_y_steel=50.0, weight_per_ft=80.0, segment_length_ft=(), rail_height_above_in=None, notes='MASH TL-4 (transition to MGS guardrail is MASH TL-3). Post length 4 ft-6 in; min box-beam depth 17 in; max future wearing surface 3 in.')}

Catalog keyed by designation.

class civilpy.structural.odot.bridge_railing.BridgeRailing(scd: str, scd_date: str, designation: str, name: str, shape: str, material: str, test_level: str, height: float | None = None, base_width: float | None = None, top_width: float | None = None, section_area: float | None = None, f_c: float | None = None, f_y: float | None = None, vertical_bar_spacing: float | None = None, bar_sizes: tuple[int, ...] = (), transition_length_ft: float | None = None, transition_volume_cy: float | None = None, post_shape: str = '', post_spacing: float | None = None, rail_element: str = '', f_y_steel: float | None = None, weight_per_ft: float | None = None, segment_length_ft: tuple[float, ...] = (), rail_height_above_in: float | None = None, notes: str = '')[source]

Bases: object

One Ohio DOT standard bridge railing / barrier configuration.

test_level is the NCHRP 350 / MASH level stated on the drawing ("TL-2" .. "TL-6"); it keys TEST_LEVEL_LOADS. An empty string means the drawing states no numeric crash test level. Fields left as None / "" are not called out (or not applicable) on the drawing.

Concrete-parapet entries populate section_area (gross area of the standard, non-transition section), f_c/f_y, and the vertical-bar fields. Post-and-beam steel railings populate post_shape, post_spacing, rail_element, and f_y_steel instead.

bar_sizes: tuple[int, ...] = ()

Standard-bar designation numbers present in the section (#5, #6, …).

base_width: float | None = None
design_force_check(m_c: float, m_w: float, m_b: float = 0.0, end_region: bool = False)[source]

Run the AASHTO A13.3.1 yield-line check for this railing against its own test-level design forces.

Only meaningful for concrete-parapet entries. m_c (kip-ft/ft), m_w and m_b (kip-ft) are the wall’s flexural resistances; the railing’s catalog height (in) is converted to feet. Returns a CheckResult whose demand is the Table A13.2-1 transverse force Ft.

designation: str
f_c: float | None = None
f_y: float | None = None
f_y_steel: float | None = None

Structural / tube steel minimum yield, ksi.

height: float | None = None
material: str
meets_minimum_height() bool | None[source]

Whether the railing’s height satisfies the minimum rail height H for its test level (Table A13.2-1, h_min). None when the height or test level is not recorded.

For combination and post-and-beam railings height may be the crashworthy element height only; treat the result accordingly.

name: str
notes: str = ''
post_shape: str = ''

Steel post shape for post-and-beam railings (e.g. "W6x25").

post_spacing: float | None = None

Maximum post spacing, inches.

rail_element: str = ''

Longitudinal rail element(s) (e.g. "2 - TS 8x4x5/16").

rail_height_above_in: float | None = None

For a “combination” railing (full-height concrete barrier + steel tube pedestrian rail on top, e.g. BR-2-15): how far the steel tube assembly extends above the concrete barrier’s own height, inches.

scd: str
scd_date: str
section_area: float | None = None
segment_length_ft: tuple[float, ...] = ()

Precast segment length(s), feet (portable barrier).

shape: str
test_level: str
test_level_load() TestLevelLoad | None[source]

The Table A13.2-1 design forces for this railing’s test level, or None if the drawing states no numeric crash test level.

top_width: float | None = None
transition_length_ft: float | None = None

Length of the standard approach transition section, feet.

transition_volume_cy: float | None = None

Concrete volume of one transition section, cubic yards.

vertical_bar_spacing: float | None = None

Maximum on-center spacing of vertical reinforcing bars, inches.

weight_per_ft: float | None = None

Unit weight of the railing, lb/ft.

civilpy.structural.odot.bridge_railing.railing(designation: str) BridgeRailing[source]

Look up a railing by its designation (e.g. "BR-1 (36 in)").

civilpy.structural.odot.bridge_railing.railings_for_test_level(test_level: str) list[BridgeRailing][source]

All cataloged railings rated for test_level (e.g. "TL-4").

civilpy.structural.odot.capped_pile_abutment module

Ohio DOT capped pile abutment for slab bridges (CPA-1-08).

Transcribed from Ohio DOT Standard Bridge Drawing CPA-1-08, “Capped Pile Abutment for Slab Bridges” (rev. 01-19-2024, 6 sheets: three railing-variant pairs – SBR-1 deflector parapet, three steel tube, twin steel tube – of part-plan/elevation views, all referencing one shared cap cross-section (Section C-C/D-D, sheet 2) and one reinforcing steel table (sheet 4)). SB-1-24’s companion, referenced from its slab elevation as “ABUT. DIAPHRAGM SEE STANDARD DRAWING CPA-1-08”.

Like BCHW (civilpy.structural.odot.box_culvert_headwall), this sheet mixes a handful of fixed dimensions (cap width 3’-0”, the 1’-6”/1’-6” pile-zone split, max bar spacings) with project-variable ones the reinforcing steel table itself marks with an asterisk (“DIMENSION MAY VARY WITH EACH INDIVIDUAL STRUCTURE”) – wingwall length, pile count and spacing, footing depth, and every skew-dependent bar length (the S501/S502/S503 bars carry a literal sec(theta) term in their tabulated length, 1'-5"/COS(theta) etc.). layout_capped_pile_abutment takes those as required inputs; there is no discrete catalog to look them up from.

The D801 bar (sheet 4’s bending diagram legend, “TYPE 6 – SEE STANDARD BRIDGE DRAWING AS-1-15”) is the same bar as civilpy.structural.odot.approach_slab’s D801/D802 anchor bar – this sheet does not redefine it, so this module doesn’t either; see d801_length_ft().

Conventions match the rest of this package: X along stations, Y transverse, Z up; feet in plan, inches for section dimensions. The origin sits on the abutment centerline at the bridge-seat elevation (z = 0), y = 0 at the cap centerline.

class civilpy.structural.odot.capped_pile_abutment.AbutmentInput(wingwall_length_ft: float, skew_deg: float, n_piles: int, pile_spacing_ft: float, footing_depth_ft: float, cap_width_ft: float = 3.0)[source]

Bases: object

Project-supplied dimensions for one capped pile abutment.

wingwall_length_ft is the “W” dimension (Section B-B/F-F); n_piles/pile_spacing_ft lay out the cap’s pile line; footing_depth_ft is the cap/footing depth below the bridge seat. Nothing here is cataloged – see the module docstring.

cap_width_ft: float = 3.0
footing_depth_ft: float
n_piles: int
pile_spacing_ft: float
skew_deg: float
wingwall_length_ft: float
class civilpy.structural.odot.capped_pile_abutment.AbutmentLayout(inputs: ~civilpy.structural.odot.capped_pile_abutment.AbutmentInput, cap_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], pile_points: tuple[tuple[float, float, float], ...], wingwall_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], notes: tuple[str, ...] = <factory>)[source]

Bases: object

The generated abutment. cap_outline is the cap’s plan footprint (top of cap, z = 0, the bridge seat) extending down footing_depth_ft; pile_points are the pile centerlines along the cap; wingwall_outline is one flared wingwall plane (mirrors layout_full_height_headwall()’s convention).

cap_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
inputs: AbutmentInput
notes: tuple[str, ...]
pile_points: tuple[tuple[float, float, float], ...]
structural_model(reaction: float = 0.0) StructuralModel[source]

Returns a MIDAS-ready StructuralModel of the abutment cap as a beam.

wingwall_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
class civilpy.structural.odot.capped_pile_abutment.RebarMark(mark: 'str', length_ft: 'float | None', bend_type: 'int', a_ft: 'float | None' = None, b_ft: 'float | None' = None, c_ft: 'float | None' = None, note: 'str' = '')[source]

Bases: object

a_ft: float | None = None
b_ft: float | None = None
bend_type: int
c_ft: float | None = None
length_ft: float | None
mark: str
note: str = ''
civilpy.structural.odot.capped_pile_abutment.bend_shape(bend_type: int, **legs: float) tuple[tuple[float, float], ...][source]

The bend polyline for one of CPA-1-08’s own legend shapes (1-5).

legs supplies whatever the sheet leaves blank (A, B, C as applicable). Raises ValueError naming the valid types (1-5; call into approach_slab for Type 6/D801) and required legs.

civilpy.structural.odot.capped_pile_abutment.layout_capped_pile_abutment(inp: AbutmentInput) AbutmentLayout[source]

Generate one capped pile abutment from fully project-supplied dimensions (no catalog lookup – see the module docstring).

Raises ValueError for a non-positive length/spacing/depth or fewer than 2 piles.

civilpy.structural.odot.capped_pile_abutment.rebar_mark(mark: str) tuple[RebarMark, ...][source]

All REBAR_TABLE rows for a bar mark (usually one; A801 has two – the standard anchor bar and the optional hooked-dowel alternate).

Raises ValueError naming the valid marks otherwise.

civilpy.structural.odot.capped_pile_abutment.s_bar_length_ft(base_ft: float, skew_deg: float) float[source]

S501/S502/S503’s tabulated base/COS(theta) length formula.

civilpy.structural.odot.capped_pile_pier module

Ohio DOT capped pile pier for continuous slab bridges (CPP-1-08).

Transcribed from Ohio DOT Standard Bridge Drawing CPP-1-08, “Capped Pile Pier for Continuous Slab Bridges” (rev. 07-21-2017, 1 sheet). The drawing remains the controlling document. CS-1-24’s companion pier (feasibility rated in ODOT_SCD_Feasibility.md).

Unlike BCHW/CPA-1-08, this sheet is genuinely “clean and parametric”: the pier cap length is a literal formula in terms of the bridge slab width and skew, and the cap cross-section (width, end radius) is fixed regardless of span – there is no “insert design here” blank. Pile count/spacing and the reinforcing bar list quantities remain project-supplied (spacing has a stated max, not a table), same as every capped-pile-cap sheet in this package.

Design basis (General Notes / Design Instructions): AASHTO LRFD + 2008 interim revisions + 2007 ODOT BDM; HL-93; FWS 0.06 ksf; concrete f’c = 4.5 ksi; reinforcing/spiral steel min. yield 60 ksi; HP12X53 steel pile min. yield 50 ksi. Limits of design (exceeding any of these means this standard drawing does not apply): skew <= 30 deg, unsupported pile length <= 20 ft, supports a standard continuous slab with individual span <= 57.50 ft (CS-1-24), sloped embankment/debris/ice-flow lateral force on the pile bent, or piles not driven >= 10 ft into rock/firm material.

Conventions match the rest of this package: X along stations, Y transverse, Z up; feet in plan, inches for section dimensions. The origin sits on the pier centerline (X = 0) at the top-of-cap elevation (Z = 0), Y = 0 on the roadway centerline.

class civilpy.structural.odot.capped_pile_pier.PierBarMark(mark: 'str', width_ft: 'float | None', height_is_q: 'bool', inside_radius_ft: 'float | None' = None, note: 'str' = '')[source]

Bases: object

height_is_q: bool
inside_radius_ft: float | None = None
mark: str
note: str = ''
width_ft: float | None
class civilpy.structural.odot.capped_pile_pier.PierInput(slab_width_ft: float, skew_deg: float, n_piles: int, pile_spacing_ft: float, cap_depth_ft: float = 2.0)[source]

Bases: object

Inputs for a capped pile pier.

slab_width_ft is the bridge slab width (drives pier_length_ft()); n_piles/pile_spacing_ft lay out the pile line (spacing must not exceed MAX_PILE_SPACING_FT); cap_depth_ft defaults to the sheet’s fixed CAP_DEPTH_FT.

cap_depth_ft: float = 2.0
n_piles: int
pile_spacing_ft: float
skew_deg: float
slab_width_ft: float
class civilpy.structural.odot.capped_pile_pier.PierLayout(inputs: ~civilpy.structural.odot.capped_pile_pier.PierInput, cap_outline: tuple[tuple[float, float, float], ...], pile_points: tuple[tuple[float, float, float], ...], length_ft: float, notes: tuple[str, ...] = <factory>)[source]

Bases: object

The generated pier. cap_outline is the rounded-end cap plan footprint (top of cap, z = 0) extending down cap_depth_ft; pile_points are the pile centerlines (top of pile, at the cap underside).

cap_outline: tuple[tuple[float, float, float], ...]
inputs: PierInput
length_ft: float
notes: tuple[str, ...]
pile_points: tuple[tuple[float, float, float], ...]
civilpy.structural.odot.capped_pile_pier.layout_capped_pile_pier(inp: PierInput, *, n_arc_segments: int = 8) PierLayout[source]

Generate a capped pile pier: the rounded-end cap solid outline and the pile line, from the sheet’s own pier-length formula.

Raises ValueError for a non-positive slab width/pile spacing, fewer than 2 piles, a pile spacing beyond MAX_PILE_SPACING_FT, or a skew beyond MAX_SKEW_DEG.

civilpy.structural.odot.capped_pile_pier.pier_bar(mark: str) PierBarMark[source]

Look up a CPP-1-08 bar mark (P501-P504).

Raises ValueError naming the valid marks otherwise.

civilpy.structural.odot.capped_pile_pier.pier_length_ft(slab_width_ft: float, skew_deg: float = 0.0) float[source]
civilpy.structural.odot.capped_pile_pier.q_bend_height_ft(slab_thickness_in: float) float[source]

civilpy.structural.odot.concrete_curb module

ODOT BP-5.1 Standard Concrete Curbs and Combined Curb & Gutter.

Transcribed from Ohio DOT Standard Roadway Construction Drawing BP-5.1 (rev. 01-16-2026, 2 sheets), which catalogs 13 named curb/ combined-curb-and-gutter face profiles (Types 1 through 11, several with lettered substrate variants). Each is a small, fixed cross section – no span table or design formula – so, consistent with how civilpy.structural.odot.bridge_railing catalogs a parapet’s height/top_width/base_width without modeling its exact toe kick, each entry here is a schematic (height, top_width, base_width) trapezoid of the curb’s OWN concrete (not the paved gutter pad it may tie into, and not the exact fillet/rolled-curb arc – those are approximated as straight chamfers/ramps). The drawing remains the controlling document for the true face geometry.

Several sheet labels differ only by the pavement/base course the same curb face sits on (Types 2/2-A/2-B, 3/3-A/3-B, 4/4-A/4-B all share one profile); those are consolidated into one catalog entry whose sheet_labels records every name the profile answers to.

height is None for the three types (9, 10, 11) whose height is the project-specified gutter-plate thickness T (general note: “Thickness of gutter plate T shall be 9 in unless otherwise shown on the plans”) – DEFAULT_GUTTER_PLATE_T_IN gives that 9 in default.

Lengths are in inches.

Source: BP-5.1 (rev. 01-16-2026).

civilpy.structural.odot.concrete_curb.CURB_TOLERANCE_IN = (-0.09375, 0.25)

curb -3/32 to +1/4 in, gutter 0 to +1/8 in.

Type:

Dimensional tolerances (general note)

civilpy.structural.odot.concrete_curb.CURB_TYPES: dict[str, CurbType] = {'Type 1': CurbType(sheet_labels=('Type 1',), name='Asphalt curb (wedge)', height=6.0, top_width=4.0, base_width=9.0, toe_radius=None, notes='Sits on the asphalt concrete surface course over base; 42 deg battered face, 2 in top radius (approximated here as a straight-line wedge).'), 'Type 10': CurbType(sheet_labels=('Type 10',), name='Variable-height curb, no gutter pad', height=None, top_width=9.0, base_width=9.0, toe_radius=None, notes='Height is T (default 9 in); no integral gutter pad, back width per the Typical Sections.'), 'Type 10-A': CurbType(sheet_labels=('Type 10-A',), name='Tall curb, 45 deg chamfer', height=18.0, top_width=17.0, base_width=18.0, toe_radius=None, notes='6 in nose + 12 in pavement-contact width; 45 deg chamfer at the top corner (1 in / 2 in radii), approximated here as a 1 in top setback.'), 'Type 10-B': CurbType(sheet_labels=('Type 10-B',), name='Curb at joint (14 in)', height=14.0, top_width=6.0, base_width=6.0, toe_radius=None, notes='Preformed-joint-filler detail like Type 10-A but shorter (14 in) and without the 45 deg chamfer.'), 'Type 11': CurbType(sheet_labels=('Type 11',), name='Wide curb, compound curve face', height=None, top_width=6.0, base_width=24.0, toe_radius=None, notes='Height is T (default the 9 in gutter-plate thickness, per Typical Sections). Face is a compound curve (18 in toe radius, X=4-3/4 in / Y=4-5/8 in offsets) approximated here as a 9+9+6 in straight-segment trapezoid.'), 'Type 2': CurbType(sheet_labels=('Type 2', 'Type 2-A', 'Type 2-B'), name='Vertical curb, integral gutter pad', height=6.0, top_width=5.0, base_width=6.0, toe_radius=3.0, notes='Monolithic with new concrete pavement (Type 2), an asphalt wearing course over concrete base (Type 2-A), or a concrete base course under a wearing course (Type 2-B) -- same curb face on all three. Integral gutter pad extends 2\'-6" (30 in) beyond the toe unless the plans show otherwise, sloped 12:1 down to the pavement.'), 'Type 2-A': CurbType(sheet_labels=('Type 2', 'Type 2-A', 'Type 2-B'), name='Vertical curb, integral gutter pad', height=6.0, top_width=5.0, base_width=6.0, toe_radius=3.0, notes='Monolithic with new concrete pavement (Type 2), an asphalt wearing course over concrete base (Type 2-A), or a concrete base course under a wearing course (Type 2-B) -- same curb face on all three. Integral gutter pad extends 2\'-6" (30 in) beyond the toe unless the plans show otherwise, sloped 12:1 down to the pavement.'), 'Type 2-B': CurbType(sheet_labels=('Type 2', 'Type 2-A', 'Type 2-B'), name='Vertical curb, integral gutter pad', height=6.0, top_width=5.0, base_width=6.0, toe_radius=3.0, notes='Monolithic with new concrete pavement (Type 2), an asphalt wearing course over concrete base (Type 2-A), or a concrete base course under a wearing course (Type 2-B) -- same curb face on all three. Integral gutter pad extends 2\'-6" (30 in) beyond the toe unless the plans show otherwise, sloped 12:1 down to the pavement.'), 'Type 3': CurbType(sheet_labels=('Type 3', 'Type 3-A', 'Type 3-B'), name='Mountable (rolled) curb', height=4.0, top_width=0.0, base_width=10.0, toe_radius=None, notes='Rounds flush with the pavement over a 10 in radius arc (Type 3 on concrete pavement, 3-A on asphalt, 3-B on a wearing course over concrete base) -- approximated here as a straight ramp from pavement to the 4 in curb top, not the true arc.'), 'Type 3-A': CurbType(sheet_labels=('Type 3', 'Type 3-A', 'Type 3-B'), name='Mountable (rolled) curb', height=4.0, top_width=0.0, base_width=10.0, toe_radius=None, notes='Rounds flush with the pavement over a 10 in radius arc (Type 3 on concrete pavement, 3-A on asphalt, 3-B on a wearing course over concrete base) -- approximated here as a straight ramp from pavement to the 4 in curb top, not the true arc.'), 'Type 3-B': CurbType(sheet_labels=('Type 3', 'Type 3-A', 'Type 3-B'), name='Mountable (rolled) curb', height=4.0, top_width=0.0, base_width=10.0, toe_radius=None, notes='Rounds flush with the pavement over a 10 in radius arc (Type 3 on concrete pavement, 3-A on asphalt, 3-B on a wearing course over concrete base) -- approximated here as a straight ramp from pavement to the 4 in curb top, not the true arc.'), 'Type 4': CurbType(sheet_labels=('Type 4', 'Type 4-A', 'Type 4-B'), name='Vertical curb, no integral gutter', height=6.0, top_width=5.0, base_width=6.0, toe_radius=3.0, notes="Same face as Type 2 (concrete pavement / wearing course over concrete base / wearing course over base course respectively) but without an integral gutter pad; back width is project-specified ('as shown on Typical Sections in Plans')."), 'Type 4-A': CurbType(sheet_labels=('Type 4', 'Type 4-A', 'Type 4-B'), name='Vertical curb, no integral gutter', height=6.0, top_width=5.0, base_width=6.0, toe_radius=3.0, notes="Same face as Type 2 (concrete pavement / wearing course over concrete base / wearing course over base course respectively) but without an integral gutter pad; back width is project-specified ('as shown on Typical Sections in Plans')."), 'Type 4-B': CurbType(sheet_labels=('Type 4', 'Type 4-A', 'Type 4-B'), name='Vertical curb, no integral gutter', height=6.0, top_width=5.0, base_width=6.0, toe_radius=3.0, notes="Same face as Type 2 (concrete pavement / wearing course over concrete base / wearing course over base course respectively) but without an integral gutter pad; back width is project-specified ('as shown on Typical Sections in Plans')."), 'Type 4-C': CurbType(sheet_labels=('Type 4-C',), name='Tall curb at approach slab joint', height=16.0, top_width=5.0, base_width=6.0, toe_radius=None, notes='Used where the curb meets a pavement/approach-slab expansion joint; 1 in preformed joint filler (Item 705.03) + joint sealer (Item 705.04), full curb height per the general JOINTS note.'), 'Type 6': CurbType(sheet_labels=('Type 6',), name='Tall curb at joint (18 in)', height=18.0, top_width=6.0, base_width=8.0, toe_radius=None, notes='Taller sibling of Type 4-C (18 in vs 16 in); same preformed-joint-filler / sealer detail at pavement joints.'), 'Type 7': CurbType(sheet_labels=('Type 7',), name='Median curb against earth', height=10.0, top_width=6.5, base_width=8.0, toe_radius=None, notes='Backed by earth (not pavement/base); 1 in preformed joint filler at the pavement side.'), 'Type 8': CurbType(sheet_labels=('Type 8',), name='Median curb, shoulder/pavement joint', height=9.0, top_width=9.0, base_width=12.0, toe_radius=None, notes='Asphalt pavement or shoulder on one face, pavement on the other, with a joint-sealed interface between them.'), 'Type 9': CurbType(sheet_labels=('Type 9',), name='Variable-height curb, gutter pad', height=None, top_width=9.0, base_width=21.0, toe_radius=None, notes='Height is the project gutter-plate thickness T (default 9 in). Top cross slope matches the roadway cross slope; 9 in nose + 12 in gutter pad.')}

Catalog keyed by every sheet label it answers to (so "Type 2-A" and "Type 2-B" both resolve to the Type 2 entry).

class civilpy.structural.odot.concrete_curb.CurbType(sheet_labels: tuple[str, ...], name: str, height: float | None, top_width: float, base_width: float, toe_radius: float | None = None, notes: str = '')[source]

Bases: object

One BP-5.1 curb / combined curb-and-gutter cross section.

height is the curb’s own face height (in), None when it is the project-variable gutter-plate thickness T. top_width / base_width describe a schematic trapezoid of the curb’s concrete only (see module docstring for what is and isn’t modeled).

base_width: float
height: float | None
name: str
notes: str = ''
sheet_labels: tuple[str, ...]
toe_radius: float | None = None
top_width: float
civilpy.structural.odot.concrete_curb.DEFAULT_GUTTER_PLATE_T_IN = 9.0

gutter plate thickness T defaults to 9 in unless the plans show otherwise (governs Types 9, 10, 11’s variable height).

Type:

General note

civilpy.structural.odot.concrete_curb.EXPANSION_JOINT_WIDTH_IN = 1.0

1 in transverse expansion joints, Item 705.03 filler / 705.04 sealer, at curb-and-gutter expansion joints and approach slabs.

Type:

General note

civilpy.structural.odot.concrete_curb.curb_height_in(label: str, *, gutter_plate_t_in: float | None = None) float[source]

Resolved curb height (in): the catalog height if fixed, else the project gutter_plate_t_in (defaulting to DEFAULT_GUTTER_PLATE_T_IN) for the variable-height types.

civilpy.structural.odot.concrete_curb.curb_profile_in(label: str, *, gutter_plate_t_in: float | None = None) tuple[tuple[float, float], ...][source]

Schematic closed trapezoid profile (in) for label, (offset, z) counterclockwise from the back-bottom corner, offset measured from the curb’s back face and z up from the pavement surface.

civilpy.structural.odot.concrete_curb.curb_type(label: str) CurbType[source]

Look up a curb cross section by any of its sheet labels (e.g. "Type 2", "Type 2-A", "Type 10-B").

civilpy.structural.odot.continuous_slab_bridge module

Ohio DOT three-span continuous slab bridges (CS-1-24).

Transcribed from Ohio DOT Standard Bridge Drawing CS-1-24, “Continuous Slab Bridge” (rev. 01-16-2026, 4 sheets). The drawing remains the controlling document. SB-1-24’s continuous-span sibling; CPP-1-08 is its pier (civilpy.structural.odot.capped_pile_pier).

Sheet 2’s SLAB DATA table gives, for 33 tabulated end spans (14 to 46 ft), the slab thickness and the full longitudinal (A/B bottom, C/D top, E top-at-pier) and transverse (N bottom, M top, U lap) reinforcing schedule – 779 numeric entries, the largest table in the SCD program. The interior span is always 1.25x the end span (a fixed ratio baked into the “SPANS (FEET)” column, e.g. “14 - 17.50 - 14”), not a separately tabulated value – see interior_span_ft(). Sheet 1 also gives the Y offset formula for the first M-bar (m_bar_offset_in()).

Design basis (sheet 2 notes): same as SB-1-24 – AASHTO LRFD 9th Ed. + ODOT BDM (July 2023); HL-93; FWS 60 lb/ft^2; 1 in monolithic wearing surface; concrete f’c = 4500 psi; reinforcing steel min. yield 60,000 psi, epoxy coated. Applicable for roadway widths >= 24 ft and skew <= 25 deg (identical applicability notes to SB-1-24). Additional interior spans (same length as the middle span) may be added without changing slab thickness or area of reinforcing steel (sheet 2 General note).

Conventions match civilpy.structural.odot.slab_bridge: X along stations, Y transverse, Z up; feet in plan, inches for section dimensions. The layout origin sits at the first (upstream) abutment bearing line, y = 0 at one slab edge, z = 0 at the top of slab.

class civilpy.structural.odot.continuous_slab_bridge.ABarSpec(spacing_in: 'float', size: 'int', a_ft: 'float', length_ft: 'float')[source]

Bases: BarSpec

a_ft: float
length_ft: float
class civilpy.structural.odot.continuous_slab_bridge.BarRun(mark: 'str', size: 'int', points: 'tuple[Point, ...]')[source]

Bases: object

mark: str
points: tuple[tuple[float, float, float], ...]
size: int
class civilpy.structural.odot.continuous_slab_bridge.BarSpec(spacing_in: 'float', size: 'int')[source]

Bases: object

size: int
spacing_in: float
class civilpy.structural.odot.continuous_slab_bridge.CSSlabDesign(end_span_ft: int, thickness_in: float, a_bar: ABarSpec, b_bar: LenBarSpec, c_bar: LenBarSpec, d_bar: LenBarSpec, e_bar: LenBarSpec | None, n_bar: CountBarSpec, m_bar: CountBarSpec, u_bar_count: int)[source]

Bases: object

One SLAB DATA table row (sheet 2), keyed by end span (ft).

a_bar: ABarSpec
b_bar: LenBarSpec
c_bar: LenBarSpec
d_bar: LenBarSpec
e_bar: LenBarSpec | None
end_span_ft: int
m_bar: CountBarSpec
n_bar: CountBarSpec
thickness_in: float
u_bar_count: int
civilpy.structural.odot.continuous_slab_bridge.CS_SLAB_DESIGNS: dict[int, CSSlabDesign] = {14: CSSlabDesign(end_span_ft=14, thickness_in=11, a_bar=ABarSpec(spacing_in=7, size=8, a_ft='16\'-7"', length_ft=17.5), b_bar=LenBarSpec(spacing_in=7, size=8, length_ft=21.5), c_bar=LenBarSpec(spacing_in=7, size=5, length_ft=7.5), d_bar=LenBarSpec(spacing_in=7, size=8, length_ft=21.166667), e_bar=None, n_bar=CountBarSpec(spacing_in=15.0, size=6, count=47), m_bar=CountBarSpec(spacing_in=12.0, size=4, count=47), u_bar_count=78), 15: CSSlabDesign(end_span_ft=15, thickness_in=11.5, a_bar=ABarSpec(spacing_in=7, size=8, a_ft='17\'-7"', length_ft=18.5), b_bar=LenBarSpec(spacing_in=7, size=8, length_ft=22.75), c_bar=LenBarSpec(spacing_in=7, size=5, length_ft=7.833333), d_bar=LenBarSpec(spacing_in=7, size=8, length_ft=22.5), e_bar=None, n_bar=CountBarSpec(spacing_in=15.0, size=6, count=49), m_bar=CountBarSpec(spacing_in=12.0, size=4, count=50), u_bar_count=82), 16: CSSlabDesign(end_span_ft=16, thickness_in=12, a_bar=ABarSpec(spacing_in=7, size=8, a_ft='18\'-7"', length_ft=19.5), b_bar=LenBarSpec(spacing_in=7, size=8, length_ft=24.0), c_bar=LenBarSpec(spacing_in=7, size=5, length_ft=8.25), d_bar=LenBarSpec(spacing_in=7, size=8, length_ft=23.666667), e_bar=None, n_bar=CountBarSpec(spacing_in=15.0, size=6, count=52), m_bar=CountBarSpec(spacing_in=12.0, size=4, count=53), u_bar_count=88), 17: CSSlabDesign(end_span_ft=17, thickness_in=12.5, a_bar=ABarSpec(spacing_in=7, size=8, a_ft='19\'-7"', length_ft=20.5), b_bar=LenBarSpec(spacing_in=7, size=8, length_ft=25.25), c_bar=LenBarSpec(spacing_in=7, size=5, length_ft=8.583333), d_bar=LenBarSpec(spacing_in=7, size=8, length_ft=25.0), e_bar=None, n_bar=CountBarSpec(spacing_in=15.0, size=6, count=54), m_bar=CountBarSpec(spacing_in=12.0, size=4, count=56), u_bar_count=92), 18: CSSlabDesign(end_span_ft=18, thickness_in=13, a_bar=ABarSpec(spacing_in=7, size=8, a_ft='20\'-7"', length_ft=21.5), b_bar=LenBarSpec(spacing_in=7, size=8, length_ft=26.5), c_bar=LenBarSpec(spacing_in=7, size=5, length_ft=9.0), d_bar=LenBarSpec(spacing_in=7, size=8, length_ft=26.166667), e_bar=None, n_bar=CountBarSpec(spacing_in=15.0, size=6, count=57), m_bar=CountBarSpec(spacing_in=12.0, size=4, count=60), u_bar_count=98), 19: CSSlabDesign(end_span_ft=19, thickness_in=13.5, a_bar=ABarSpec(spacing_in=7, size=8, a_ft='21\'-7"', length_ft=22.5), b_bar=LenBarSpec(spacing_in=7, size=8, length_ft=27.75), c_bar=LenBarSpec(spacing_in=7, size=5, length_ft=9.333333), d_bar=LenBarSpec(spacing_in=7, size=8, length_ft=27.5), e_bar=None, n_bar=CountBarSpec(spacing_in=15.0, size=6, count=60), m_bar=CountBarSpec(spacing_in=12.0, size=4, count=63), u_bar_count=104), 20: CSSlabDesign(end_span_ft=20, thickness_in=14, a_bar=ABarSpec(spacing_in=7, size=8, a_ft='22\'-7"', length_ft=23.5), b_bar=LenBarSpec(spacing_in=7, size=8, length_ft=29.0), c_bar=LenBarSpec(spacing_in=7, size=5, length_ft=9.75), d_bar=LenBarSpec(spacing_in=7, size=8, length_ft=28.666667), e_bar=None, n_bar=CountBarSpec(spacing_in=15.0, size=6, count=62), m_bar=CountBarSpec(spacing_in=12.0, size=4, count=66), u_bar_count=108), 21: CSSlabDesign(end_span_ft=21, thickness_in=14.5, a_bar=ABarSpec(spacing_in=7, size=8, a_ft='23\'-7"', length_ft=24.5), b_bar=LenBarSpec(spacing_in=7, size=8, length_ft=30.25), c_bar=LenBarSpec(spacing_in=7, size=5, length_ft=10.083333), d_bar=LenBarSpec(spacing_in=7, size=8, length_ft=30.0), e_bar=None, n_bar=CountBarSpec(spacing_in=15.0, size=6, count=65), m_bar=CountBarSpec(spacing_in=12.0, size=4, count=69), u_bar_count=114), 22: CSSlabDesign(end_span_ft=22, thickness_in=15, a_bar=ABarSpec(spacing_in=7, size=8, a_ft='24\'-7"', length_ft=25.5), b_bar=LenBarSpec(spacing_in=7, size=8, length_ft=31.5), c_bar=LenBarSpec(spacing_in=7, size=5, length_ft=13.666667), d_bar=LenBarSpec(spacing_in=7, size=8, length_ft=24.833333), e_bar=LenBarSpec(spacing_in=7, size=5, length_ft=9.916667), n_bar=CountBarSpec(spacing_in=15.0, size=6, count=67), m_bar=CountBarSpec(spacing_in=12.0, size=4, count=73), u_bar_count=118), 23: CSSlabDesign(end_span_ft=23, thickness_in=15.5, a_bar=ABarSpec(spacing_in=7, size=8, a_ft='25\'-7"', length_ft=26.5), b_bar=LenBarSpec(spacing_in=7, size=8, length_ft=32.75), c_bar=LenBarSpec(spacing_in=7, size=5, length_ft=14.25), d_bar=LenBarSpec(spacing_in=7, size=8, length_ft=25.666667), e_bar=LenBarSpec(spacing_in=7, size=5, length_ft=10.333333), n_bar=CountBarSpec(spacing_in=15.0, size=6, count=70), m_bar=CountBarSpec(spacing_in=12.0, size=4, count=76), u_bar_count=124), 24: CSSlabDesign(end_span_ft=24, thickness_in=16, a_bar=ABarSpec(spacing_in=7, size=8, a_ft='26\'-7"', length_ft=27.5), b_bar=LenBarSpec(spacing_in=7, size=8, length_ft=34.0), c_bar=LenBarSpec(spacing_in=6, size=5, length_ft=14.833333), d_bar=LenBarSpec(spacing_in=6, size=8, length_ft=26.583333), e_bar=LenBarSpec(spacing_in=6, size=5, length_ft=10.833333), n_bar=CountBarSpec(spacing_in=15.0, size=6, count=73), m_bar=CountBarSpec(spacing_in=12.0, size=4, count=79), u_bar_count=130), 25: CSSlabDesign(end_span_ft=25, thickness_in=16.5, a_bar=ABarSpec(spacing_in=7, size=8, a_ft='27\'-7"', length_ft=28.5), b_bar=LenBarSpec(spacing_in=7, size=8, length_ft=35.25), c_bar=LenBarSpec(spacing_in=6, size=5, length_ft=15.416667), d_bar=LenBarSpec(spacing_in=6, size=8, length_ft=27.333333), e_bar=LenBarSpec(spacing_in=6, size=5, length_ft=11.25), n_bar=CountBarSpec(spacing_in=15.0, size=6, count=75), m_bar=CountBarSpec(spacing_in=12.0, size=4, count=82), u_bar_count=134), 26: CSSlabDesign(end_span_ft=26, thickness_in=17, a_bar=ABarSpec(spacing_in=7, size=8, a_ft='28\'-7"', length_ft=29.5), b_bar=LenBarSpec(spacing_in=7, size=8, length_ft=36.5), c_bar=LenBarSpec(spacing_in=6, size=5, length_ft=16.083333), d_bar=LenBarSpec(spacing_in=6, size=8, length_ft=28.083333), e_bar=LenBarSpec(spacing_in=6, size=5, length_ft=11.666667), n_bar=CountBarSpec(spacing_in=15.0, size=6, count=78), m_bar=CountBarSpec(spacing_in=12.0, size=4, count=86), u_bar_count=140), 27: CSSlabDesign(end_span_ft=27, thickness_in=17.5, a_bar=ABarSpec(spacing_in=7, size=8, a_ft='29\'-7"', length_ft=30.5), b_bar=LenBarSpec(spacing_in=7, size=8, length_ft=37.75), c_bar=LenBarSpec(spacing_in=6, size=5, length_ft=16.666667), d_bar=LenBarSpec(spacing_in=6, size=8, length_ft=28.833333), e_bar=LenBarSpec(spacing_in=6, size=5, length_ft=12.166667), n_bar=CountBarSpec(spacing_in=15.0, size=6, count=80), m_bar=CountBarSpec(spacing_in=12.0, size=4, count=89), u_bar_count=144), 28: CSSlabDesign(end_span_ft=28, thickness_in=18, a_bar=ABarSpec(spacing_in=6, size=8, a_ft='30\'-7"', length_ft=31.5), b_bar=LenBarSpec(spacing_in=6, size=8, length_ft=39.0), c_bar=LenBarSpec(spacing_in=6, size=5, length_ft=17.25), d_bar=LenBarSpec(spacing_in=6, size=8, length_ft=29.666667), e_bar=LenBarSpec(spacing_in=6, size=5, length_ft=12.583333), n_bar=CountBarSpec(spacing_in=15.0, size=6, count=83), m_bar=CountBarSpec(spacing_in=12.0, size=4, count=92), u_bar_count=150), 29: CSSlabDesign(end_span_ft=29, thickness_in=18.5, a_bar=ABarSpec(spacing_in=6, size=8, a_ft='31\'-7"', length_ft=32.5), b_bar=LenBarSpec(spacing_in=6, size=8, length_ft=40.25), c_bar=LenBarSpec(spacing_in=6, size=5, length_ft=17.833333), d_bar=LenBarSpec(spacing_in=6, size=8, length_ft=30.583333), e_bar=LenBarSpec(spacing_in=6, size=5, length_ft=13.0), n_bar=CountBarSpec(spacing_in=15.0, size=6, count=86), m_bar=CountBarSpec(spacing_in=12.0, size=4, count=95), u_bar_count=156), 30: CSSlabDesign(end_span_ft=30, thickness_in=19, a_bar=ABarSpec(spacing_in=6, size=8, a_ft='32\'-7"', length_ft=33.5), b_bar=LenBarSpec(spacing_in=6, size=8, length_ft=41.5), c_bar=LenBarSpec(spacing_in=7, size=5, length_ft=18.416667), d_bar=LenBarSpec(spacing_in=7, size=9, length_ft=33.0), e_bar=LenBarSpec(spacing_in=7, size=5, length_ft=13.5), n_bar=CountBarSpec(spacing_in=15.0, size=6, count=88), m_bar=CountBarSpec(spacing_in=12.0, size=4, count=99), u_bar_count=160), 31: CSSlabDesign(end_span_ft=31, thickness_in=19.5, a_bar=ABarSpec(spacing_in=6, size=8, a_ft='33\'-7"', length_ft=34.5), b_bar=LenBarSpec(spacing_in=6, size=8, length_ft=42.75), c_bar=LenBarSpec(spacing_in=7, size=5, length_ft=19.0), d_bar=LenBarSpec(spacing_in=7, size=9, length_ft=33.833333), e_bar=LenBarSpec(spacing_in=7, size=5, length_ft=13.916667), n_bar=CountBarSpec(spacing_in=15.0, size=6, count=91), m_bar=CountBarSpec(spacing_in=12.0, size=4, count=102), u_bar_count=166), 32: CSSlabDesign(end_span_ft=32, thickness_in=20, a_bar=ABarSpec(spacing_in=6, size=8, a_ft='34\'-7"', length_ft=35.5), b_bar=LenBarSpec(spacing_in=6, size=8, length_ft=44.0), c_bar=LenBarSpec(spacing_in=7, size=5, length_ft=19.666667), d_bar=LenBarSpec(spacing_in=7, size=9, length_ft=34.5), e_bar=LenBarSpec(spacing_in=7, size=5, length_ft=14.333333), n_bar=CountBarSpec(spacing_in=15.0, size=6, count=93), m_bar=CountBarSpec(spacing_in=12.0, size=5, count=105), u_bar_count=170), 33: CSSlabDesign(end_span_ft=33, thickness_in=20.5, a_bar=ABarSpec(spacing_in=6, size=8, a_ft='35\'-7"', length_ft=36.5), b_bar=LenBarSpec(spacing_in=6, size=8, length_ft=45.25), c_bar=LenBarSpec(spacing_in=6, size=5, length_ft=20.25), d_bar=LenBarSpec(spacing_in=6, size=9, length_ft=35.333333), e_bar=LenBarSpec(spacing_in=6, size=5, length_ft=14.75), n_bar=CountBarSpec(spacing_in=15.0, size=6, count=96), m_bar=CountBarSpec(spacing_in=12.0, size=5, count=108), u_bar_count=176), 34: CSSlabDesign(end_span_ft=34, thickness_in=21, a_bar=ABarSpec(spacing_in=6, size=8, a_ft='36\'-7"', length_ft=37.5), b_bar=LenBarSpec(spacing_in=6, size=8, length_ft=46.5), c_bar=LenBarSpec(spacing_in=6, size=5, length_ft=20.833333), d_bar=LenBarSpec(spacing_in=6, size=9, length_ft=36.25), e_bar=LenBarSpec(spacing_in=6, size=5, length_ft=15.166667), n_bar=CountBarSpec(spacing_in=15.0, size=6, count=99), m_bar=CountBarSpec(spacing_in=12.0, size=5, count=112), u_bar_count=182), 35: CSSlabDesign(end_span_ft=35, thickness_in=21.5, a_bar=ABarSpec(spacing_in=7, size=9, a_ft='37\'-10"', length_ft=39.083333), b_bar=LenBarSpec(spacing_in=7, size=9, length_ft=48.25), c_bar=LenBarSpec(spacing_in=6, size=5, length_ft=21.416667), d_bar=LenBarSpec(spacing_in=6, size=9, length_ft=37.0), e_bar=LenBarSpec(spacing_in=6, size=5, length_ft=15.666667), n_bar=CountBarSpec(spacing_in=15.0, size=6, count=101), m_bar=CountBarSpec(spacing_in=12.0, size=5, count=115), u_bar_count=186), 36: CSSlabDesign(end_span_ft=36, thickness_in=22, a_bar=ABarSpec(spacing_in=7, size=9, a_ft='38\'-10"', length_ft=40.083333), b_bar=LenBarSpec(spacing_in=7, size=9, length_ft=49.5), c_bar=LenBarSpec(spacing_in=6, size=5, length_ft=22.0), d_bar=LenBarSpec(spacing_in=6, size=9, length_ft=37.833333), e_bar=LenBarSpec(spacing_in=6, size=5, length_ft=16.083333), n_bar=CountBarSpec(spacing_in=15.0, size=6, count=104), m_bar=CountBarSpec(spacing_in=12.0, size=5, count=118), u_bar_count=192), 37: CSSlabDesign(end_span_ft=37, thickness_in=22.5, a_bar=ABarSpec(spacing_in=7, size=9, a_ft='39\'-10"', length_ft=41.083333), b_bar=LenBarSpec(spacing_in=7, size=9, length_ft=50.75), c_bar=LenBarSpec(spacing_in=6, size=5, length_ft=22.583333), d_bar=LenBarSpec(spacing_in=6, size=9, length_ft=38.75), e_bar=LenBarSpec(spacing_in=6, size=5, length_ft=16.583333), n_bar=CountBarSpec(spacing_in=15.0, size=6, count=106), m_bar=CountBarSpec(spacing_in=12.0, size=5, count=121), u_bar_count=196), 38: CSSlabDesign(end_span_ft=38, thickness_in=23, a_bar=ABarSpec(spacing_in=7, size=9, a_ft='40\'-10"', length_ft=42.083333), b_bar=LenBarSpec(spacing_in=7, size=9, length_ft=52.0), c_bar=LenBarSpec(spacing_in=7, size=5, length_ft=23.25), d_bar=LenBarSpec(spacing_in=7, size=10, length_ft=41.333333), e_bar=LenBarSpec(spacing_in=7, size=5, length_ft=17.0), n_bar=CountBarSpec(spacing_in=15.0, size=6, count=109), m_bar=CountBarSpec(spacing_in=12.0, size=5, count=125), u_bar_count=202), 39: CSSlabDesign(end_span_ft=39, thickness_in=23.5, a_bar=ABarSpec(spacing_in=7, size=9, a_ft='41\'-10"', length_ft=43.083333), b_bar=LenBarSpec(spacing_in=7, size=9, length_ft=53.25), c_bar=LenBarSpec(spacing_in=7, size=5, length_ft=23.833333), d_bar=LenBarSpec(spacing_in=7, size=10, length_ft=42.25), e_bar=LenBarSpec(spacing_in=7, size=5, length_ft=17.5), n_bar=CountBarSpec(spacing_in=15.0, size=6, count=112), m_bar=CountBarSpec(spacing_in=12.0, size=5, count=128), u_bar_count=208), 40: CSSlabDesign(end_span_ft=40, thickness_in=24, a_bar=ABarSpec(spacing_in=7, size=9, a_ft='42\'-10"', length_ft=44.083333), b_bar=LenBarSpec(spacing_in=7, size=9, length_ft=54.5), c_bar=LenBarSpec(spacing_in=7, size=5, length_ft=24.416667), d_bar=LenBarSpec(spacing_in=7, size=10, length_ft=43.0), e_bar=LenBarSpec(spacing_in=7, size=5, length_ft=17.916667), n_bar=CountBarSpec(spacing_in=15.0, size=6, count=114), m_bar=CountBarSpec(spacing_in=12.0, size=5, count=131), u_bar_count=212), 41: CSSlabDesign(end_span_ft=41, thickness_in=24.5, a_bar=ABarSpec(spacing_in=6, size=9, a_ft='43\'-10"', length_ft=45.083333), b_bar=LenBarSpec(spacing_in=6, size=9, length_ft=55.75), c_bar=LenBarSpec(spacing_in=6, size=5, length_ft=25.0), d_bar=LenBarSpec(spacing_in=6, size=10, length_ft=43.833333), e_bar=LenBarSpec(spacing_in=6, size=5, length_ft=18.416667), n_bar=CountBarSpec(spacing_in=15.0, size=6, count=117), m_bar=CountBarSpec(spacing_in=12.0, size=5, count=134), u_bar_count=218), 42: CSSlabDesign(end_span_ft=42, thickness_in=25, a_bar=ABarSpec(spacing_in=6, size=9, a_ft='44\'-10"', length_ft=46.083333), b_bar=LenBarSpec(spacing_in=6, size=9, length_ft=57.0), c_bar=LenBarSpec(spacing_in=6, size=5, length_ft=25.666667), d_bar=LenBarSpec(spacing_in=6, size=10, length_ft=44.5), e_bar=LenBarSpec(spacing_in=6, size=5, length_ft=18.833333), n_bar=CountBarSpec(spacing_in=15.0, size=6, count=119), m_bar=CountBarSpec(spacing_in=12.0, size=5, count=138), u_bar_count=222), 43: CSSlabDesign(end_span_ft=43, thickness_in=25.5, a_bar=ABarSpec(spacing_in=6, size=9, a_ft='45\'-10"', length_ft=47.083333), b_bar=LenBarSpec(spacing_in=6, size=9, length_ft=58.25), c_bar=LenBarSpec(spacing_in=6, size=5, length_ft=26.25), d_bar=LenBarSpec(spacing_in=6, size=10, length_ft=45.333333), e_bar=LenBarSpec(spacing_in=6, size=5, length_ft=19.25), n_bar=CountBarSpec(spacing_in=15.0, size=6, count=122), m_bar=CountBarSpec(spacing_in=12.0, size=5, count=141), u_bar_count=228), 44: CSSlabDesign(end_span_ft=44, thickness_in=26, a_bar=ABarSpec(spacing_in=6, size=9, a_ft='46\'-10"', length_ft=48.083333), b_bar=LenBarSpec(spacing_in=6, size=9, length_ft=59.5), c_bar=LenBarSpec(spacing_in=6, size=5, length_ft=26.833333), d_bar=LenBarSpec(spacing_in=6, size=10, length_ft=46.25), e_bar=LenBarSpec(spacing_in=6, size=5, length_ft=19.666667), n_bar=CountBarSpec(spacing_in=15.0, size=6, count=125), m_bar=CountBarSpec(spacing_in=12.0, size=5, count=144), u_bar_count=234), 45: CSSlabDesign(end_span_ft=45, thickness_in=26.5, a_bar=ABarSpec(spacing_in=7, size=10, a_ft='48\'-1"', length_ft=49.5), b_bar=LenBarSpec(spacing_in=7, size=10, length_ft=61.25), c_bar=LenBarSpec(spacing_in=6, size=5, length_ft=27.416667), d_bar=LenBarSpec(spacing_in=6, size=10, length_ft=47.0), e_bar=LenBarSpec(spacing_in=6, size=5, length_ft=20.166667), n_bar=CountBarSpec(spacing_in=15.0, size=6, count=127), m_bar=CountBarSpec(spacing_in=12.0, size=5, count=147), u_bar_count=238), 46: CSSlabDesign(end_span_ft=46, thickness_in=27, a_bar=ABarSpec(spacing_in=7, size=10, a_ft='49\'-1"', length_ft=50.5), b_bar=LenBarSpec(spacing_in=7, size=10, length_ft=62.5), c_bar=LenBarSpec(spacing_in=6, size=5, length_ft=28.083333), d_bar=LenBarSpec(spacing_in=6, size=10, length_ft=47.75), e_bar=LenBarSpec(spacing_in=6, size=5, length_ft=20.666667), n_bar=CountBarSpec(spacing_in=15.0, size=6, count=130), m_bar=CountBarSpec(spacing_in=12.0, size=5, count=151), u_bar_count=244)}

CS-1-24 SLAB DATA, keyed by end span (ft). D-bar SIZE is transcribed explicitly per row (it steps 8->9 at span 30 and 9->10 at span 38, which does not line up with the A/B/M-bar thickness thresholds below – do not infer it from t). A/B-bar size steps 8->9 at span 35 (T=21.5) and 9->10 at span 45 (T=26.5); M-bar size steps 4->5 at span 32 (T=20).

class civilpy.structural.odot.continuous_slab_bridge.ContinuousSlabComponent(inp: ContinuousSlabInput)[source]

Bases: object

Analytical component for a 3-span continuous slab (CS-1-24).

structural_model(level: str = 'L1') StructuralModel[source]

Returns a MIDAS-ready StructuralModel (L1 strip or L2 grillage).

class civilpy.structural.odot.continuous_slab_bridge.ContinuousSlabInput(end_span_ft: int, width_ft: float, skew_deg: float = 0.0)[source]

Bases: object

Project dimensions for a 3-span continuous slab bridge (CS-1-24).

end_span_ft: int
skew_deg: float = 0.0
property total_length_ft: float

2 * end_span + interior_span.

Type:

Total length

width_ft: float
class civilpy.structural.odot.continuous_slab_bridge.ContinuousSlabLayout(inputs: ~civilpy.structural.odot.continuous_slab_bridge.ContinuousSlabInput, outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], thickness_in: float, total_length_ft: float, pier_stations: tuple[float, float], bars: tuple[~civilpy.structural.odot.continuous_slab_bridge.BarRun, ...], notes: tuple[str, ...] = <factory>)[source]

Bases: object

The generated three-span continuous slab bridge. outline is the skewed plan parallelogram at z = 0 (top of slab, uniform thickness – haunches over the piers are not modeled); pier_stations are the two pier centerline X coordinates.

bars: tuple[BarRun, ...]
inputs: ContinuousSlabInput
notes: tuple[str, ...]
outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
pier_stations: tuple[float, float]
thickness_in: float
total_length_ft: float
class civilpy.structural.odot.continuous_slab_bridge.CountBarSpec(spacing_in: 'float', size: 'int', count: 'int')[source]

Bases: BarSpec

count: int
civilpy.structural.odot.continuous_slab_bridge.INTERIOR_SPAN_RATIO = 1.25

Interior span = end span * this ratio (fixed on every tabulated row).

civilpy.structural.odot.continuous_slab_bridge.LAP_SPLICE_FT = {4: {'single': 3.0}, 5: {'single': 3.8333333333333335}, 6: {'single': 4.333333333333333}, 8: {'bot': 7.25, 'top': 6.583333333333333}, 9: {'bot': 8.916666666666666, 'top': 7.333333333333333}, 10: {'bot': 10.916666666666666, 'top': 8.75}}

Lap splice lengths by bar size, feet (“TOP”/”BOT” where the sheet gives both; #4/#5/#6 give a single length).

class civilpy.structural.odot.continuous_slab_bridge.LenBarSpec(spacing_in: 'float', size: 'int', length_ft: 'float')[source]

Bases: BarSpec

length_ft: float
civilpy.structural.odot.continuous_slab_bridge.cs_slab_design(end_span_ft: int) CSSlabDesign[source]

Look up the CS-1-24 slab design for an end span (feet, 14-46 tabulated; interior span is always 1.25x, see interior_span_ft()).

Raises ValueError naming the valid spans otherwise.

civilpy.structural.odot.continuous_slab_bridge.interior_span_ft(end_span_ft: float) float[source]

Interior span = end span * 1.25 (fixed ratio, sheet 2’s SLAB DATA “SPANS” column, e.g. 14 ft end -> 17.50 ft interior).

civilpy.structural.odot.continuous_slab_bridge.layout_continuous_slab(inp: ContinuousSlabInput) ContinuousSlabLayout[source]

Generate a three-span continuous slab bridge: plan outline, thickness, pier stations, and the A/B/C/D/E longitudinal bar mats (transverse N/M bars are cataloged by count, not separately drawn).

Raises ValueError for an untabulated end span or a skew beyond the sheet’s 25 deg limit.

civilpy.structural.odot.continuous_slab_bridge.m_bar_offset_in(bridge_limits_ft: float, n_m_bars: int, m_bar_spacing_ft: float) float[source]

Sheet 1’s Y formula: the offset from the bearing line to the first M-bar, Y = 1/2 * [bridge limits - (n_m_bars - 1) * spacing] * 12 (inches).

civilpy.structural.odot.deck_design module

Ohio DOT standard reinforced concrete deck designs (BDM 309.3).

Design policy, the minimum-thickness formula, and the standard deck design table transcribed from the Ohio DOT Bridge Design Manual, 2020 Edition, January 2026 revision, Section 309.3 “Reinforced Concrete Deck on Longitudinal Members” (pp. 3-187 ff.) and Figure 309-3 (p. 3-188). The manual remains the controlling document.

Three things are carried here:

minimum_deck_thickness (BDM 309.3.1)

Tmin (in) = (S + 17)(12) / 36 >= 8.5, S = effective span length in feet per LRFD 9.7.2.3, rounded up to the nearest 1/4 in. The 1 in monolithic wearing surface is included in this thickness but excluded from structural design (BDM 309.1.A).

POLICY (BDM 309.3.2 / 309.2)

The non-negotiable design requirements: approximate elastic (strip) method of LRFD 9.7.3 only — the empirical method (LRFD 9.7.2) and refined methods are prohibited — HL-93 live load, 0.06 ksf future wearing surface, covers, exposure factor, and the standard materials (class QC2 concrete at f’c = 4.5 ksi, Grade 60 epoxy-coated bars).

STANDARD_DECK_DESIGNS (BDM Figure 309-3)

The pre-engineered deck designs for effective spans of 7.0 ft to 14.0 ft in 0.5 ft steps: thicknesses, transverse and longitudinal mats, and the additional overhang bars. standard_deck_design looks a design up by effective span (rounded up to the next 0.5 ft per the figure’s note 2.k) and enforces the figure’s assumption limits.

Railing designations cross-reference the SCDs cataloged in civilpy.structural.odot.bridge_railing. Bar sizes are standard US designators resolved through civilpy.structural.steel.Rebar. Lengths in inches unless a name says otherwise; spans in feet.

class civilpy.structural.odot.deck_design.BarMat(size: int, spacing: float)[source]

Bases: object

One reinforcing mat: bar size at a uniform spacing (in).

property area_per_ft: float

Provided steel area (in^2/ft of deck).

size: int
spacing: float
civilpy.structural.odot.deck_design.DESIGN_METHOD = 'LRFD 9.7.3 approximate elastic (equivalent strip)'

Analysis method mandated by BDM 309.3.2.

class civilpy.structural.odot.deck_design.DeckDesignPolicy(method: str = 'LRFD 9.7.3 approximate elastic (equivalent strip)', live_load: str = 'HL-93', future_wearing_surface_ksf: float = 0.06, monolithic_wearing_surface: float = 1.0, top_cover: float = 2.5, bottom_cover: float = 1.5, exposure_factor: float = 0.75, f_c: float = 4.5, f_y: float = 60.0, concrete_class: str = 'QC2', epoxy_coated: bool = True)[source]

Bases: object

ODOT concrete deck design requirements (BDM 309.3.2, 309.2, and the Figure 309-3 design assumptions). Thicknesses/covers in inches, pressures in ksf, strengths in ksi.

bottom_cover: float = 1.5
concrete_class: str = 'QC2'
epoxy_coated: bool = True
exposure_factor: float = 0.75
f_c: float = 4.5
f_y: float = 60.0
future_wearing_surface_ksf: float = 0.06
live_load: str = 'HL-93'
method: str = 'LRFD 9.7.3 approximate elastic (equivalent strip)'
monolithic_wearing_surface: float = 1.0
top_cover: float = 2.5
class civilpy.structural.odot.deck_design.Haunch(depth: float, flange_width: float)[source]

Bases: object

A concrete haunch per BDM 309.3.5: sides vertical and aligned with the edges of the top flange, so the haunch cross-section is simply flange_width x depth. Depths/widths in inches.

property area: float

Cross-sectional area (in^2).

dead_load_klf(unit_weight_kcf: float = 0.15) float[source]

Haunch self-weight per foot of girder (kip/ft).

depth: float
flange_width: float
civilpy.structural.odot.deck_design.MIN_BEAM_LINES = 4

Figure 309-3 note 2 assumption limits.

civilpy.structural.odot.deck_design.MIN_DESIGN_HAUNCH = 2.0

Minimum design haunch (in) between top of beam/girder flange and bottom of deck (BDM 309.3.5). Haunches absorb unforeseen camber variation so the slab never thins below design.

civilpy.structural.odot.deck_design.MIN_OVERHANG_THICKNESS: dict[str, float] = {'TST-1-99': 18.0, 'TST-2-21': 20.0}

Note 2.k minimum overhang deck thickness overrides for the steel-tube railings (in); these govern over the tabulated overhang thickness.

civilpy.structural.odot.deck_design.POLICY = DeckDesignPolicy(method='LRFD 9.7.3 approximate elastic (equivalent strip)', live_load='HL-93', future_wearing_surface_ksf=0.06, monolithic_wearing_surface=1.0, top_cover=2.5, bottom_cover=1.5, exposure_factor=0.75, f_c=4.5, f_y=60.0, concrete_class='QC2', epoxy_coated=True)

The BDM deck design policy; treat as read-only.

civilpy.structural.odot.deck_design.PROHIBITED_METHODS = ('LRFD 9.7.2 empirical design', 'refined methods of analysis')

Methods BDM 309.3.2 explicitly prohibits for ODOT deck design.

civilpy.structural.odot.deck_design.STANDARD_DECK_DESIGNS: tuple[StandardDeckDesign, ...] = (StandardDeckDesign(effective_span_ft=7.0, deck_thickness=8.5, overhang_thickness=10.5, transverse_top=BarMat(size=5, spacing=6.0), transverse_bottom=BarMat(size=5, spacing=6.0), longitudinal_top=BarMat(size=4, spacing=12.5), longitudinal_bottom=BarMat(size=5, spacing=10.75), overhang_bar_size=5, overhang_cutoff=54.0), StandardDeckDesign(effective_span_ft=7.5, deck_thickness=8.5, overhang_thickness=10.5, transverse_top=BarMat(size=5, spacing=6.0), transverse_bottom=BarMat(size=5, spacing=6.0), longitudinal_top=BarMat(size=4, spacing=12.0), longitudinal_bottom=BarMat(size=5, spacing=10.25), overhang_bar_size=5, overhang_cutoff=54.0), StandardDeckDesign(effective_span_ft=8.0, deck_thickness=8.5, overhang_thickness=10.5, transverse_top=BarMat(size=5, spacing=6.0), transverse_bottom=BarMat(size=5, spacing=6.0), longitudinal_top=BarMat(size=4, spacing=11.5), longitudinal_bottom=BarMat(size=5, spacing=9.75), overhang_bar_size=5, overhang_cutoff=54.0), StandardDeckDesign(effective_span_ft=8.5, deck_thickness=8.5, overhang_thickness=10.5, transverse_top=BarMat(size=5, spacing=5.75), transverse_bottom=BarMat(size=5, spacing=5.75), longitudinal_top=BarMat(size=4, spacing=11.0), longitudinal_bottom=BarMat(size=5, spacing=9.25), overhang_bar_size=4, overhang_cutoff=54.0), StandardDeckDesign(effective_span_ft=9.0, deck_thickness=8.75, overhang_thickness=10.75, transverse_top=BarMat(size=5, spacing=5.75), transverse_bottom=BarMat(size=5, spacing=5.75), longitudinal_top=BarMat(size=4, spacing=11.0), longitudinal_bottom=BarMat(size=5, spacing=9.25), overhang_bar_size=4, overhang_cutoff=54.0), StandardDeckDesign(effective_span_ft=9.5, deck_thickness=9.0, overhang_thickness=11.0, transverse_top=BarMat(size=5, spacing=5.75), transverse_bottom=BarMat(size=5, spacing=5.75), longitudinal_top=BarMat(size=4, spacing=11.0), longitudinal_bottom=BarMat(size=5, spacing=9.25), overhang_bar_size=4, overhang_cutoff=54.0), StandardDeckDesign(effective_span_ft=10.0, deck_thickness=9.0, overhang_thickness=11.0, transverse_top=BarMat(size=5, spacing=5.25), transverse_bottom=BarMat(size=5, spacing=5.25), longitudinal_top=BarMat(size=4, spacing=10.0), longitudinal_bottom=BarMat(size=5, spacing=8.75), overhang_bar_size=4, overhang_cutoff=48.0), StandardDeckDesign(effective_span_ft=10.5, deck_thickness=9.25, overhang_thickness=11.25, transverse_top=BarMat(size=5, spacing=5.25), transverse_bottom=BarMat(size=5, spacing=5.25), longitudinal_top=BarMat(size=4, spacing=10.0), longitudinal_bottom=BarMat(size=5, spacing=8.75), overhang_bar_size=4, overhang_cutoff=48.0), StandardDeckDesign(effective_span_ft=11.0, deck_thickness=9.5, overhang_thickness=11.5, transverse_top=BarMat(size=5, spacing=5.0), transverse_bottom=BarMat(size=5, spacing=5.0), longitudinal_top=BarMat(size=4, spacing=9.5), longitudinal_bottom=BarMat(size=5, spacing=8.75), overhang_bar_size=4, overhang_cutoff=48.0), StandardDeckDesign(effective_span_ft=11.5, deck_thickness=9.5, overhang_thickness=11.5, transverse_top=BarMat(size=6, spacing=5.75), transverse_bottom=BarMat(size=5, spacing=5.75), longitudinal_top=BarMat(size=4, spacing=7.75), longitudinal_bottom=BarMat(size=5, spacing=8.75), overhang_bar_size=4, overhang_cutoff=28.0), StandardDeckDesign(effective_span_ft=12.0, deck_thickness=9.75, overhang_thickness=11.75, transverse_top=BarMat(size=6, spacing=5.75), transverse_bottom=BarMat(size=5, spacing=5.75), longitudinal_top=BarMat(size=4, spacing=7.75), longitudinal_bottom=BarMat(size=5, spacing=8.75), overhang_bar_size=4, overhang_cutoff=28.0), StandardDeckDesign(effective_span_ft=12.5, deck_thickness=10.0, overhang_thickness=12.0, transverse_top=BarMat(size=6, spacing=5.75), transverse_bottom=BarMat(size=5, spacing=5.75), longitudinal_top=BarMat(size=4, spacing=7.75), longitudinal_bottom=BarMat(size=5, spacing=8.75), overhang_bar_size=None, overhang_cutoff=None), StandardDeckDesign(effective_span_ft=13.0, deck_thickness=10.0, overhang_thickness=12.0, transverse_top=BarMat(size=6, spacing=5.75), transverse_bottom=BarMat(size=5, spacing=5.75), longitudinal_top=BarMat(size=4, spacing=7.75), longitudinal_bottom=BarMat(size=5, spacing=8.75), overhang_bar_size=None, overhang_cutoff=None), StandardDeckDesign(effective_span_ft=13.5, deck_thickness=10.25, overhang_thickness=12.25, transverse_top=BarMat(size=6, spacing=5.75), transverse_bottom=BarMat(size=5, spacing=5.75), longitudinal_top=BarMat(size=4, spacing=7.75), longitudinal_bottom=BarMat(size=5, spacing=8.75), overhang_bar_size=None, overhang_cutoff=None), StandardDeckDesign(effective_span_ft=14.0, deck_thickness=10.5, overhang_thickness=12.5, transverse_top=BarMat(size=6, spacing=5.75), transverse_bottom=BarMat(size=5, spacing=5.75), longitudinal_top=BarMat(size=4, spacing=7.75), longitudinal_bottom=BarMat(size=5, spacing=8.75), overhang_bar_size=None, overhang_cutoff=None))

BDM Figure 309-3, one entry per tabulated effective span.

class civilpy.structural.odot.deck_design.StandardDeckDesign(effective_span_ft: float, deck_thickness: float, overhang_thickness: float, transverse_top: BarMat, transverse_bottom: BarMat, longitudinal_top: BarMat, longitudinal_bottom: BarMat, overhang_bar_size: int | None, overhang_cutoff: float | None)[source]

Bases: object

One row of BDM Figure 309-3.

deck_thickness and overhang_thickness are totals including the 1 in monolithic wearing surface. overhang_bar_size / overhang_cutoff are the additional overhang bar and the length (in) beyond the fascia beam/girder centerline where it is no longer required (note 5); both are None where the figure tabulates none. Longitudinal spacings exclude the additional negative-moment reinforcement required over piers (note 6; LRFD 6.10.1.7 / 5.6.3.2).

deck_thickness: float
effective_span_ft: float
longitudinal_bottom: BarMat
longitudinal_top: BarMat
overhang_bar_size: int | None
overhang_cutoff: float | None
overhang_thickness: float
transverse_bottom: BarMat
transverse_top: BarMat
civilpy.structural.odot.deck_design.VALID_RAILINGS: tuple[str, ...] = ('BR-1-13', 'SBR-1-20', 'SBR-2-20', 'SBR-3-20', 'BR-2-15', 'TST-1-99', 'TST-2-21')

Railing SCDs the overhang design is valid for (note 2.k); designations resolve through civilpy.structural.odot.bridge_railing.railing().

civilpy.structural.odot.deck_design.haunch_depth_at(design_haunch: float, camber_residual: float) float[source]

Theoretical haunch depth (in) at a station where the girder sits camber_residual inches BELOW its theoretical profile (positive = girder low -> deeper haunch; negative = girder high -> shallower). The result may fall below MIN_DESIGN_HAUNCH — that is the signal the design haunch must be increased, not clamped away.

civilpy.structural.odot.deck_design.minimum_deck_thickness(effective_span_ft: float) float[source]

Minimum total deck thickness (in) per BDM 309.3.1.

Tmin = (S + 17)(12)/36 >= 8.5 in rounded up to the nearest 1/4 in, where effective_span_ft is the effective span length per LRFD 9.7.2.3. Includes the 1 in monolithic wearing surface; subtract DeckDesignPolicy.monolithic_wearing_surface for the structural design thickness.

civilpy.structural.odot.deck_design.overhang_thickness(design: StandardDeckDesign, railing: str | None = None) float[source]

Overhang deck thickness (in) for a standard design, applying the note 2.k minimums for the TST steel-tube railings when they govern.

civilpy.structural.odot.deck_design.secondary_longitudinal_reinforcement(main: BarMat) BarMat[source]

Minimum longitudinal top-mat (secondary) reinforcement per BDM 309.3.4.1: at least 1/3 of the main (transverse) reinforcement, spaced uniformly, detailed as #4 bars — unless that would put the #4s closer than 3 in, in which case a larger bar at >= 3 in spacing is returned.

Applies the 1/3 rule to the provided main steel, which is slightly conservative against BDM Figure 309-3 (whose longitudinal mats derive from the required steel); for spans the figure tabulates, use the figure’s mats — this helper is for custom designs outside it.

civilpy.structural.odot.deck_design.standard_deck_design(effective_span_ft: float, *, railing: str | None = None, beam_lines: int | None = None, beam_spacing_ft: float | None = None, overhang_ft: float | None = None) StandardDeckDesign[source]

Look up the BDM Figure 309-3 standard design for an effective span.

effective_span_ft is the effective span length per LRFD 9.7.3.2; it is rounded up to the next tabulated 0.5 ft increment (note 2.k). The optional keywords assert the figure’s design assumptions — railing (SCD designation, note 2.k), beam_lines (>= 4, note 2.a), beam_spacing_ft (<= 15 ft, note 2.b) and overhang_ft (<= 4 ft, note 2.j) — and raise ValueError when the standard designs do not apply, in which case the deck must be designed per BDM 309.3.2 instead.

civilpy.structural.odot.deck_design.structural_design_thickness(total_thickness: float) float[source]

Deck thickness used in structural design (in): the total thickness minus the monolithic wearing surface (BDM 309.3.1 / 309.1.A).

civilpy.structural.odot.drip_strip module

ODOT DS-1-92 Drip Strip for Structures with Over the Side Drainage.

Transcribed from Ohio DOT Standard Construction Drawing DS-1-92 (revised 07-15-22, 2 sheets). The drawing remains the controlling document.

The drip strip is a bent stainless steel sheet cast into (or fastened to) the fascia edge of the deck: a 4-1/2 in perforated plate is embedded horizontally with a 3 in leg bent up 90 degrees against the formwork; after form removal the leg is bent out to its final 45 degree position. The lower strip runs continuously along the full length of each side of the bridge (pieces tightly butted, never lapped); a short upper strip (1’-6” for DBR-2-73 and TST-1-99 railings, 2’-0” for TST-2-21) is added at each railing post, its leg turned up while the lower strip’s leg turns down. On prestressed box beams without a cast deck the bent strips are instead fastened to the beam edge with 1-1/4 in x 3/32 in button head spikes with deformed shanks or expansion anchors at 1’-6” c/c max, all devices galvanized or stainless.

Material: stainless steel, minimum 22 gage, ASTM A167 Type 304, mill finish. Measurement: by the foot, totaling upper and lower strips (pay item “Special, Steel Drip Strip”).

Conventions match the other SCD modules: plan lengths in feet, section dimensions in inches.

class civilpy.structural.odot.drip_strip.DripStripPlacement(railing: str, upper_strip_length_in: float, root_depth_in: float)[source]

Bases: object

Upper-strip length and the strip root depth below the deck (or wearing) surface for one railing type.

railing: str
root_depth_in: float
upper_strip_length_in: float
civilpy.structural.odot.drip_strip.STRUCTURE_TYPES = ('concrete slab', 'noncomposite box beam', 'composite box beam')

Deck/structure families the sheet details (each shown with all three railings; “deck on concrete or steel beam similar”).

class civilpy.structural.odot.drip_strip.StripRun(kind: str, start_ft: float, end_ft: float)[source]

Bases: object

One strip piece along the fascia: stations in feet from the start of the run, plus which profile it carries.

end_ft: float
kind: str
property length_ft: float
start_ft: float
civilpy.structural.odot.drip_strip.drip_strip_runs(length_ft: float, post_stations_ft: tuple[float, ...], railing: str) tuple[StripRun, ...][source]

The strip pieces along ONE fascia edge: the continuous lower strip over the full length plus an upper strip centered at each railing post (clipped to the fascia). Raises ValueError for an unknown railing or non-positive length.

civilpy.structural.odot.drip_strip.hole_centers_in(strip_length_in: float) list[tuple[float, float]][source]

Perforation centers over a strip of the given length, in the embedded-plate plane: (s, w) with s along the strip from its start and w measured from the bend line into the deck (0 to EMBED_WIDTH_IN).

Two staggered rows 1-1/2 in from each plate edge, 4 in c/c along each row, second row offset 2 in (view G-G).

civilpy.structural.odot.drip_strip.pay_length_ft(runs: tuple[StripRun, ...], sides: int = 1) float[source]

Measured length (ft): the total of upper and lower strips. sides=2 doubles a single-fascia takeoff for both edges.

civilpy.structural.odot.drip_strip.placement(railing: str) DripStripPlacement[source]

Placement data for a railing type; raises ValueError listing the railings DS-1-92 details.

civilpy.structural.odot.drip_strip.strip_profile_in(kind: str, *, bent: bool = True, include_embedded: bool = True) tuple[tuple[float, float], ...][source]

Cross-section polyline of one strip, inches, in the (h, v) plane: h positive outward from the fascia face (h = 0 at the bend line), v positive up.

kind is "upper" (leg turned up 45 degrees) or "lower" (leg turned down). bent=False gives the pre-placement shape (leg vertical against the form). include_embedded=False returns only the exposed leg.

civilpy.structural.odot.drip_strip.upper_strip_length_in(railing: str) float[source]

civilpy.structural.odot.fixed_bearing module

Ohio DOT fixed bearings for steel beam and girder bridges (FB-1-82).

Dimension and capacity table transcribed from Ohio DOT Standard Bridge Drawing FB-1-82 (Office of Structural Engineering, rev. 05-10-1982, rev. 07-19-2024). The drawing remains the controlling document.

Each row is a pin-bearing assembly: a masonry (base) plate F x G, a cylindrical bearing pin of diameter DIA, and a top plate A x B under the girder, overall height H. F-50/F-100 use only 2 anchor rods (diagonally opposite corners, note 1); F-350/F-400 require bearing stiffeners both sides of the girder web (note 2).

Design basis (General Notes): AASHTO Standard Specifications (1977 + 1978- 1981 interims) + Ohio supplement, masonry plates designed for 30,000 psi allowable bending, uniform bearing distribution assumed. Anchor rods are 1-1/4 in dia x 1’-7 in long in 1-5/8 in dia holes. Lateral expansion clearance is 1/8 in per end for superstructure widths up to 120 ft (1/4 in for widths over 60 ft, per the note’s own overlapping ranges – see LATERAL_CLEARANCE_IN/LATERAL_CLEARANCE_WIDE_IN).

Dimensions in inches, weight in pounds, load in pounds. Spot-checked against the drawing in the test suite.

civilpy.structural.odot.fixed_bearing.DIM_LETTERS: tuple[str, ...] = ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'K', 'DIA')

Dimension letters in FB-1-82 table column order.

civilpy.structural.odot.fixed_bearing.FIXED_BEARINGS: dict[str, FixedBearing] = {'F-100': FixedBearing(designation='F-100', max_load_lb=100000, dims={'A': 7, 'B': 9, 'C': 1.75, 'D': 4, 'E': 1.5, 'F': 9, 'G': 18, 'H': 1.5, 'K': 5.625, 'DIA': 2}, weight_lb=143, two_anchor_rods=True, stiffeners_required=False), 'F-150': FixedBearing(designation='F-150', max_load_lb=150000, dims={'A': 9, 'B': 9, 'C': 2.5, 'D': 5, 'E': 1.5, 'F': 11, 'G': 20, 'H': 2, 'K': 6.875, 'DIA': 2.5}, weight_lb=244, two_anchor_rods=False, stiffeners_required=False), 'F-200': FixedBearing(designation='F-200', max_load_lb=200000, dims={'A': 10, 'B': 10, 'C': 3, 'D': 6, 'E': 2, 'F': 11, 'G': 22, 'H': 2, 'K': 7.875, 'DIA': 2.5}, weight_lb=300, two_anchor_rods=False, stiffeners_required=False), 'F-250': FixedBearing(designation='F-250', max_load_lb=250000, dims={'A': 11, 'B': 10, 'C': 3.5, 'D': 7, 'E': 2, 'F': 12, 'G': 24, 'H': 2.5, 'K': 8.875, 'DIA': 3}, weight_lb=400, two_anchor_rods=False, stiffeners_required=False), 'F-300': FixedBearing(designation='F-300', max_load_lb=300000, dims={'A': 12, 'B': 11, 'C': 3.75, 'D': 8, 'E': 2.5, 'F': 14, 'G': 25, 'H': 2.5, 'K': 9.625, 'DIA': 3}, weight_lb=502, two_anchor_rods=False, stiffeners_required=False), 'F-350': FixedBearing(designation='F-350', max_load_lb=350000, dims={'A': 12, 'B': 11, 'C': 3.75, 'D': 8, 'E': 2.5, 'F': 16, 'G': 25, 'H': 2.5, 'K': 9.625, 'DIA': 3}, weight_lb=540, two_anchor_rods=False, stiffeners_required=True), 'F-400': FixedBearing(designation='F-400', max_load_lb=400000, dims={'A': 12, 'B': 12, 'C': 3.75, 'D': 8, 'E': 2.5, 'F': 18, 'G': 26, 'H': 2.5, 'K': 9.625, 'DIA': 3}, weight_lb=610, two_anchor_rods=False, stiffeners_required=True), 'F-50': FixedBearing(designation='F-50', max_load_lb=50000, dims={'A': 6, 'B': 6, 'C': 1.5, 'D': 3, 'E': 1.25, 'F': 8, 'G': 16, 'H': 1.5, 'K': 5.625, 'DIA': 2}, weight_lb=100, two_anchor_rods=True, stiffeners_required=False)}

Fixed-bearing lines keyed by designation (“F-50” .. “F-400”).

class civilpy.structural.odot.fixed_bearing.FixedBearing(designation: str, max_load_lb: float, dims: dict[str, float], weight_lb: float, two_anchor_rods: bool = False, stiffeners_required: bool = False)[source]

Bases: object

One FB-1-82 fixed-bearing capacity line.

two_anchor_rods (note 1) is true only for F-50/F-100; otherwise 4 anchor rods are used (one per masonry-plate corner). stiffeners_required (note 2) is true only for F-350/F-400.

designation: str
dims: dict[str, float]
max_load_lb: float
stiffeners_required: bool = False
two_anchor_rods: bool = False
weight_lb: float
class civilpy.structural.odot.fixed_bearing.FixedBearingLayout(fb: civilpy.structural.odot.fixed_bearing.FixedBearing, base_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], base_thickness_in: float, top_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], top_z_in: float, pin_diameter_in: float, pin_center: tuple[float, float, float], notes: tuple[str, ...] = <factory>)[source]

Bases: object

base_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
base_thickness_in: float
fb: FixedBearing
notes: tuple[str, ...]
pin_center: tuple[float, float, float]
pin_diameter_in: float
top_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
top_z_in: float
civilpy.structural.odot.fixed_bearing.LATERAL_CLEARANCE_IN = 0.125

Lateral expansion clearance per end of the bearing pin, inches.

civilpy.structural.odot.fixed_bearing.fixed_bearing(designation: str) FixedBearing[source]

Look up a FB-1-82 fixed-bearing line by designation (“F-50”, …, “F-400”). Raises ValueError naming the valid designations otherwise.

civilpy.structural.odot.fixed_bearing.lateral_clearance_in(superstructure_width_ft: float) float[source]

Lateral expansion clearance per end of the bearing pin (General Notes): 1/8 in normally, 1/4 in for a superstructure over 60 ft wide (up to the 120 ft this note addresses).

civilpy.structural.odot.fixed_bearing.layout_fixed_bearing(fb: FixedBearing) FixedBearingLayout[source]

Generate the drawable subset of one FB-1-82 line: the masonry plate, the top plate, and the bearing pin centerline.

E is used as the masonry plate thickness (it is the smallest tabulated dimension, consistent with a base-plate thickness) and H as the clearance from the top of that plate to the pin center, so the stack (plate + pin + top plate) is self-consistent even though the sheet does not label a dimension “base plate thickness” outright – see SCD_BUILD_QUESTIONS.md.

civilpy.structural.odot.fixed_bearing.smallest_for_load(load_lb: float) FixedBearing[source]

The lightest standard fixed bearing whose maximum load covers load_lb; raises ValueError if the load exceeds the F-400 line.

civilpy.structural.odot.full_height_headwall module

Ohio DOT full-height headwalls (HW-1.1).

Transcribed from Ohio DOT Standard Bridge Drawing HW-1.1, “Full-Height Headwalls” (rev. 07-18-2025, 2 sheets). The drawing remains the controlling document.

HW-1.1 covers full-height headwalls with wingwalls for circular pipe or pipe-arch culverts, 42 to 84 in inclusive, skewed or non-skewed. Type A (skew_deg <= 10) uses a wingwall symmetrical about the culvert centerline, flared 45 deg each side; Type B (skew_deg > 10) uses an asymmetric pair of wingwalls flared 45 - skew/2 and 45 + skew/2 deg off the culvert centerline (sheet 1 plan views). The dimension table (sheet 2) tabulates quantities at four discrete skew angles (0, 15, 30, 45 deg); intermediate skews use the nearest tabulated bucket, which is standard ODOT practice for this drawing (its own title reads “theta ~=”).

Design basis (sheet 1 notes): internal friction angle of backfill soil phi_bf = 30 deg, backfill unit weight = 120 pcf, foundation soil drained friction angle phi_f = 28 deg, foundation undrained shear strength = 1500 psf, concrete unit weight = 150 pcf, backfill slope = 2:1. Concrete Class QC1 (f’c = 4000 psi). Reinforcing steel ASTM A615/A616/A617 Grade 60, epoxy coated.

Conventions match civilpy.structural.odot.headwall: X along the culvert/wall centerline is not used here – instead Y is along the headwall face (wingwall spread direction), X is out from the culvert centerline (positive downstream), Z is up with z = 0 at the flow line / wall base. Feet in plan, inches only where the sheet itself uses them (pipe diameter, chamfer, weepholes).

civilpy.structural.odot.full_height_headwall.FULL_HEIGHT_HEADWALLS: dict[float, FullHeightHeadwallDesign] = {42.0: FullHeightHeadwallDesign(diameter_in=42.0, height_ft=5.333333333333333, a_ft=3.25, b_ft=1.5, c_ft=2.5, ts_ft=1.5, bar_size=5, skews=(SkewGroup(skew_deg=0.0, L1=None, L2=3.5833333333333335, h1=None, h2=3.5, concrete_cmp_cy=7.2, concrete_rcp_cy=7.1, steel_lb=695), SkewGroup(skew_deg=15.0, L1=8.75, L2=4.5, h1=4.083333333333333, h2=3.5833333333333335, concrete_cmp_cy=7.6, concrete_rcp_cy=7.5, steel_lb=656), SkewGroup(skew_deg=30.0, L1=7.833333333333333, L2=5.75, h1=3.5833333333333335, h2=3.6666666666666665, concrete_cmp_cy=7.8, concrete_rcp_cy=7.7, steel_lb=688), SkewGroup(skew_deg=45.0, L1=7.833333333333333, L2=7.75, h1=3.5833333333333335, h2=3.6666666666666665, concrete_cmp_cy=9.0, concrete_rcp_cy=8.9, steel_lb=794))), 48.0: FullHeightHeadwallDesign(diameter_in=48.0, height_ft=5.833333333333333, a_ft=3.5, b_ft=1.5, c_ft=2.75, ts_ft=1.5, bar_size=5, skews=(SkewGroup(skew_deg=0.0, L1=None, L2=4.333333333333333, h1=None, h2=3.75, concrete_cmp_cy=8.8, concrete_rcp_cy=8.6, steel_lb=861), SkewGroup(skew_deg=15.0, L1=10.0, L2=5.333333333333333, h1=4.5, h2=3.8333333333333335, concrete_cmp_cy=9.3, concrete_rcp_cy=9.1, steel_lb=806), SkewGroup(skew_deg=30.0, L1=8.75, L2=6.833333333333333, h1=3.8333333333333335, h2=3.9166666666666665, concrete_cmp_cy=9.4, concrete_rcp_cy=9.2, steel_lb=833), SkewGroup(skew_deg=45.0, L1=8.75, L2=9.166666666666666, h1=3.8333333333333335, h2=4.0, concrete_cmp_cy=10.9, concrete_rcp_cy=10.8, steel_lb=970))), 54.0: FullHeightHeadwallDesign(diameter_in=54.0, height_ft=6.416666666666667, a_ft=3.75, b_ft=1.5, c_ft=3.0, ts_ft=1.5, bar_size=5, skews=(SkewGroup(skew_deg=0.0, L1=None, L2=5.166666666666667, h1=None, h2=4.166666666666667, concrete_cmp_cy=10.8, concrete_rcp_cy=10.5, steel_lb=1001), SkewGroup(skew_deg=15.0, L1=11.333333333333334, L2=6.25, h1=5.0, h2=4.166666666666667, concrete_cmp_cy=11.3, concrete_rcp_cy=11.0, steel_lb=977), SkewGroup(skew_deg=30.0, L1=9.666666666666666, L2=7.916666666666667, h1=4.166666666666667, h2=4.25, concrete_cmp_cy=11.2, concrete_rcp_cy=11.0, steel_lb=1002), SkewGroup(skew_deg=45.0, L1=9.666666666666666, L2=10.583333333333334, h1=4.166666666666667, h2=4.333333333333333, concrete_cmp_cy=13.1, concrete_rcp_cy=12.9, steel_lb=1149))), 60.0: FullHeightHeadwallDesign(diameter_in=60.0, height_ft=7.0, a_ft=4.0, b_ft=1.5, c_ft=3.25, ts_ft=1.5, bar_size=5, skews=(SkewGroup(skew_deg=0.0, L1=None, L2=5.916666666666667, h1=None, h2=4.416666666666667, concrete_cmp_cy=12.7, concrete_rcp_cy=12.4, steel_lb=1151), SkewGroup(skew_deg=15.0, L1=12.583333333333334, L2=7.166666666666667, h1=5.333333333333333, h2=4.5, concrete_cmp_cy=13.4, concrete_rcp_cy=13.1, steel_lb=1127), SkewGroup(skew_deg=30.0, L1=10.583333333333334, L2=9.0, h1=4.333333333333333, h2=4.583333333333333, concrete_cmp_cy=13.2, concrete_rcp_cy=12.9, steel_lb=1124), SkewGroup(skew_deg=45.0, L1=10.583333333333334, L2=12.0, h1=4.333333333333333, h2=4.583333333333333, concrete_cmp_cy=15.4, concrete_rcp_cy=15.1, steel_lb=1306))), 72.0: FullHeightHeadwallDesign(diameter_in=72.0, height_ft=8.166666666666666, a_ft=4.5, b_ft=1.5833333333333335, c_ft=3.75, ts_ft=1.5, bar_size=7, skews=(SkewGroup(skew_deg=0.0, L1=None, L2=7.416666666666667, h1=None, h2=5.0, concrete_cmp_cy=17.5, concrete_rcp_cy=17.1, steel_lb=1808), SkewGroup(skew_deg=15.0, L1=15.083333333333334, L2=8.916666666666666, h1=6.166666666666667, h2=5.083333333333333, concrete_cmp_cy=18.5, concrete_rcp_cy=18.0, steel_lb=1803), SkewGroup(skew_deg=30.0, L1=12.416666666666666, L2=11.166666666666666, h1=4.833333333333333, h2=5.166666666666667, concrete_cmp_cy=18.0, concrete_rcp_cy=17.5, steel_lb=1770), SkewGroup(skew_deg=45.0, L1=12.416666666666666, L2=14.833333333333334, h1=4.833333333333333, h2=5.25, concrete_cmp_cy=21.0, concrete_rcp_cy=20.6, steel_lb=2080))), 84.0: FullHeightHeadwallDesign(diameter_in=84.0, height_ft=9.333333333333334, a_ft=5.0, b_ft=1.8333333333333335, c_ft=4.25, ts_ft=1.5, bar_size=8, skews=(SkewGroup(skew_deg=0.0, L1=None, L2=9.0, h1=None, h2=5.666666666666667, concrete_cmp_cy=24.6, concrete_rcp_cy=24.0, steel_lb=2608), SkewGroup(skew_deg=15.0, L1=17.583333333333332, L2=10.75, h1=7.0, h2=5.75, concrete_cmp_cy=25.7, concrete_rcp_cy=25.1, steel_lb=2563), SkewGroup(skew_deg=30.0, L1=14.583333333333334, L2=13.333333333333334, h1=5.5, h2=5.833333333333333, concrete_cmp_cy=25.1, concrete_rcp_cy=24.5, steel_lb=2559), SkewGroup(skew_deg=45.0, L1=14.25, L2=17.666666666666668, h1=5.333333333333333, h2=5.833333333333333, concrete_cmp_cy=28.9, concrete_rcp_cy=28.3, steel_lb=2943)))}

HW-1.1 “FULL-HEIGHT HEADWALLS (ENGLISH)” table, sheet 2, keyed by pipe diameter (inches). L/H columns in feet-inches on the sheet, converted with _fi(); concrete in CY, steel in lbs.

class civilpy.structural.odot.full_height_headwall.FullHeightHeadwallDesign(diameter_in: float, height_ft: float, a_ft: float, b_ft: float, c_ft: float, ts_ft: float, bar_size: int, skews: tuple[SkewGroup, ...])[source]

Bases: object

One HW-1.1 table row (a pipe diameter), with all four skew columns.

a_ft: float
b_ft: float
bar_size: int
c_ft: float
diameter_in: float
height_ft: float
skew(skew_deg: float) SkewGroup[source]

The tabulated column for the nearest skew bucket to skew_deg.

skews: tuple[SkewGroup, ...]
ts_ft: float
class civilpy.structural.odot.full_height_headwall.FullHeightHeadwallLayout(inputs: ~civilpy.structural.odot.full_height_headwall.HeadwallInput, table: ~civilpy.structural.odot.full_height_headwall.FullHeightHeadwallDesign, skew: ~civilpy.structural.odot.full_height_headwall.SkewGroup, skew_bucket_deg: float, type_: str, center_face: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], wing1: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], wing2: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], concrete_cy: float, steel_lb: float, notes: tuple[str, ...] = <factory>)[source]

Bases: object

The generated headwall+wingwall unit.

center_face is the vertical rectangular panel at the culvert centerline (X-Z plane at y = 0, width D centered on x = 0, height H); wing1/wing2 are the two wingwall planes as (near_top, near_base, far_base, far_top) quads swept from the center face’s top corners out to each wingwall’s far end. wing1 is the acute-side (L1/h1) wingwall, wing2 the obtuse-side (L2/h2) wingwall; for Type A (skew snapped to 0) both use the L2/h2 data and are mirror images. Origin: x = 0 on the culvert centerline, y = 0 at the headwall front face (wall behind, +y downstream), z = 0 at the flow line / wall base.

center_face: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
concrete_cy: float
inputs: HeadwallInput
notes: tuple[str, ...]
skew: SkewGroup
skew_bucket_deg: float
steel_lb: float
table: FullHeightHeadwallDesign
type_: str
wing1: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
wing2: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
class civilpy.structural.odot.full_height_headwall.HeadwallInput(diameter_in: float, skew_deg: float = 0.0)[source]

Bases: object

Inputs for a full-height headwall + wingwall solid.

diameter_in must be a tabulated pipe diameter; skew_deg is snapped to the nearest tabulated bucket (0/15/30/45 deg – see nearest_skew_bucket()).

diameter_in: float
skew_deg: float = 0.0
civilpy.structural.odot.full_height_headwall.MIN_DIAMETER_IN = 42.0

Applicable pipe diameter/rise range (sheet 1 “APPLICATION” note).

civilpy.structural.odot.full_height_headwall.SKEW_BUCKETS: tuple[float, ...] = (0.0, 15.0, 30.0, 45.0)

The dimension table only tabulates quantities at these nominal skew angles; nearest_skew_bucket snaps any input to the closest one.

class civilpy.structural.odot.full_height_headwall.SkewGroup(skew_deg: float, L1: float | None, L2: float, h1: float | None, h2: float, concrete_cmp_cy: float, concrete_rcp_cy: float, steel_lb: float)[source]

Bases: object

One skew-angle column of the HW-1.1 table for a given pipe diameter.

L1/h1 are None at skew_deg == 0 (Type A: only one wingwall shape, tabulated as L2/h2, symmetric about the centerline).

L1: float | None
L2: float
concrete_cmp_cy: float
concrete_rcp_cy: float
h1: float | None
h2: float
skew_deg: float
steel_lb: float
civilpy.structural.odot.full_height_headwall.full_height_headwall_design(diameter_in: float) FullHeightHeadwallDesign[source]

Look up the HW-1.1 table row for a pipe diameter (inches).

Raises ValueError naming the tabulated sizes if diameter_in is not one of them.

civilpy.structural.odot.full_height_headwall.layout_full_height_headwall(inp: HeadwallInput) FullHeightHeadwallLayout[source]

Generate the full-height headwall + wingwall solid.

Raises ValueError (via full_height_headwall_design()) for an untabulated pipe diameter, and (via nearest_skew_bucket()) for a skew beyond the table’s 45 deg range.

civilpy.structural.odot.full_height_headwall.nearest_skew_bucket(skew_deg: float) float[source]

Snap a skew angle to the nearest tabulated bucket (0/15/30/45 deg).

The 0 deg cutoff is pinned to SKEW_TYPE_A_MAX_DEG (10 deg) – sheet 1’s own Type A/B boundary – rather than the halfway point (7.5 deg) so a skew that the sheet calls Type A never gets Type B’s asymmetric wingwall data; 15/30/45 split at their halfway points (22.5, 37.5) as plain nearest-neighbor. Raises ValueError for a skew outside the table’s range (sheet 1 tabulates through 45 deg only; beyond that the standard drawing does not apply).

civilpy.structural.odot.guardrail module

Ohio DOT Midwest Guardrail System (MGS) roadway drawings.

Geometry and layout transcribed from the Ohio DOT Standard Roadway Construction Drawings, MGS series (Office of Roadway Engineering). The standard system parameters (rail height, post spacing, blockouts, post sections) come from MGS-2.1; the series registry maps every MGS drawing and flags the bridge terminal assemblies that connect a guardrail run to the bridge railings cataloged in civilpy.structural.odot.bridge_railing.

Lengths are in inches unless a field name says otherwise. Values are spot-checked against the cited drawings in the test suite; the drawings remain the controlling document for detailing.

Beyond the MGS-2.1 system parameters this module carries the three bridge terminal assemblies as typed post-by-post layouts (BRIDGE_TERMINALS / layout_bridge_terminal()) — the guardrail-to-bridge-railing hardware — and a standard- run post/panel layout (layout_mgs_run()).

Sources (SCD number — latest cited revision):

MGS-2.1 Midwest Guardrail System, Standard Type MGS (rev. 2026-01-16) MGS-3.1 MGS Bridge Terminal Assembly, Type 1 (rev. 2026-01-16) MGS-3.2 MGS Bridge Terminal Assembly, Type 2 (rev. 2025-07-18) MGS-3.3 MGS Bridge Terminal Assembly, Type TST-2 (rev. 2026-01-16) MGS-4.3 Guardrail Transitions (rev. 2025-07-18) (plus the full MGS series registry, MGS_DRAWINGS)

class civilpy.structural.odot.guardrail.BridgeTerminalAssembly(scd: str, scd_date: str, designation: str, origin: str, start_offset_in: float, post_spacings_in: tuple[float, ...], post_groups: tuple[TerminalPostGroup, ...] = (), rail_elements: tuple[str, ...] = (), connection: str = '', curb_note: str = '', connects_to: tuple[str, ...] = (), pay_item: str = '', notes: str = '')[source]

Bases: object

One MGS bridge terminal assembly (SCD MGS-3.1 / 3.2 / 3.3).

post_spacings_in are the successive c/c spacings starting from origin (each sheet’s own stationing direction); start_offset_in is the distance from the origin to post 1. rail_elements list the transition rail pieces in the same order. Payment is Item 606, Each.

connection: str = ''
connects_to: tuple[str, ...] = ()
curb_note: str = ''
designation: str
property length_in: float

Origin to the last post, inches.

property n_posts: int
notes: str = ''
origin: str

what post 1 is measured from

pay_item: str = ''
post_groups: tuple[TerminalPostGroup, ...] = ()
post_spacings_in: tuple[float, ...]
post_stations_in() tuple[float, ...][source]

Post centers (inches) from origin.

rail_elements: tuple[str, ...] = ()
scd: str
scd_date: str
start_offset_in: float
class civilpy.structural.odot.guardrail.BridgeTerminalLayout(terminal: BridgeTerminalAssembly, post_stations_in: tuple[float, ...], posts: tuple[tuple[int, str, float, str], ...], length_in: float, notes: tuple[str, ...] = ())[source]

Bases: object

Post stations and members of one MGS bridge terminal assembly.

length_in: float
notes: tuple[str, ...] = ()
post_stations_in: tuple[float, ...]
posts: tuple[tuple[int, str, float, str], ...]
terminal: BridgeTerminalAssembly
civilpy.structural.odot.guardrail.MGS = MGSStandard(scd='MGS-2.1', scd_date='2026-01-16', rail_height=31.0, rail_height_tolerance_new=1.0, rail_height_tolerance_existing=3.0, rail='12 gauge W-beam (CMS 606.02)', rail_panel_lengths=(12.5, 25.0), standard_post_length=72.0, round_wood_post_length=68.0, long_post_length=97.0, embedment=40.0, round_wood_embedment=36.0, post_bolt_diameter=0.625, blockout_section='6 x 12', transition_rate_in_per_ft=0.08)

The standard Type MGS guardrail (MGS-2.1).

class civilpy.structural.odot.guardrail.MGSDrawing(scd: str, title: str, sheets: int, scd_date: str, category: str, connects_to: tuple[str, ...] = (), notes: str = '')[source]

Bases: object

One drawing in the Ohio DOT MGS roadway series.

category is one of standard, special, bridge_terminal, transition, anchor, terminal, layout, bridge. connects_to lists bridge-railing SCD numbers a terminal assembly ties into, where stated on the drawing.

category: str
connects_to: tuple[str, ...] = ()
notes: str = ''
scd: str
scd_date: str
sheets: int
title: str
class civilpy.structural.odot.guardrail.MGSRunLayout(length_ft: float, spacing: PostSpacing, post_stations_ft: tuple[float, ...], n_panels: int, panel_length_ft: float, rail_height_in: float = 31.0, notes: tuple[str, ...] = ())[source]

Bases: object

Posts and W-beam panels of one straight standard-MGS run.

length_ft: float
n_panels: int
notes: tuple[str, ...] = ()
panel_length_ft: float
post_stations_ft: tuple[float, ...]
rail_height_in: float = 31.0
spacing: PostSpacing
class civilpy.structural.odot.guardrail.MGSStandard(scd: str = 'MGS-2.1', scd_date: str = '2026-01-16', rail_height: float = 31.0, rail_height_tolerance_new: float = 1.0, rail_height_tolerance_existing: float = 3.0, rail: str = '12 gauge W-beam (CMS 606.02)', rail_panel_lengths: tuple[float, ...] = (12.5, 25.0), standard_post_length: float = 72.0, round_wood_post_length: float = 68.0, long_post_length: float = 97.0, embedment: float = 40.0, round_wood_embedment: float = 36.0, post_bolt_diameter: float = 0.625, blockout_section: str = '6 x 12', transition_rate_in_per_ft: float = 0.08)[source]

Bases: object

Standard Type MGS guardrail parameters (MGS-2.1).

Heights/lengths in inches; rail_panel_lengths (between splices) and transition rate are in feet.

blockout_section: str = '6 x 12'

Nominal blockout cross-section, inches.

embedment: float = 40.0

Standard embedment (steel / rectangular wood), inches.

long_post_length: float = 97.0

Long post length (steel / rectangular wood near slope break), inches.

post_bolt_diameter: float = 0.625

Post bolt diameter, inches.

post_spacing(name: str = 'standard') float[source]

On-center post spacing (inches) for "standard", "half", or "quarter" spacing.

rail: str = '12 gauge W-beam (CMS 606.02)'
rail_height: float = 31.0

Standard rail height to top of W-beam, inches.

rail_height_tolerance_existing: float = 3.0

Tolerance for existing guardrail after resurfacing, inches (+/-).

rail_height_tolerance_new: float = 1.0

Construction tolerance on initial install, inches (+/-).

rail_panel_lengths: tuple[float, ...] = (12.5, 25.0)

W-beam panel lengths between splices, feet.

round_wood_embedment: float = 36.0

Round wood post embedment, inches.

round_wood_post_length: float = 68.0

Round wood post length, inches.

scd: str = 'MGS-2.1'
scd_date: str = '2026-01-16'
standard_post_length: float = 72.0

Standard post length (steel / rectangular wood), inches.

transition_rate_in_per_ft: float = 0.08

Max rail-height transition rate (MGS-4.3), inches of height per foot.

civilpy.structural.odot.guardrail.MGS_DRAWINGS: dict[str, MGSDrawing] = {'MGS-2.1': MGSDrawing(scd='MGS-2.1', title='Midwest Guardrail System, Standard Type MGS', sheets=7, scd_date='2026-01-16', category='standard', connects_to=(), notes='31 in rail height; W-beam on W6x8.5/W6x9 steel, 6x8 rectangular wood, or 7.25 in round wood posts.'), 'MGS-2.2': MGSDrawing(scd='MGS-2.2', title='Barrier Design with Rub Rail', sheets=2, scd_date='2026-01-16', category='special', connects_to=(), notes='Standard MGS with a rub rail below the W-beam for curbed/vulnerable-user locations.'), 'MGS-2.3': MGSDrawing(scd='MGS-2.3', title='Long-Span Guardrail', sheets=1, scd_date='2025-07-18', category='special', connects_to=(), notes='Unposted MGS span over low-fill culverts (posts omitted across the structure); 31 in rail height kept. Paid per foot as Item 606 - Guardrail, Type MGS, Long-Span.'), 'MGS-2.4': MGSDrawing(scd='MGS-2.4', title='Socketed Weak Post Attached to Headwall', sheets=2, scd_date='2026-01-16', category='special', connects_to=(), notes='Weak posts grouted into sockets cast in an HW-series headwall where embedment is impossible. Paid per foot as Item 606 - Guardrail, Type MGS With Socketed Posts.'), 'MGS-3.1': MGSDrawing(scd='MGS-3.1', title='MGS Bridge Terminal Assembly, Type 1', sheets=2, scd_date='2026-01-16', category='bridge_terminal', connects_to=('BR-1-13', 'TST-1-99', 'RM-4.6'), notes='Connects guardrail to deflector-parapet bridge railings (BR-1-13, single-slope SBR), twin steel tube (TST-1-99), and concrete barrier end sections (RM-4.6). 12 ft-6 in nested thrie beam + 6 ft-3 in thrie + 6 ft-3 in asymmetrical transition; posts 1-6 at quarter spacing.'), 'MGS-3.2': MGSDrawing(scd='MGS-3.2', title='MGS Bridge Terminal Assembly, Type 2', sheets=1, scd_date='2025-07-18', category='bridge_terminal', connects_to=('RM-4.5', 'RM-4.6'), notes='Trailing-end connection (one-directional roadways only): W-beam terminal connector through-bolted to an 11x10x5/8 in bearing plate on the wall end.'), 'MGS-3.3': MGSDrawing(scd='MGS-3.3', title='MGS Bridge Terminal Assembly, Type TST-2', sheets=2, scd_date='2026-01-16', category='bridge_terminal', connects_to=('TST-2-21',), notes='Terminal assembly connecting MGS to the three steel tube bridge railing (TST-2-21).'), 'MGS-4.1': MGSDrawing(scd='MGS-4.1', title='MGS Type A Anchor Assembly', sheets=1, scd_date='2025-07-18', category='anchor', connects_to=(), notes='Buried anchor block terminating a run away from traffic: 18\'-9" rail into a reinforced concrete anchor. Paid Each as Item 606 - Anchor Assembly, Type A (or Barrier Design, Type A).'), 'MGS-4.2': MGSDrawing(scd='MGS-4.2', title='MGS Type T Anchor Assembly', sheets=7, scd_date='2025-07-18', category='anchor', connects_to=(), notes='Crashworthy tangent end terminal: 12\'-6" rounded-end 12-gauge W-beam on breakaway posts with a Type 2 BCT anchor cable and bearing plate. Paid Each as Item 606 - Anchor Assembly, MGS Type T.'), 'MGS-4.3': MGSDrawing(scd='MGS-4.3', title='Guardrail Transitions', sheets=1, scd_date='2025-07-18', category='transition', connects_to=(), notes='Type 5-to-MGS transition: ramp rail height 27 in to 31 in at max 2 in per 25 ft; half-spacing post between.'), 'MGS-4.5': MGSDrawing(scd='MGS-4.5', title='MGS Buried in Backslope End Terminal', sheets=2, scd_date='2025-07-18', category='terminal', connects_to=(), notes=''), 'MGS-5.2': MGSDrawing(scd='MGS-5.2', title='Introduction of Guardrail Runs (Foreslopes 6:1 or Flatter)', sheets=1, scd_date='2016-07-15', category='layout', connects_to=(), notes=''), 'MGS-5.3': MGSDrawing(scd='MGS-5.3', title='Introduction of Guardrail Runs (Foreslopes 6:1 or Steeper)', sheets=1, scd_date='2016-07-15', category='layout', connects_to=(), notes=''), 'MGS-6.1': MGSDrawing(scd='MGS-6.1', title='Guardrail at Bridges', sheets=2, scd_date='2018-01-19', category='bridge', connects_to=(), notes='Arrangement of runs at structures: 25 ft bridge terminal + 12\'-6" min MGS, 7:1 max taper / flare arcs, driveway and side-road opening treatments; anchor assemblies per L&D Vol. 1 603-3.'), 'MGS-6.2': MGSDrawing(scd='MGS-6.2', title='MGS Guardrail at Piers', sheets=1, scd_date='2025-07-18', category='bridge', connects_to=(), notes=''), 'MGS-6.3': MGSDrawing(scd='MGS-6.3', title='Thrie Beam Bullnose with Steel Breakaway Posts', sheets=8, scd_date='2025-07-18', category='terminal', connects_to=(), notes='')}

MGS drawing series keyed by SCD number.

civilpy.structural.odot.guardrail.MGS_POST_SPACINGS: dict[str, PostSpacing] = {'half': PostSpacing(name='half', spacing=37.5, blockout_height=10.0), 'quarter': PostSpacing(name='quarter', spacing=18.75, blockout_height=14.0), 'standard': PostSpacing(name='standard', spacing=75.0, blockout_height=12.0)}

MGS post-spacing options (on-center spacing and required blockout height).

civilpy.structural.odot.guardrail.MGS_STEEL_POSTS: dict[str, SteelPost] = {'6x8.5 welded': SteelPost(designation='6x8.5', fabrication='welded', depth=6.0, flange_width=3.94, flange_thickness=0.193, web_thickness=0.17), '6x9 welded': SteelPost(designation='6x9', fabrication='welded', depth=6.0, flange_width=3.94, flange_thickness=0.215, web_thickness=0.17), 'W6x8.5 rolled': SteelPost(designation='W6x8.5', fabrication='rolled', depth=5.8, flange_width=3.94, flange_thickness=0.193, web_thickness=0.17), 'W6x9 rolled': SteelPost(designation='W6x9', fabrication='rolled', depth=5.9, flange_width=3.94, flange_thickness=0.215, web_thickness=0.17)}

MGS steel beam post sections (MGS-2.1 sheet P.2).

class civilpy.structural.odot.guardrail.PostSpacing(name: str, spacing: float, blockout_height: float)[source]

Bases: object

One MGS post-spacing option and the blockout height it requires (MGS-2.1 sheets P.1-P.2). spacing and blockout_height in inches.

blockout_height: float
name: str
spacing: float
class civilpy.structural.odot.guardrail.SteelPost(designation: str, fabrication: str, depth: float, flange_width: float, flange_thickness: float, web_thickness: float)[source]

Bases: object

An MGS steel beam post section (MGS-2.1 sheet P.2 table). All dimensions in inches.

depth: float
designation: str
fabrication: str
flange_thickness: float
flange_width: float
web_thickness: float
class civilpy.structural.odot.guardrail.TerminalPostGroup(first: int, last: int, post: str, length_in: float, blockout: str)[source]

Bases: object

A run of identical posts within a bridge terminal assembly. first/last are 1-based post numbers; lengths in inches.

blockout: str
property count: int
first: int
last: int
length_in: float
post: str
civilpy.structural.odot.guardrail.bridge_terminal(designation: Literal['Type 1', 'Type 2', 'Type TST-2']) BridgeTerminalAssembly[source]

Look up a bridge terminal assembly ("Type 1", "Type 2", "Type TST-2").

civilpy.structural.odot.guardrail.bridge_terminal_assemblies() list[MGSDrawing][source]

The MGS bridge terminal assemblies (transitions to bridge railings).

civilpy.structural.odot.guardrail.layout_bridge_terminal(designation: Literal['Type 1', 'Type 2', 'Type TST-2']) BridgeTerminalLayout[source]

Expand a BRIDGE_TERMINALS entry into per-post members.

civilpy.structural.odot.guardrail.layout_mgs_run(length_ft: float, *, spacing: Literal['standard', 'half', 'quarter'] = 'standard', panel_length_ft: float = 25.0) MGSRunLayout[source]

Lay out a straight MGS-2.1 guardrail run: posts at the chosen spacing ("standard" / "half" / "quarter") and W-beam panels of panel_length_ft (12.5 or 25 ft between splices). Raises ValueError for a non-positive length, an unknown spacing, or a non-standard panel length.

civilpy.structural.odot.guardrail.mgs_drawing(scd: str) MGSDrawing[source]

Look up an MGS drawing by SCD number (e.g. "MGS-3.1").

civilpy.structural.odot.guardrail.terminals_for_railing(scd: str) list[MGSDrawing][source]

MGS terminal assemblies that connect to bridge railing scd (e.g. "TST-2-21").

civilpy.structural.odot.headwall module

Ohio DOT cast-in-place half-height headwalls (HW-2.1, HW-2.2).

Cast-in-place headwall dimension tables transcribed from two Ohio DOT Standard Bridge Drawings (Office of Structural Engineering):

HW-2.1  Half-Height Headwalls for Corrugated Metal Pipe and Plastic
        Pipe  (2018-07-20, rev. 2022-07-15)
HW-2.2  Half-Height Headwalls for Concrete Pipe  (rev. 2018-07-20)

For each pipe size the table gives headwall width W, height H, thickness T, and the cast-in-place concrete quantity. HW-2.1 is keyed by circular-pipe diameter D (the corrugated-metal/plastic primary table; its pipe-arch tables are not transcribed here). HW-2.2 carries both a circular table (by diameter) and an elliptical table (by rise and span).

The data lives in the res/hw_2_*.csv files and is loaded once at import. All dimensions are inches; concrete quantity is cubic yards. Spot-checked against the drawings in the test suite.

class civilpy.structural.odot.headwall.EllipticalHeadwall(rise: float, span: float, width: float, height: float, thickness: float, concrete_cy: float)[source]

Bases: object

One HW-2.2 elliptical-pipe headwall line.

rise and span are the pipe rise R and span; width (W), height (H) and thickness (T) are the headwall dimensions; concrete_cy is the cast-in-place concrete quantity. All inches.

concrete_cy: float
height: float
rise: float
span: float
thickness: float
width: float
civilpy.structural.odot.headwall.HEADWALLS_BY_DIAMETER: dict[float, Headwall] = {12.0: Headwall(diameter=12.0, width=24.0, height=36.0, thickness=12.0, concrete_cy=0.21, note=''), 15.0: Headwall(diameter=15.0, width=30.0, height=38.0, thickness=12.0, concrete_cy=0.27, note=''), 18.0: Headwall(diameter=18.0, width=36.0, height=39.0, thickness=12.0, concrete_cy=0.33, note=''), 21.0: Headwall(diameter=21.0, width=42.0, height=40.0, thickness=12.0, concrete_cy=0.39, note=''), 24.0: Headwall(diameter=24.0, width=48.0, height=42.0, thickness=12.0, concrete_cy=0.46, note=''), 27.0: Headwall(diameter=27.0, width=54.0, height=44.0, thickness=12.0, concrete_cy=0.53, note=''), 30.0: Headwall(diameter=30.0, width=60.0, height=45.0, thickness=12.0, concrete_cy=0.6, note=''), 33.0: Headwall(diameter=33.0, width=66.0, height=46.0, thickness=12.0, concrete_cy=0.68, note=''), 36.0: Headwall(diameter=36.0, width=72.0, height=48.0, thickness=12.0, concrete_cy=0.76, note=''), 39.0: Headwall(diameter=39.0, width=78.0, height=50.0, thickness=12.0, concrete_cy=0.84, note=''), 42.0: Headwall(diameter=42.0, width=84.0, height=51.0, thickness=12.0, concrete_cy=0.92, note=''), 48.0: Headwall(diameter=48.0, width=96.0, height=54.0, thickness=12.0, concrete_cy=1.1, note=''), 54.0: Headwall(diameter=54.0, width=111.0, height=57.0, thickness=12.0, concrete_cy=1.33, note=''), 60.0: Headwall(diameter=60.0, width=126.0, height=60.0, thickness=12.0, concrete_cy=1.78, note=''), 66.0: Headwall(diameter=66.0, width=141.0, height=63.0, thickness=12.0, concrete_cy=2.06, note=''), 72.0: Headwall(diameter=72.0, width=156.0, height=72.0, thickness=12.0, concrete_cy=2.37, note=''), 78.0: Headwall(diameter=78.0, width=171.0, height=75.0, thickness=14.0, concrete_cy=2.94, note=''), 84.0: Headwall(diameter=84.0, width=186.0, height=78.0, thickness=14.0, concrete_cy=3.3, note=''), 90.0: Headwall(diameter=90.0, width=201.0, height=81.0, thickness=16.0, concrete_cy=4.0, note=''), 96.0: Headwall(diameter=96.0, width=216.0, height=84.0, thickness=16.0, concrete_cy=4.4, note=''), 102.0: Headwall(diameter=102.0, width=231.0, height=87.0, thickness=18.0, concrete_cy=5.28, note=''), 108.0: Headwall(diameter=108.0, width=246.0, height=90.0, thickness=20.0, concrete_cy=6.21, note=''), 114.0: Headwall(diameter=114.0, width=261.0, height=93.0, thickness=22.0, concrete_cy=7.25, note=''), 120.0: Headwall(diameter=120.0, width=276.0, height=96.0, thickness=24.0, concrete_cy=8.38, note=''), 126.0: Headwall(diameter=126.0, width=276.0, height=99.0, thickness=26.0, concrete_cy=8.64, note='between end treatment A and B'), 132.0: Headwall(diameter=132.0, width=276.0, height=102.0, thickness=28.0, concrete_cy=9.23, note=''), 138.0: Headwall(diameter=138.0, width=289.0, height=105.0, thickness=30.0, concrete_cy=10.5, note=''), 144.0: Headwall(diameter=144.0, width=302.0, height=108.0, thickness=32.0, concrete_cy=11.89, note=''), 150.0: Headwall(diameter=150.0, width=316.0, height=111.0, thickness=34.0, concrete_cy=13.38, note=''), 156.0: Headwall(diameter=156.0, width=329.0, height=114.0, thickness=36.0, concrete_cy=15.01, note=''), 162.0: Headwall(diameter=162.0, width=343.0, height=117.0, thickness=38.0, concrete_cy=16.75, note=''), 168.0: Headwall(diameter=168.0, width=356.0, height=120.0, thickness=40.0, concrete_cy=18.61, note=''), 174.0: Headwall(diameter=174.0, width=369.0, height=123.0, thickness=42.0, concrete_cy=20.28, note=''), 180.0: Headwall(diameter=180.0, width=383.0, height=126.0, thickness=43.0, concrete_cy=21.87, note=''), 186.0: Headwall(diameter=186.0, width=396.0, height=129.0, thickness=44.0, concrete_cy=23.54, note=''), 192.0: Headwall(diameter=192.0, width=410.0, height=132.0, thickness=45.0, concrete_cy=25.3, note=''), 198.0: Headwall(diameter=198.0, width=423.0, height=135.0, thickness=46.0, concrete_cy=27.12, note=''), 204.0: Headwall(diameter=204.0, width=436.0, height=138.0, thickness=47.0, concrete_cy=29.15, note=''), 210.0: Headwall(diameter=210.0, width=450.0, height=141.0, thickness=48.0, concrete_cy=31.03, note=''), 216.0: Headwall(diameter=216.0, width=463.0, height=144.0, thickness=49.0, concrete_cy=33.43, note=''), 222.0: Headwall(diameter=222.0, width=477.0, height=147.0, thickness=50.0, concrete_cy=36.26, note=''), 228.0: Headwall(diameter=228.0, width=490.0, height=150.0, thickness=51.0, concrete_cy=37.52, note=''), 234.0: Headwall(diameter=234.0, width=504.0, height=153.0, thickness=52.0, concrete_cy=39.86, note=''), 240.0: Headwall(diameter=240.0, width=517.0, height=156.0, thickness=53.0, concrete_cy=42.28, note=''), 246.0: Headwall(diameter=246.0, width=530.0, height=159.0, thickness=54.0, concrete_cy=44.83, note=''), 252.0: Headwall(diameter=252.0, width=544.0, height=162.0, thickness=54.0, concrete_cy=47.44, note='')}

Circular headwalls keyed by pipe diameter (inches).

civilpy.structural.odot.headwall.HEADWALLS_CIRCULAR: list[Headwall] = [Headwall(diameter=12.0, width=24.0, height=36.0, thickness=12.0, concrete_cy=0.21, note=''), Headwall(diameter=15.0, width=30.0, height=38.0, thickness=12.0, concrete_cy=0.27, note=''), Headwall(diameter=18.0, width=36.0, height=39.0, thickness=12.0, concrete_cy=0.33, note=''), Headwall(diameter=21.0, width=42.0, height=40.0, thickness=12.0, concrete_cy=0.39, note=''), Headwall(diameter=24.0, width=48.0, height=42.0, thickness=12.0, concrete_cy=0.46, note=''), Headwall(diameter=27.0, width=54.0, height=44.0, thickness=12.0, concrete_cy=0.53, note=''), Headwall(diameter=30.0, width=60.0, height=45.0, thickness=12.0, concrete_cy=0.6, note=''), Headwall(diameter=33.0, width=66.0, height=46.0, thickness=12.0, concrete_cy=0.68, note=''), Headwall(diameter=36.0, width=72.0, height=48.0, thickness=12.0, concrete_cy=0.76, note=''), Headwall(diameter=39.0, width=78.0, height=50.0, thickness=12.0, concrete_cy=0.84, note=''), Headwall(diameter=42.0, width=84.0, height=51.0, thickness=12.0, concrete_cy=0.92, note=''), Headwall(diameter=48.0, width=96.0, height=54.0, thickness=12.0, concrete_cy=1.1, note=''), Headwall(diameter=54.0, width=111.0, height=57.0, thickness=12.0, concrete_cy=1.33, note=''), Headwall(diameter=60.0, width=126.0, height=60.0, thickness=12.0, concrete_cy=1.78, note=''), Headwall(diameter=66.0, width=141.0, height=63.0, thickness=12.0, concrete_cy=2.06, note=''), Headwall(diameter=72.0, width=156.0, height=72.0, thickness=12.0, concrete_cy=2.37, note=''), Headwall(diameter=78.0, width=171.0, height=75.0, thickness=14.0, concrete_cy=2.94, note=''), Headwall(diameter=84.0, width=186.0, height=78.0, thickness=14.0, concrete_cy=3.3, note=''), Headwall(diameter=90.0, width=201.0, height=81.0, thickness=16.0, concrete_cy=4.0, note=''), Headwall(diameter=96.0, width=216.0, height=84.0, thickness=16.0, concrete_cy=4.4, note=''), Headwall(diameter=102.0, width=231.0, height=87.0, thickness=18.0, concrete_cy=5.28, note=''), Headwall(diameter=108.0, width=246.0, height=90.0, thickness=20.0, concrete_cy=6.21, note=''), Headwall(diameter=114.0, width=261.0, height=93.0, thickness=22.0, concrete_cy=7.25, note=''), Headwall(diameter=120.0, width=276.0, height=96.0, thickness=24.0, concrete_cy=8.38, note=''), Headwall(diameter=126.0, width=276.0, height=99.0, thickness=26.0, concrete_cy=8.64, note='between end treatment A and B'), Headwall(diameter=132.0, width=276.0, height=102.0, thickness=28.0, concrete_cy=9.23, note=''), Headwall(diameter=138.0, width=289.0, height=105.0, thickness=30.0, concrete_cy=10.5, note=''), Headwall(diameter=144.0, width=302.0, height=108.0, thickness=32.0, concrete_cy=11.89, note=''), Headwall(diameter=150.0, width=316.0, height=111.0, thickness=34.0, concrete_cy=13.38, note=''), Headwall(diameter=156.0, width=329.0, height=114.0, thickness=36.0, concrete_cy=15.01, note=''), Headwall(diameter=162.0, width=343.0, height=117.0, thickness=38.0, concrete_cy=16.75, note=''), Headwall(diameter=168.0, width=356.0, height=120.0, thickness=40.0, concrete_cy=18.61, note=''), Headwall(diameter=174.0, width=369.0, height=123.0, thickness=42.0, concrete_cy=20.28, note=''), Headwall(diameter=180.0, width=383.0, height=126.0, thickness=43.0, concrete_cy=21.87, note=''), Headwall(diameter=186.0, width=396.0, height=129.0, thickness=44.0, concrete_cy=23.54, note=''), Headwall(diameter=192.0, width=410.0, height=132.0, thickness=45.0, concrete_cy=25.3, note=''), Headwall(diameter=198.0, width=423.0, height=135.0, thickness=46.0, concrete_cy=27.12, note=''), Headwall(diameter=204.0, width=436.0, height=138.0, thickness=47.0, concrete_cy=29.15, note=''), Headwall(diameter=210.0, width=450.0, height=141.0, thickness=48.0, concrete_cy=31.03, note=''), Headwall(diameter=216.0, width=463.0, height=144.0, thickness=49.0, concrete_cy=33.43, note=''), Headwall(diameter=222.0, width=477.0, height=147.0, thickness=50.0, concrete_cy=36.26, note=''), Headwall(diameter=228.0, width=490.0, height=150.0, thickness=51.0, concrete_cy=37.52, note=''), Headwall(diameter=234.0, width=504.0, height=153.0, thickness=52.0, concrete_cy=39.86, note=''), Headwall(diameter=240.0, width=517.0, height=156.0, thickness=53.0, concrete_cy=42.28, note=''), Headwall(diameter=246.0, width=530.0, height=159.0, thickness=54.0, concrete_cy=44.83, note=''), Headwall(diameter=252.0, width=544.0, height=162.0, thickness=54.0, concrete_cy=47.44, note='')]

HW-2.1 circular-pipe headwalls, ordered by pipe diameter.

civilpy.structural.odot.headwall.HEADWALLS_CONCRETE_BY_DIAMETER: dict[float, Headwall] = {12.0: Headwall(diameter=12.0, width=24.0, height=36.0, thickness=12.0, concrete_cy=0.2, note=''), 15.0: Headwall(diameter=15.0, width=30.0, height=38.0, thickness=12.0, concrete_cy=0.25, note=''), 18.0: Headwall(diameter=18.0, width=36.0, height=39.0, thickness=12.0, concrete_cy=0.31, note=''), 21.0: Headwall(diameter=21.0, width=42.0, height=40.0, thickness=12.0, concrete_cy=0.37, note=''), 24.0: Headwall(diameter=24.0, width=48.0, height=42.0, thickness=12.0, concrete_cy=0.43, note=''), 27.0: Headwall(diameter=27.0, width=54.0, height=44.0, thickness=12.0, concrete_cy=0.49, note=''), 30.0: Headwall(diameter=30.0, width=60.0, height=45.0, thickness=12.0, concrete_cy=0.56, note=''), 33.0: Headwall(diameter=33.0, width=66.0, height=46.0, thickness=12.0, concrete_cy=0.62, note=''), 36.0: Headwall(diameter=36.0, width=72.0, height=48.0, thickness=12.0, concrete_cy=0.69, note=''), 39.0: Headwall(diameter=39.0, width=78.0, height=50.0, thickness=12.0, concrete_cy=0.77, note=''), 42.0: Headwall(diameter=42.0, width=84.0, height=51.0, thickness=12.0, concrete_cy=0.84, note=''), 48.0: Headwall(diameter=48.0, width=96.0, height=54.0, thickness=14.0, concrete_cy=1.09, note=''), 54.0: Headwall(diameter=54.0, width=111.0, height=57.0, thickness=14.0, concrete_cy=1.32, note=''), 60.0: Headwall(diameter=60.0, width=126.0, height=66.0, thickness=16.0, concrete_cy=1.93, note=''), 66.0: Headwall(diameter=66.0, width=141.0, height=69.0, thickness=18.0, concrete_cy=2.42, note=''), 72.0: Headwall(diameter=72.0, width=156.0, height=72.0, thickness=18.0, concrete_cy=2.77, note=''), 78.0: Headwall(diameter=78.0, width=171.0, height=75.0, thickness=20.0, concrete_cy=3.37, note=''), 84.0: Headwall(diameter=84.0, width=186.0, height=78.0, thickness=22.0, concrete_cy=4.05, note=''), 90.0: Headwall(diameter=90.0, width=201.0, height=81.0, thickness=22.0, concrete_cy=4.51, note=''), 96.0: Headwall(diameter=96.0, width=216.0, height=84.0, thickness=24.0, concrete_cy=5.31, note=''), 102.0: Headwall(diameter=102.0, width=231.0, height=87.0, thickness=26.0, concrete_cy=6.2, note=''), 108.0: Headwall(diameter=108.0, width=246.0, height=90.0, thickness=26.0, concrete_cy=6.78, note=''), 114.0: Headwall(diameter=114.0, width=261.0, height=93.0, thickness=28.0, concrete_cy=7.81, note=''), 120.0: Headwall(diameter=120.0, width=276.0, height=96.0, thickness=30.0, concrete_cy=8.93, note=''), 126.0: Headwall(diameter=126.0, width=291.0, height=99.0, thickness=30.0, concrete_cy=9.57, note=''), 132.0: Headwall(diameter=132.0, width=306.0, height=102.0, thickness=32.0, concrete_cy=10.84, note=''), 144.0: Headwall(diameter=144.0, width=344.0, height=108.0, thickness=34.0, concrete_cy=13.0, note='')}

HW-2.2 concrete circular headwalls keyed by pipe diameter (inches).

civilpy.structural.odot.headwall.HEADWALLS_CONCRETE_CIRCULAR: list[Headwall] = [Headwall(diameter=12.0, width=24.0, height=36.0, thickness=12.0, concrete_cy=0.2, note=''), Headwall(diameter=15.0, width=30.0, height=38.0, thickness=12.0, concrete_cy=0.25, note=''), Headwall(diameter=18.0, width=36.0, height=39.0, thickness=12.0, concrete_cy=0.31, note=''), Headwall(diameter=21.0, width=42.0, height=40.0, thickness=12.0, concrete_cy=0.37, note=''), Headwall(diameter=24.0, width=48.0, height=42.0, thickness=12.0, concrete_cy=0.43, note=''), Headwall(diameter=27.0, width=54.0, height=44.0, thickness=12.0, concrete_cy=0.49, note=''), Headwall(diameter=30.0, width=60.0, height=45.0, thickness=12.0, concrete_cy=0.56, note=''), Headwall(diameter=33.0, width=66.0, height=46.0, thickness=12.0, concrete_cy=0.62, note=''), Headwall(diameter=36.0, width=72.0, height=48.0, thickness=12.0, concrete_cy=0.69, note=''), Headwall(diameter=39.0, width=78.0, height=50.0, thickness=12.0, concrete_cy=0.77, note=''), Headwall(diameter=42.0, width=84.0, height=51.0, thickness=12.0, concrete_cy=0.84, note=''), Headwall(diameter=48.0, width=96.0, height=54.0, thickness=14.0, concrete_cy=1.09, note=''), Headwall(diameter=54.0, width=111.0, height=57.0, thickness=14.0, concrete_cy=1.32, note=''), Headwall(diameter=60.0, width=126.0, height=66.0, thickness=16.0, concrete_cy=1.93, note=''), Headwall(diameter=66.0, width=141.0, height=69.0, thickness=18.0, concrete_cy=2.42, note=''), Headwall(diameter=72.0, width=156.0, height=72.0, thickness=18.0, concrete_cy=2.77, note=''), Headwall(diameter=78.0, width=171.0, height=75.0, thickness=20.0, concrete_cy=3.37, note=''), Headwall(diameter=84.0, width=186.0, height=78.0, thickness=22.0, concrete_cy=4.05, note=''), Headwall(diameter=90.0, width=201.0, height=81.0, thickness=22.0, concrete_cy=4.51, note=''), Headwall(diameter=96.0, width=216.0, height=84.0, thickness=24.0, concrete_cy=5.31, note=''), Headwall(diameter=102.0, width=231.0, height=87.0, thickness=26.0, concrete_cy=6.2, note=''), Headwall(diameter=108.0, width=246.0, height=90.0, thickness=26.0, concrete_cy=6.78, note=''), Headwall(diameter=114.0, width=261.0, height=93.0, thickness=28.0, concrete_cy=7.81, note=''), Headwall(diameter=120.0, width=276.0, height=96.0, thickness=30.0, concrete_cy=8.93, note=''), Headwall(diameter=126.0, width=291.0, height=99.0, thickness=30.0, concrete_cy=9.57, note=''), Headwall(diameter=132.0, width=306.0, height=102.0, thickness=32.0, concrete_cy=10.84, note=''), Headwall(diameter=144.0, width=344.0, height=108.0, thickness=34.0, concrete_cy=13.0, note='')]

HW-2.2 concrete-pipe circular headwalls, ordered by diameter.

civilpy.structural.odot.headwall.HEADWALLS_CONCRETE_ELLIPTICAL: list[EllipticalHeadwall] = [EllipticalHeadwall(rise=14.0, span=23.0, width=36.0, height=38.0, thickness=12.0, concrete_cy=0.29), EllipticalHeadwall(rise=19.0, span=30.0, width=43.0, height=40.0, thickness=12.0, concrete_cy=0.35), EllipticalHeadwall(rise=22.0, span=34.0, width=47.0, height=41.0, thickness=12.0, concrete_cy=0.38), EllipticalHeadwall(rise=24.0, span=38.0, width=54.0, height=42.0, thickness=12.0, concrete_cy=0.44), EllipticalHeadwall(rise=29.0, span=45.0, width=62.0, height=44.0, thickness=12.0, concrete_cy=0.49), EllipticalHeadwall(rise=34.0, span=53.0, width=71.0, height=48.0, thickness=14.0, concrete_cy=0.66), EllipticalHeadwall(rise=38.0, span=60.0, width=82.0, height=50.0, thickness=14.0, concrete_cy=0.82), EllipticalHeadwall(rise=43.0, span=68.0, width=96.0, height=52.0, thickness=16.0, concrete_cy=1.01), EllipticalHeadwall(rise=48.0, span=76.0, width=110.0, height=60.0, thickness=16.0, concrete_cy=1.34), EllipticalHeadwall(rise=53.0, span=83.0, width=124.0, height=62.0, thickness=18.0, concrete_cy=1.65), EllipticalHeadwall(rise=58.0, span=91.0, width=138.0, height=65.0, thickness=18.0, concrete_cy=1.97), EllipticalHeadwall(rise=63.0, span=98.0, width=151.0, height=67.0, thickness=20.0, concrete_cy=2.38), EllipticalHeadwall(rise=68.0, span=106.0, width=165.0, height=70.0, thickness=20.0, concrete_cy=2.69), EllipticalHeadwall(rise=72.0, span=113.0, width=177.0, height=72.0, thickness=22.0, concrete_cy=3.14), EllipticalHeadwall(rise=77.0, span=121.0, width=191.0, height=75.0, thickness=22.0, concrete_cy=3.49), EllipticalHeadwall(rise=82.0, span=128.0, width=204.0, height=77.0, thickness=24.0, concrete_cy=4.04), EllipticalHeadwall(rise=87.0, span=136.0, width=218.0, height=80.0, thickness=24.0, concrete_cy=4.84), EllipticalHeadwall(rise=92.0, span=143.0, width=232.0, height=82.0, thickness=26.0, concrete_cy=5.12), EllipticalHeadwall(rise=97.0, span=151.0, width=246.0, height=85.0, thickness=26.0, concrete_cy=5.42), EllipticalHeadwall(rise=106.0, span=166.0, width=271.0, height=89.0, thickness=28.0, concrete_cy=6.6), EllipticalHeadwall(rise=116.0, span=180.0, width=298.0, height=94.0, thickness=30.0, concrete_cy=7.99)]

HW-2.2 concrete-pipe elliptical headwalls, ordered by rise.

class civilpy.structural.odot.headwall.Headwall(diameter: float, width: float, height: float, thickness: float, concrete_cy: float, note: str = '')[source]

Bases: object

One HW-2.1 circular-pipe headwall line.

diameter is the pipe inside diameter D; width (W), height (H) and thickness (T) are the headwall dimensions; concrete_cy is the cast-in-place concrete quantity. note flags special rows (e.g. pipe sizes between end treatments A and B).

concrete_cy: float
diameter: float
height: float
note: str = ''
thickness: float
width: float
class civilpy.structural.odot.headwall.HeadwallInput(diameter_in: float, concrete: bool = False)[source]

Bases: object

Inputs for a circular-pipe headwall solid.

diameter_in is a tabulated pipe inside diameter D; concrete selects the HW-2.2 concrete-pipe table instead of the HW-2.1 corrugated-metal/plastic table.

concrete: bool = False
diameter_in: float
class civilpy.structural.odot.headwall.HeadwallLayout(inputs: ~civilpy.structural.odot.headwall.HeadwallInput, table: ~civilpy.structural.odot.headwall.Headwall, front_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], side_profile: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], pipe_center: tuple[float, float, float], pipe_diameter_ft: float, width_ft: float, height_ft: float, base_thickness_ft: float, top_thickness_ft: float, cover_in: float, concrete_cy: float, notes: tuple[str, ...] = <factory>)[source]

Bases: object

The generated headwall. front_outline is the vertical front face (counterclockwise in the X-Z plane at y = 0); side_profile is the battered wall cross-section in the Y-Z plane at x = -W/2 (front vertical, back battered 12 in -> T); the solid is side_profile swept the full width W in +X with the circular pipe opening (centre pipe_center, diameter pipe_diameter_ft) cut through it along Y. Origin: x = 0 on the wall centreline, y = 0 at the front face (wall behind, -y), z = 0 at the flow line / wall base.

base_thickness_ft: float
concrete_cy: float
cover_in: float
front_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
height_ft: float
inputs: HeadwallInput
notes: tuple[str, ...]
pipe_center: tuple[float, float, float]
pipe_diameter_ft: float
side_profile: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
table: Headwall
top_thickness_ft: float
width_ft: float
civilpy.structural.odot.headwall.elliptical_headwall_for_rise(rise: float) EllipticalHeadwall[source]

Look up the HW-2.2 concrete elliptical headwall by pipe rise (inches).

civilpy.structural.odot.headwall.headwall_for_diameter(diameter: float, concrete: bool = False) Headwall[source]

Look up the circular headwall for a pipe diameter (inches).

concrete=False uses the HW-2.1 corrugated-metal/plastic table; concrete=True uses the HW-2.2 concrete-pipe table. Raises KeyError if the diameter is not a tabulated size.

civilpy.structural.odot.headwall.layout_headwall(inp: HeadwallInput) HeadwallLayout[source]

Generate the rectangular circular-pipe headwall solid (end treatment “A”).

Raises KeyError for a pipe diameter that is not a tabulated size and ValueError for a size whose cover over the pipe crown drops below the 6 in minimum (end treatment “B”, not modeled here).

civilpy.structural.odot.portable_barrier module

ODOT PCB-91 Standard Portable Concrete Barrier Details.

Transcribed from Ohio DOT Standard Construction Drawing PCB-91 (revised 07-17-2020, 1 sheet). The drawing remains the controlling document. Crash-test levels, materials, and the catalog listing live in civilpy.structural.odot.bridge_railing (designations "PCB (portable, unanchored)" — NCHRP 350 TL-3 — and "PCB (portable, anchored)" — TL-4 fully anchored on the traffic side); this module adds the drawable geometry: the New Jersey shape section, segment/joint layout, anchor-hole stations, and the drainage/lifting slot.

Segments are 10’-0” or 12’-0” long, connected by 3/4 in dia. galvanized hinge-bar loops pinned with a vertical 1-1/4 in dia. H.S. bolt (plate washers + hex nut): barriers are set closer together so the bolt drops through the loops, and joints must be fully open (1-3/4 in max gap) before the nut is tightened. Anchors are 1 in dia. H.S. bolts through 1-1/4 in dia. holes — thru bolts or partial-depth bolts embedded a minimum of 6-1/2 in and grouted (705.20). Concrete f’c >= 4,000 psi; all hardware per 711.09 (ASTM A325), galvanized per 711.02; reinforcing (including hinge bars) per 509.02. Segments are marked PCB-BXX-350 (XX = year cast) in 2 in impressed lettering.

Units: section dimensions in inches, run stations in feet.

class civilpy.structural.odot.portable_barrier.BarrierSegment(index: int, start_ft: float, end_ft: float)[source]

Bases: object

One placed segment: stations (ft) along the run.

end_ft: float
index: int
property length_ft: float
start_ft: float
civilpy.structural.odot.portable_barrier.anchor_hole_stations_ft(segment_length_ft: float) tuple[float, ...][source]

Anchor-hole stations along one segment (ft from its start): 1’-0” from each end, equally spaced at 2’-0” c/c (5 holes per row on a 10 ft segment, 6 on a 12 ft).

civilpy.structural.odot.portable_barrier.barrier_run(n_segments: int, segment_length_ft: float = 10.0, joint_gap_in: float = 0.25) tuple[BarrierSegment, ...][source]

Lay out n_segments along a straight run with the given joint gap (closed 1/4 in up to the fully-open 1-3/4 in max).

civilpy.structural.odot.portable_barrier.profile_points_in(chamfered: bool = True) tuple[tuple[float, float], ...][source]

The closed New Jersey shape section, counterclockwise from the bottom-left corner, as (x, y) inches with x transverse from the barrier centerline and y up from the deck surface.

chamfered includes the 3/4 in top chamfers (the sheet allows a 1 in radius instead).

civilpy.structural.odot.portable_barrier.run_length_ft(segments: tuple[BarrierSegment, ...]) float[source]

Overall length of a laid-out run (ft), including joint gaps.

civilpy.structural.odot.ps_i_beam module

Ohio DOT prestressed concrete I-beam bridge details (PSID-1-13).

Transcribed from Ohio DOT Standard Bridge Drawing PSID-1-13, “Prestressed Concrete I-Beam Bridge Details” (rev. 07-18-2025, 10 sheets). The drawing remains the controlling document.

Thirteen standard sections:

  • AASHTO Type 2/3/4 and three deepened “Modified AASHTO Type 4” webs (60/66/72 in overall depth) – sheet 1’s SECTION PROPERTIES table. The Modified Type 4s keep Type 4’s 26 in bottom flange but carry a wide, thin top flange (36 in for the 60/66, 48 in for the 72 – verified against sheet 1’s own dimension strings and the shipping-strand offsets), not Type 4’s 20 in flange.

  • WF36-49 .. WF72-49 wide-flange sections (sheets 2-3, sheet 3’s SECTION PROPERTIES table): 49 in top flange, 40 in bottom flange, 8 in web, 62 permissible bottom-flange strand locations each.

Beyond the section tables this module also catalogs, per section, the sheet’s permissible strand grid (the + marks: 2 in lattice both ways, exact per-row offsets extracted from the drawing’s vector marks – row totals reconcile with the sheet’s stated 26/40/52/62 permissible location counts), the WF web locations that must be draped if utilized (sheet 2 note), the Modified-AASHTO/WF shipping strand locations, and the sheet 10 design constants (0.6 in Grade 270 low-relaxation strand at 0.217 in^2, designer-selected f'c / f'ci ranges, HL-93 + 60 psf FWS, spacing < 14 ft, skew < 45 deg).

No PSIDD companion design-data sheet exists (unlike PSBD/PSBDD for box beams), so there are no tabulated standard strand patterns; civilpy.structural.ps_i_beam_pipeline designs a pattern on this grid instead.

Lengths in inches, area in in^2, weight in lb/ft, moment of inertia in in^4, section moduli in in^3, unless noted. Spot-checked against the drawing in the test suite.

civilpy.structural.odot.ps_i_beam.DIAPHRAGM_FC_KSI = 4.5

Diaphragm concrete (Item 511), ksi.

civilpy.structural.odot.ps_i_beam.FCI_RANGE_KSI = (4.0, 5.0)

Designer-selected release strength range, ksi (sheet 10).

civilpy.structural.odot.ps_i_beam.FC_RANGE_KSI = (5.5, 7.0)

Designer-selected 28-day strength range, ksi (sheet 10).

civilpy.structural.odot.ps_i_beam.FWS_PSF = 60.0

Future wearing surface dead load, lb/ft^2 (sheet 10 design loading).

civilpy.structural.odot.ps_i_beam.MAX_BEAM_SPACING_FT = 14.0

The standard applies to beam spacings under 14 ft and skews under 45 degrees (sheet 10 general notes).

class civilpy.structural.odot.ps_i_beam.PSIBeamLayout(section: ~civilpy.structural.odot.ps_i_beam.PSIBeamSection, profile: tuple[tuple[float, float], ...], length_ft: float, notes: tuple[str, ...] = <factory>)[source]

Bases: object

A simplified I-shaped cross-section profile (top flange, web, bottom flange) – straight-line approximation, no fillet/bulb radii – extruded length_ft. Profile points (y, z) inches, y transverse, z up from the bottom; the beam centerline is y = 0.

length_ft: float
notes: tuple[str, ...]
profile: tuple[tuple[float, float], ...]
section: PSIBeamSection
class civilpy.structural.odot.ps_i_beam.PSIBeamSection(name: str, depth_in: float, area_in2: float, weight_plf: float, yb_in: float, yt_in: float, i_in4: float, sb_in3: float, st_in3: float, vol_surf_ratio: float, top_flange_width_in: float, bottom_flange_width_in: float, max_bottom_flange_strands: int, web_in: float = 8.0, strand_rows: tuple = (), draped_required: tuple = (), shipping_strand_locations: tuple = ())[source]

Bases: object

One PSID-1-13 standard section (sheet 1 / sheet 3 SECTION PROPERTIES tables).

strand_rows is the sheet’s permissible strand grid: a tuple of (z, (y, ...)) rows – z inches above the beam bottom, y transverse offsets from the beam centerline (2 in lattice). The row totals equal max_bottom_flange_strands. draped_required lists the grid locations the sheet marks “if utilized, these strand locations must be draped” (WF sections’ upper web column). shipping_strand_locations are the optional debonded shipping strands the fabricator may add in the top flange (Modified AASHTO / WF sheets; the sheet ties them to general-note bonding rules – see SHIPPING_STRAND_BOND_FT).

area_in2: float
bottom_flange_width_in: float
depth_in: float
draped_required: tuple = ()
i_in4: float
max_bottom_flange_strands: int
name: str
sb_in3: float
shipping_strand_locations: tuple = ()
st_in3: float
strand_rows: tuple = ()
top_flange_width_in: float
vol_surf_ratio: float
web_in: float = 8.0
weight_plf: float
yb_in: float
yt_in: float
civilpy.structural.odot.ps_i_beam.PS_I_BEAM_SECTIONS: dict[str, PSIBeamSection] = {'AASHTO Type 2': PSIBeamSection(name='AASHTO Type 2', depth_in=36.0, area_in2=369.0, weight_plf=384.0, yb_in=15.83, yt_in=20.17, i_in4=50979, sb_in3=3221, st_in3=2527, vol_surf_ratio=3.371, top_flange_width_in=12.0, bottom_flange_width_in=18.0, max_bottom_flange_strands=26, web_in=6.0, strand_rows=((2.0, (-6.0, -4.0, 0.0, 4.0, 6.0)), (4.0, (-6.0, -4.0, -2.0, 0.0, 2.0, 4.0, 6.0)), (6.0, (-6.0, -4.0, 0.0, 4.0, 6.0)), (8.0, (-4.0, -2.0, 0.0, 2.0, 4.0)), (10.0, (-2.0, 0.0, 2.0)), (12.0, (0.0,))), draped_required=(), shipping_strand_locations=()), 'AASHTO Type 3': PSIBeamSection(name='AASHTO Type 3', depth_in=45.0, area_in2=560.0, weight_plf=583.0, yb_in=20.27, yt_in=24.73, i_in4=125390, sb_in3=6185, st_in3=5071, vol_surf_ratio=4.056, top_flange_width_in=16.0, bottom_flange_width_in=22.0, max_bottom_flange_strands=40, web_in=7.0, strand_rows=((2.0, (-7.0, -5.0, 5.0, 7.0)), (4.0, (-9.0, -7.0, -5.0, -3.0, -1.0, 1.0, 3.0, 5.0, 7.0, 9.0)), (6.0, (-9.0, -7.0, -5.0, 5.0, 7.0, 9.0)), (8.0, (-7.0, -5.0, -3.0, -1.0, 1.0, 3.0, 5.0, 7.0)), (10.0, (-5.0, -3.0, -1.0, 1.0, 3.0, 5.0)), (12.0, (-3.0, -1.0, 1.0, 3.0)), (14.0, (-1.0, 1.0))), draped_required=(), shipping_strand_locations=()), 'AASHTO Type 4': PSIBeamSection(name='AASHTO Type 4', depth_in=54.0, area_in2=789.0, weight_plf=822.0, yb_in=24.73, yt_in=29.27, i_in4=260741, sb_in3=10542, st_in3=8909, vol_surf_ratio=4.741, top_flange_width_in=20.0, bottom_flange_width_in=26.0, max_bottom_flange_strands=52, web_in=8.0, strand_rows=((2.0, (-10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0)), (4.0, (-10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0)), (6.0, (-10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0)), (8.0, (-10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0)), (10.0, (-8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0)), (12.0, (-6.0, -4.0, 0.0, 4.0, 6.0)), (14.0, (-4.0, 0.0, 4.0)), (16.0, (0.0,))), draped_required=(), shipping_strand_locations=()), 'Modified AASHTO Type 4 (60in)': PSIBeamSection(name='Modified AASHTO Type 4 (60in)', depth_in=60.0, area_in2=860.0, weight_plf=896.0, yb_in=28.74, yt_in=31.26, i_in4=384705, sb_in3=13385, st_in3=12307, vol_surf_ratio=4.089, top_flange_width_in=36.0, bottom_flange_width_in=26.0, max_bottom_flange_strands=52, web_in=8.0, strand_rows=((2.0, (-10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0)), (4.0, (-10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0)), (6.0, (-10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0)), (8.0, (-10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0)), (10.0, (-8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0)), (12.0, (-6.0, -4.0, 0.0, 4.0, 6.0)), (14.0, (-4.0, 0.0, 4.0)), (16.0, (0.0,))), draped_required=(), shipping_strand_locations=((-10.0, 57.25), (-8.0, 57.25), (-6.0, 57.25), (6.0, 57.25), (8.0, 57.25), (10.0, 57.25))), 'Modified AASHTO Type 4 (66in)': PSIBeamSection(name='Modified AASHTO Type 4 (66in)', depth_in=66.0, area_in2=908.0, weight_plf=946.0, yb_in=31.58, yt_in=34.42, i_in4=492212, sb_in3=15588, st_in3=14299, vol_surf_ratio=4.085, top_flange_width_in=36.0, bottom_flange_width_in=26.0, max_bottom_flange_strands=52, web_in=8.0, strand_rows=((2.0, (-10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0)), (4.0, (-10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0)), (6.0, (-10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0)), (8.0, (-10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0)), (10.0, (-8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0)), (12.0, (-6.0, -4.0, 0.0, 4.0, 6.0)), (14.0, (-4.0, 0.0, 4.0)), (16.0, (0.0,))), draped_required=(), shipping_strand_locations=((-10.0, 63.25), (-8.0, 63.25), (-6.0, 63.25), (6.0, 63.25), (8.0, 63.25), (10.0, 63.25))), 'Modified AASHTO Type 4 (72in)': PSIBeamSection(name='Modified AASHTO Type 4 (72in)', depth_in=72.0, area_in2=1015.0, weight_plf=1058.0, yb_in=36.52, yt_in=35.48, i_in4=684726, sb_in3=18749, st_in3=19299, vol_surf_ratio=3.947, top_flange_width_in=48.0, bottom_flange_width_in=26.0, max_bottom_flange_strands=52, web_in=8.0, strand_rows=((2.0, (-10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0)), (4.0, (-10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0)), (6.0, (-10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0)), (8.0, (-10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0)), (10.0, (-8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0)), (12.0, (-6.0, -4.0, 0.0, 4.0, 6.0)), (14.0, (-4.0, 0.0, 4.0)), (16.0, (0.0,))), draped_required=(), shipping_strand_locations=((-10.0, 69.25), (-8.0, 69.25), (-6.0, 69.25), (6.0, 69.25), (8.0, 69.25), (10.0, 69.25))), 'WF36-49': PSIBeamSection(name='WF36-49', depth_in=36.0, area_in2=878.3, weight_plf=915.0, yb_in=18.2, yt_in=17.8, i_in4=145592, sb_in3=8000, st_in3=8179, vol_surf_ratio=4.16, top_flange_width_in=49.0, bottom_flange_width_in=40.0, max_bottom_flange_strands=62, web_in=8.0, strand_rows=((2.0, (-16.0, -14.0, -12.0, -10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0)), (4.0, (-18.0, -16.0, -14.0, -12.0, -10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 18.0)), (6.0, (-14.0, -12.0, -10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0)), (8.0, (-10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0)), (10.0, (-6.0, -4.0, 0.0, 4.0, 6.0)), (12.0, (0.0,)), (14.0, (0.0,)), (16.0, (0.0,))), draped_required=((0.0, 14.0), (0.0, 16.0)), shipping_strand_locations=((-10.0, 33.25), (-8.0, 33.25), (-6.0, 33.25), (6.0, 33.25), (8.0, 33.25), (10.0, 33.25))), 'WF42-49': PSIBeamSection(name='WF42-49', depth_in=42.0, area_in2=926.3, weight_plf=965.0, yb_in=21.1, yt_in=20.9, i_in4=217461, sb_in3=10306, st_in3=10405, vol_surf_ratio=4.152, top_flange_width_in=49.0, bottom_flange_width_in=40.0, max_bottom_flange_strands=62, web_in=8.0, strand_rows=((2.0, (-16.0, -14.0, -12.0, -10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0)), (4.0, (-18.0, -16.0, -14.0, -12.0, -10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 18.0)), (6.0, (-14.0, -12.0, -10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0)), (8.0, (-10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0)), (10.0, (-6.0, -4.0, 0.0, 4.0, 6.0)), (12.0, (0.0,)), (14.0, (0.0,)), (16.0, (0.0,))), draped_required=((0.0, 14.0), (0.0, 16.0)), shipping_strand_locations=((-10.0, 39.25), (-8.0, 39.25), (-6.0, 39.25), (6.0, 39.25), (8.0, 39.25), (10.0, 39.25))), 'WF48-49': PSIBeamSection(name='WF48-49', depth_in=48.0, area_in2=974.3, weight_plf=1015.0, yb_in=24.0, yt_in=24.0, i_in4=305994, sb_in3=12750, st_in3=12750, vol_surf_ratio=4.144, top_flange_width_in=49.0, bottom_flange_width_in=40.0, max_bottom_flange_strands=62, web_in=8.0, strand_rows=((2.0, (-16.0, -14.0, -12.0, -10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0)), (4.0, (-18.0, -16.0, -14.0, -12.0, -10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 18.0)), (6.0, (-14.0, -12.0, -10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0)), (8.0, (-10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0)), (10.0, (-6.0, -4.0, 0.0, 4.0, 6.0)), (12.0, (0.0,)), (14.0, (0.0,)), (16.0, (0.0,))), draped_required=((0.0, 14.0), (0.0, 16.0)), shipping_strand_locations=((-10.0, 45.25), (-8.0, 45.25), (-6.0, 45.25), (6.0, 45.25), (8.0, 45.25), (10.0, 45.25))), 'WF54-49': PSIBeamSection(name='WF54-49', depth_in=54.0, area_in2=1022.3, weight_plf=1065.0, yb_in=27.0, yt_in=27.0, i_in4=412056, sb_in3=15261, st_in3=15261, vol_surf_ratio=4.137, top_flange_width_in=49.0, bottom_flange_width_in=40.0, max_bottom_flange_strands=62, web_in=8.0, strand_rows=((2.0, (-16.0, -14.0, -12.0, -10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0)), (4.0, (-18.0, -16.0, -14.0, -12.0, -10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 18.0)), (6.0, (-14.0, -12.0, -10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0)), (8.0, (-10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0)), (10.0, (-6.0, -4.0, 0.0, 4.0, 6.0)), (12.0, (0.0,)), (14.0, (0.0,)), (16.0, (0.0,))), draped_required=((0.0, 14.0), (0.0, 16.0)), shipping_strand_locations=((-10.0, 51.25), (-8.0, 51.25), (-6.0, 51.25), (6.0, 51.25), (8.0, 51.25), (10.0, 51.25))), 'WF60-49': PSIBeamSection(name='WF60-49', depth_in=60.0, area_in2=1070.3, weight_plf=1115.0, yb_in=29.9, yt_in=30.1, i_in4=536513, sb_in3=17944, st_in3=17824, vol_surf_ratio=4.131, top_flange_width_in=49.0, bottom_flange_width_in=40.0, max_bottom_flange_strands=62, web_in=8.0, strand_rows=((2.0, (-16.0, -14.0, -12.0, -10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0)), (4.0, (-18.0, -16.0, -14.0, -12.0, -10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 18.0)), (6.0, (-14.0, -12.0, -10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0)), (8.0, (-10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0)), (10.0, (-6.0, -4.0, 0.0, 4.0, 6.0)), (12.0, (0.0,)), (14.0, (0.0,)), (16.0, (0.0,))), draped_required=((0.0, 14.0), (0.0, 16.0)), shipping_strand_locations=((-10.0, 57.25), (-8.0, 57.25), (-6.0, 57.25), (6.0, 57.25), (8.0, 57.25), (10.0, 57.25))), 'WF66-49': PSIBeamSection(name='WF66-49', depth_in=66.0, area_in2=1118.3, weight_plf=1165.0, yb_in=32.9, yt_in=33.1, i_in4=680229, sb_in3=20676, st_in3=20551, vol_surf_ratio=4.125, top_flange_width_in=49.0, bottom_flange_width_in=40.0, max_bottom_flange_strands=62, web_in=8.0, strand_rows=((2.0, (-16.0, -14.0, -12.0, -10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0)), (4.0, (-18.0, -16.0, -14.0, -12.0, -10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 18.0)), (6.0, (-14.0, -12.0, -10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0)), (8.0, (-10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0)), (10.0, (-6.0, -4.0, 0.0, 4.0, 6.0)), (12.0, (0.0,)), (14.0, (0.0,)), (16.0, (0.0,))), draped_required=((0.0, 14.0), (0.0, 16.0)), shipping_strand_locations=((-10.0, 63.25), (-8.0, 63.25), (-6.0, 63.25), (6.0, 63.25), (8.0, 63.25), (10.0, 63.25))), 'WF72-49': PSIBeamSection(name='WF72-49', depth_in=72.0, area_in2=1166.3, weight_plf=1215.0, yb_in=35.8, yt_in=36.2, i_in4=844069, sb_in3=23577, st_in3=23317, vol_surf_ratio=4.12, top_flange_width_in=49.0, bottom_flange_width_in=40.0, max_bottom_flange_strands=62, web_in=8.0, strand_rows=((2.0, (-16.0, -14.0, -12.0, -10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0)), (4.0, (-18.0, -16.0, -14.0, -12.0, -10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 18.0)), (6.0, (-14.0, -12.0, -10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0)), (8.0, (-10.0, -8.0, -6.0, -4.0, 0.0, 4.0, 6.0, 8.0, 10.0)), (10.0, (-6.0, -4.0, 0.0, 4.0, 6.0)), (12.0, (0.0,)), (14.0, (0.0,)), (16.0, (0.0,))), draped_required=((0.0, 14.0), (0.0, 16.0)), shipping_strand_locations=((-10.0, 69.25), (-8.0, 69.25), (-6.0, 69.25), (6.0, 69.25), (8.0, 69.25), (10.0, 69.25)))}

PSID-1-13 standard I-beam sections, keyed by name.

civilpy.structural.odot.ps_i_beam.SHIPPING_STRAND_BOND_FT = 10.0

Shipping strands are debonded except the last 10 ft each end (sheet 10).

civilpy.structural.odot.ps_i_beam.STRAND_AREA_IN2 = 0.217

Nominal strand area (in^2) – 0.6 in seven-wire strand (sheet 10).

civilpy.structural.odot.ps_i_beam.STRAND_DIAMETER_IN = 0.6

Strand diameter, inches.

civilpy.structural.odot.ps_i_beam.STRAND_FPU_KSI = 270.0

Strand ultimate strength, ksi (711.27 / ASTM A416 Grade 270, low-lax).

civilpy.structural.odot.ps_i_beam.i_beam_diaphragm_stations_ft(span_ft: float) list[float][source]

Intermediate-diaphragm centerline stations (ft from the span start) per sheet 5: one at midspan for spans up to 80 ft, at the quarter points beyond that. (Cast-in-place required under 60 in deep beams; 60/66/72 in beams may use the sheet 9 galvanized-steel diaphragms instead – sheet 10 general notes.)

civilpy.structural.odot.ps_i_beam.layout_ps_i_beam(name: str, length_ft: float, web_thickness_in: float = 8.0, flange_thickness_in: float = 8.0) PSIBeamLayout[source]

Generate a simplified I-beam cross-section profile for name (ps_i_beam_section()), extruded length_ft.

Raises ValueError for a non-positive length or an unknown section name.

civilpy.structural.odot.ps_i_beam.ps_i_beam_profile(name: str) tuple[tuple[float, float], ...][source]

The true tapered cross-section outline of a PSID-1-13 section as closed-polygon vertices (y, z) in inches, y transverse from the beam centerline, z up from the bottom – counter-clockwise, starting at the bottom-left corner. Straight-line approximation: fillet and 3/4 in chamfer radii are not modeled (unlike layout_ps_i_beam(), the flange tapers are).

civilpy.structural.odot.ps_i_beam.ps_i_beam_section(name: str) PSIBeamSection[source]

Look up a PSID-1-13 standard section by name.

Raises ValueError naming the valid sections otherwise.

civilpy.structural.odot.ps_i_beam.strand_centroid_in(pattern: list[tuple[float, float]]) float[source]

Height of a strand pattern’s centroid above the beam bottom (in).

civilpy.structural.odot.ps_i_beam.strand_grid(name: str) list[tuple[float, float]][source]

Every permissible bottom-flange/web strand location of a section as (y, z) inches, in the standard fill order: row by row from the bottom up, outermost locations first within a row (the fill order keeps each partial pattern symmetric and its centroid low).

Locations in PSIBeamSection.draped_required come last so a straight-strand design never occupies them by accident.

civilpy.structural.odot.ps_i_beam.strand_pattern(name: str, n_strands: int) list[tuple[float, float]][source]

The first n_strands locations of strand_grid() – the pattern the pipeline’s designer uses. Raises ValueError when n_strands exceeds the section’s permissible locations.

civilpy.structural.odot.roadway_barrier module

Ohio DOT standard roadway (at-grade) single-slope concrete barriers.

Office of Roadway Engineering counterparts of the Office of Structural Engineering’s bridge parapets in civilpy.structural.odot.bridge_railing – same 5.25:1 single-slope face, but freestanding at grade (median or shoulder) rather than backed against a deck edge. shape carries "single slope" so civilpy.structural.rhino_barrier.shape_family() routes these through the same profile-sweep engine; unlike a deck-edge parapet a roadway barrier is placed with side=0 (freestanding, symmetric about its centerline).

Types B/B1/D/N are fully dimensioned on their drawings (fixed height, top, and base width). Types C/C1 are variable-height siblings of B/B1 – the drawings show a project-defined upper extension (“Varies … See Plans for dimensions”) added above the fixed B/B1 body, so no formula is transcribed for the extension; height/base_width here are the B/B1 base-body values and notes records the variable range. Type E (RM-4.9) differs structurally – a shorter 36 in barrier on a cast-in-place moment slab foundation with a curved/vertical face – and its concrete envelope is not dimensioned on the drawing (only the rebar cage is); its catalog entry therefore omits top_width/base_width rather than inventing them, and layout_roadway_barrier() raises if asked to build its profile.

Two companion drawings extend the same profile engine along the run:

  • RM-4.6 end sections (layout_barrier_end_section()): the cast-in-place taper that steps a Type B / B1 / D barrier down to a 32 in vertical-faced end for a Bridge Terminal Assembly or impact attenuator connection — profiles at the drawing’s stations, ready to loft.

  • RM-4.4 transitions (layout_barrier_transition()): the plan-view widening that wraps a Type B/B1/C/C1 barrier around a sign support / light tower foundation or a bridge pier — half-width per station over the 40 ft tapers.

Lengths are in inches unless noted. Concrete strength f_c in ksi.

Sources (SCD number — drawing date / latest cited revision):

RM-4.3 Single slope barrier, Types B, B1, C, C1 (rev. 2025-07-18) RM-4.4 Single slope barrier transitions (rev. 2025-01-17) RM-4.5 Single slope barrier, Type D (rev. 2026-01-16) RM-4.6 Concrete barrier end sections, Types B, B1, D (rev. 2025-07-18) RM-4.8 Single slope barrier, Type N (general design) (rev. 2026-01-16) RM-4.9 Single slope barrier, Type E, moment slab foundation (rev. 2025-07-18)

civilpy.structural.odot.roadway_barrier.BARRIER_END_SECTIONS: dict[str, BarrierEndSection] = {'Type B': BarrierEndSection(scd='RM-4.6', scd_date='2025-07-18', designation='Type B', parent='Type B', total_length_ft=30.0, body_length_ft=16.0, face_transition_ft=10.0, vertical_run_in=32.0, end_taper_in=16.0, end_height_in=32.0, end_width_in=32.0, end_core_width_in=24.0, median=True, notes='Median end section for the 42 in Type B; X501-X505 #5 / Y601-Y603 #6 cage per the sheet 1 steel list.'), 'Type B1': BarrierEndSection(scd='RM-4.6', scd_date='2025-07-18', designation='Type B1', parent='Type B1', total_length_ft=30.0, body_length_ft=16.0, face_transition_ft=10.0, vertical_run_in=32.0, end_taper_in=16.0, end_height_in=32.0, end_width_in=32.0, end_core_width_in=24.0, median=True, notes='Median end section for the 57 in Type B1; the top tapers 57 -> 42 in over the 16 ft body, then follows the Type B transition. X511-X515 / Y611-Y613 cage per the sheet 2 list.'), 'Type D': BarrierEndSection(scd='RM-4.6', scd_date='2025-07-18', designation='Type D', parent='Type D', total_length_ft=14.0, body_length_ft=0.0, face_transition_ft=10.0, vertical_run_in=32.0, end_taper_in=16.0, end_height_in=32.0, end_width_in=20.0, end_core_width_in=16.0, median=False, notes='Roadside end section for the 42 in Type D (traffic on one side); single-slope traffic face only. X521-X524 / Y621-Y623 cage per the sheet 3 list.')}

RM-4.6 end sections keyed by designation.

class civilpy.structural.odot.roadway_barrier.BarrierEndSection(scd: str, scd_date: str, designation: str, parent: str, total_length_ft: float, body_length_ft: float, face_transition_ft: float, vertical_run_in: float, end_taper_in: float, end_height_in: float, end_width_in: float, end_core_width_in: float, median: bool = True, notes: str = '')[source]

Bases: object

One RM-4.6 cast-in-place concrete barrier end section.

Steps the parent single-slope barrier down to a 32 in tall, vertical-faced end that a Bridge Terminal Assembly (SCD MGS-3.1/3.2/ 3.3, Item 606) or impact attenuator attaches to; the single-slope faces transition to vertical over 10 ft to prevent snagging, and the concrete end carries a 4:1 plan flare over the last 16 in. Paid as Item 622 “Concrete Barrier End Section, Type _”, Each.

body_length_ft: float

Full parent-profile run before the face transition, ft (the Type B1 body also tapers 57 -> 42 in tall across it).

designation: str
end_core_width_in: float

vertical-faced core between curbs

end_height_in: float
end_taper_in: float

1 concrete end flare

Type:

4

end_width_in: float

overall width across the curbs

face_transition_ft: float

vertical-face transition length

median: bool = True

median (two-sided) vs roadside

notes: str = ''
parent: str

RM-4.3 / RM-4.5 barrier designation

scd: str
scd_date: str
total_length_ft: float
vertical_run_in: float

full-height vertical-face run

class civilpy.structural.odot.roadway_barrier.BarrierEndSectionLayout(end_section: BarrierEndSection, stations: tuple[tuple[float, tuple[tuple[float, float], ...]], ...], notes: tuple[str, ...] = ())[source]

Bases: object

Stationed cross-sections of an RM-4.6 end section, ready to loft.

stations is a tuple of (station_ft, profile) pairs from the parent-barrier joint (station 0) to the end; each profile is a closed (offset_in, z_in) loop in the roadway-barrier convention. The 4:1 plan end flare inside the last 16 in is described in notes rather than drawn (it rounds the very end plan corners).

end_section: BarrierEndSection
notes: tuple[str, ...] = ()
stations: tuple[tuple[float, tuple[tuple[float, float], ...]], ...]
class civilpy.structural.odot.roadway_barrier.BarrierTransitionLayout(barrier: RoadwayBarrier, kind: str, obstruction_width_in: float, stations: tuple[tuple[float, float], ...], total_length_ft: float, notes: tuple[str, ...] = ())[source]

Bases: object

Plan-view widening of an RM-4.4 single-slope barrier transition.

stations is a tuple of (station_ft, width_in) pairs of the barrier’s overall plan width from the start of the first taper; the cross-section at any station keeps the parent barrier’s height and 5.25:1 faces with the extra width filled solid between them.

barrier: RoadwayBarrier
kind: str
notes: tuple[str, ...] = ()
obstruction_width_in: float
stations: tuple[tuple[float, float], ...]
total_length_ft: float
civilpy.structural.odot.roadway_barrier.PIER_PROTECTION_WIDTH_IN = 48.0

Barrier width at a protected pier column, inches.

civilpy.structural.odot.roadway_barrier.PIER_RUN_EACH_SIDE_FT = 5.0

Flat run beyond each pier column face, ft.

civilpy.structural.odot.roadway_barrier.ROADWAY_BARRIERS: dict[str, RoadwayBarrier] = {'Type B': RoadwayBarrier(scd='RM-4.3', scd_date='2025-07-18', designation='Type B', name='Single slope barrier, Type B (concrete pavement)', shape='single slope', material='reinforced concrete', height=42.0, top_width=12.0, base_width=28.0, slope_h_to_v=5.25, f_c=4.0, foundation='pavement', joint_spacing_ft=20.0, notes='Cast on new concrete pavement (8+12+8 in base split); asphalt-pavement variant uses the same body with an alternate 59 in extended toe (not modeled).'), 'Type B1': RoadwayBarrier(scd='RM-4.3', scd_date='2025-07-18', designation='Type B1', name='Single slope barrier, Type B1 (asphalt pavement)', shape='single slope', material='reinforced concrete', height=57.0, top_width=12.0, base_width=33.75, slope_h_to_v=5.25, f_c=4.0, foundation='pavement', joint_spacing_ft=20.0, notes='Taller (57 in) variant of Type B for asphalt pavement (10.875+12+10.875 in base split).'), 'Type C': RoadwayBarrier(scd='RM-4.3', scd_date='2025-07-18', designation='Type C', name='Single slope barrier, Type C (variable height, asphalt)', shape='single slope', material='reinforced concrete', height=42.0, top_width=12.0, base_width=28.0, slope_h_to_v=5.25, f_c=4.0, foundation='pavement', joint_spacing_ft=20.0, notes='Variable-height sibling of Type B: an additional 0-24 in extension is added above this 42 in body per project plans (sheet gives no formula for the extension geometry); overall height ranges 42-66 in. Height/base values here are the fixed Type B base body only.'), 'Type C1': RoadwayBarrier(scd='RM-4.3', scd_date='2025-07-18', designation='Type C1', name='Single slope barrier, Type C1 (variable height, concrete)', shape='single slope', material='reinforced concrete', height=57.0, top_width=12.0, base_width=33.75, slope_h_to_v=5.25, f_c=4.0, foundation='pavement', joint_spacing_ft=20.0, notes='Variable-height sibling of Type B1: an additional 0-24 in extension above this 57 in body per project plans; overall height ranges 57-81 in. Height/base values here are the fixed Type B1 base body only.'), 'Type D': RoadwayBarrier(scd='RM-4.5', scd_date='2026-01-16', designation='Type D', name='Single slope barrier, Type D (obstructions, compacted soil)', shape='single slope', material='reinforced concrete', height=42.0, top_width=12.0, base_width=28.0, slope_h_to_v=5.25, f_c=4.0, foundation='compacted soil', joint_spacing_ft=20.0, notes='Used at obstructions (light poles, piers, etc.) in the median/shoulder; founded on compacted soil (20 in min shoulder, 20:1 permissible batter, 2:1 max embankment beyond) rather than doweled to pavement. Longitudinal steel not required when top width >= 12 in. Transitions to MGS Bridge Terminal Assembly, Type 1/2 (SCD MGS-3.1) at each end; End Sections per RM-4.6.'), 'Type E': RoadwayBarrier(scd='RM-4.9', scd_date='2025-07-18', designation='Type E', name='Single slope barrier, Type E (moment slab foundation)', shape='single slope (moment slab)', material='reinforced concrete', height=36.0, top_width=None, base_width=None, slope_h_to_v=None, f_c=None, foundation='moment slab', joint_spacing_ft=100.0, notes="MASH TL-4. Mounted on a cast-in-place moment slab (5 ft min width, 1 ft min thickness, 6 - #5 bars @ 5 equal spaces plus Bar U #4 stirrups at 6 in) rather than doweled to pavement/leveling pad. Bar S (#4) vertical face bars at 6 in o.c.; 3/4 in PEJF at 20 ft min / 100 ft max barrier-segment joints and at the moment slab / adjacent pavement interface. Concrete face envelope (top/base width) is not dimensioned on this sheet -- only the rebar cage is -- so it is not transcribed; coordinate with plans or treat RM-4.3 Type B's 42 in profile as a rough visual stand-in. Transitions from RM-4.5's 42 in Type D barrier (see sheet 3)."), 'Type N': RoadwayBarrier(scd='RM-4.8', scd_date='2026-01-16', designation='Type N', name='Single slope barrier, Type N (general design)', shape='single slope', material='reinforced concrete', height=81.0, top_width=12.0, base_width=42.875, slope_h_to_v=5.25, f_c=4.0, foundation='leveling pad', joint_spacing_ft=10.0, notes='Tallest of the family (81 in); cast on a 9 in concrete leveling pad (Item 451, Class QC 1P) over Item 304 aggregate base for new pavement, or doweled to a sawcut existing pavement edge. 1 in PEJF (CMS 705.03) at the leveling pad / pavement interface, sealed with CMS 705.04. #8 x 12 in epoxy dowels; 4 in min raceway clearance to conduits (2 in ITS / 4 in lighting).')}

Catalog keyed by designation (e.g. "Type B", "Type N").

class civilpy.structural.odot.roadway_barrier.RoadwayBarrier(scd: str, scd_date: str, designation: str, name: str, shape: str, material: str = 'reinforced concrete', height: float | None = None, top_width: float | None = None, base_width: float | None = None, slope_h_to_v: float | None = None, f_c: float | None = None, foundation: str = 'pavement', joint_spacing_ft: float | None = None, notes: str = '')[source]

Bases: object

One Ohio DOT standard roadway single-slope barrier type.

Mirrors the field names civilpy.structural.rhino_barrier .barrier_profile() reads (shape, height, base_width, top_width) so the same profile-sweep engine renders these as it does the structural bridge parapets.

base_width: float | None = None
designation: str
f_c: float | None = None
foundation: str = 'pavement'

“pavement” (cast on/dowelled to pavement), “leveling pad” (RM-4.8 Type N), “compacted soil” (RM-4.5 Type D), or “moment slab” (RM-4.9 Type E).

Type:

Foundation

height: float | None = None
joint_spacing_ft: float | None = None

Max unsealed-joint / contraction-joint spacing, ft.

material: str = 'reinforced concrete'
name: str
notes: str = ''
scd: str
scd_date: str
shape: str
slope_h_to_v: float | None = None
top_width: float | None = None
class civilpy.structural.odot.roadway_barrier.RoadwayBarrierInput(designation: str, length_ft: float)[source]

Bases: object

Inputs for one straight run of a roadway single-slope barrier.

designation: str
length_ft: float
class civilpy.structural.odot.roadway_barrier.RoadwayBarrierLayout(barrier: RoadwayBarrier, length_ft: float, profile: tuple[tuple[float, float], ...], notes: tuple[str, ...] = ())[source]

Bases: object

Symmetric cross-section plus run length for a roadway barrier.

profile is a closed list of (offset_in, z_in) vertices, offset measured from the barrier centerline and z from its base – the same convention civilpy.structural.rhino_barrier.barrier_profile() uses for a freestanding (side=0) section.

barrier: RoadwayBarrier
length_ft: float
notes: tuple[str, ...] = ()
profile: tuple[tuple[float, float], ...]
civilpy.structural.odot.roadway_barrier.SIGN_SUPPORT_RUN_FT = 10.0

Flat run at a sign support / light tower foundation, ft.

civilpy.structural.odot.roadway_barrier.SIGN_SUPPORT_WIDTH_RANGE_IN = (36.0, 48.0)

Foundation-width band the sheet allows at a sign support, inches.

civilpy.structural.odot.roadway_barrier.TRANSITION_RACEWAYS = ('2 in ITS raceway (HDPE per SS809)', '4 in lighting raceway (CMS 625.12)')

Raceways cast into the widened barrier (RACEWAY PLACEMENT detail).

civilpy.structural.odot.roadway_barrier.TRANSITION_TAPER_FT = 40.0

RM-4.4 plan-taper length each side of the obstruction, ft.

civilpy.structural.odot.roadway_barrier.barrier_end_section(designation: str) BarrierEndSection[source]

Look up an RM-4.6 end section by designation ("Type B", "Type B1", "Type D").

civilpy.structural.odot.roadway_barrier.layout_barrier_end_section(designation: str) BarrierEndSectionLayout[source]

Build the lofting stations for an RM-4.6 end section.

civilpy.structural.odot.roadway_barrier.layout_barrier_transition(designation: str, kind: str, *, obstruction_width_in: float | None = None, obstruction_length_ft: float = 0.0) BarrierTransitionLayout[source]

Build the RM-4.4 plan-width stations for a barrier transition.

designation is an RM-4.3 type (B/B1/C/C1); kind is "sign support" (light tower / sign foundation, 36-48 in wide, 10 ft run) or "pier" (48 in wide pier column protection; obstruction_length_ft is the variable column run between the two 5 ft shoulders). Raises ValueError for other barrier types or a sign-support width outside the sheet’s 36-48 in band.

civilpy.structural.odot.roadway_barrier.layout_roadway_barrier(inp: RoadwayBarrierInput) RoadwayBarrierLayout[source]

Build the symmetric single-slope cross-section for inp.

civilpy.structural.odot.roadway_barrier.roadway_barrier(designation: str) RoadwayBarrier[source]

Look up a roadway barrier type by its designation (e.g. "Type B", "Type N").

civilpy.structural.odot.roadway_portable_barrier module

Ohio DOT standard roadway (at-grade) portable concrete barriers.

Office of Roadway Engineering successors to Structural Engineering’s PCB-91 (civilpy.structural.odot.portable_barrier): the same New Jersey shape family, reused here via BridgeRailing so name containing "portable" routes through civilpy.structural.rhino_barrier.shape_family()’s freestanding symmetric F-shape profile exactly as PCB-91 does.

Both are pin-and-loop / hinge-bar connected precast segments, NOT suitable at bridge deck edges or similar dropoffs (a fixed anchored barrier or bridge-mounted PCB is required there instead).

Sources (SCD number — drawing date / latest cited revision):
RM-4.2 32 in Portable Concrete Barrier, New Jersey shape, pin & loop

connection (rev. 2026-01-16)

RM-4.1 50 in Portable Concrete Barrier + 50->32 in transition section

(hinge bar connection) (rev. 2020-01-17)

civilpy.structural.odot.roadway_portable_barrier.CONNECTOR_BOLT_SPEC = '7/8" dia through bolts, ASTM A325 or A449'

7/8 in dia ASTM A325 or A449; at least 5 installed, 3 in the outer vertical row, >= 6 in from the segment end and >= 3 in from lifting holes/voids.

Type:

Terminal-connector through bolts

civilpy.structural.odot.roadway_portable_barrier.CONNECTOR_END_DISTANCE_MIN_IN = 6.0

Minimum distance from the PCB end to the terminal connector.

civilpy.structural.odot.roadway_portable_barrier.PCB_GAP_MAX_IN = 12.0

Maximum plan gap between the two PCB ends.

civilpy.structural.odot.roadway_portable_barrier.ROADWAY_PORTABLE_BARRIERS: dict[str, BridgeRailing] = {'RM Portable (32 in, pin & loop)': BridgeRailing(scd='RM-4.2', scd_date='2026-01-16', designation='RM Portable (32 in, pin & loop)', name='Portable concrete barrier, 32 in, New Jersey shape, pin & loop', shape='New Jersey', material='precast concrete', test_level='', height=32.0, base_width=24.0, top_width=6.0, section_area=None, f_c=4.0, f_y=None, vertical_bar_spacing=None, bar_sizes=(), transition_length_ft=None, transition_volume_cy=None, post_shape='', post_spacing=None, rail_element='', f_y_steel=None, weight_per_ft=None, segment_length_ft=(10.0, 12.0, 20.0), rail_height_above_in=None, notes="Office of Roadway Engineering successor to PCB-91: pin & loop connection (vs. PCB-91's hinge bar + through-bolt), segments 10-20 ft (vs. PCB-91's fixed 10/12 ft). Not for bridge deck edges or similar dropoffs. Drawing states no numeric NCHRP/MASH test level."), 'RM Portable (50 in, hinge bar)': BridgeRailing(scd='RM-4.1', scd_date='2020-01-17', designation='RM Portable (50 in, hinge bar)', name='Portable concrete barrier, 50 in, New Jersey shape, hinge bar', shape='New Jersey', material='precast concrete', test_level='TL-3', height=50.0, base_width=24.0, top_width=12.0, section_area=None, f_c=4.0, f_y=None, vertical_bar_spacing=None, bar_sizes=(), transition_length_ft=None, transition_volume_cy=None, post_shape='', post_spacing=None, rail_element='', f_y_steel=None, weight_per_ft=None, segment_length_ft=(12.0, 14.0), rail_height_above_in=None, notes="Marked PCB-RXX-350-TL3. Not to be used on bridge deck edges or similar dropoffs -- the only suitable barrier there is the 32 in PCB per Structural Engineering's PCB-91 (or an approved alternative). Mates to a 32 in barrier (RM-4.2 or PCB-91) only through the 50 in Transition Section; Impact Attenuators may only attach to that transition's 32 in end.")}

Catalog keyed by designation.

civilpy.structural.odot.roadway_portable_barrier.SPACER_PLATE_IN = (6.0, 10.0, 0.25)

Terminal-connector steel spacer (CMS 711.01, galvanized 711.02): 6 x 10 x 1/4 in plate with 1 in dia holes; add spacers to fit field conditions.

civilpy.structural.odot.roadway_portable_barrier.THRIE_BEAM_ELEMENT = '6 ft-3 in nested 12-gauge thrie-beam'

Nested thrie-beam element bridging the joint.

civilpy.structural.odot.roadway_portable_barrier.THRIE_BEAM_PCB_TRANSITIONS: dict[tuple[str, str], ThrieBeamPCBTransition] = {('Generic 32" F-shape PCB', 'J-J Hook 32" F-shape PCB'): ThrieBeamPCBTransition(sheet=3, barrier_a='Generic 32" F-shape PCB', barrier_b='J-J Hook 32" F-shape PCB', notes=''), ('Generic 32" New Jersey shape PCB', 'Generic 32" F-shape PCB'): ThrieBeamPCBTransition(sheet=1, barrier_a='Generic 32" New Jersey shape PCB', barrier_b='Generic 32" F-shape PCB', notes='May also connect barriers of the same shape. Not approved for the J-J Hook 32 in New Jersey shape PCB.'), ('Generic 32" New Jersey shape PCB', 'J-J Hook 32" F-shape PCB'): ThrieBeamPCBTransition(sheet=2, barrier_a='Generic 32" New Jersey shape PCB', barrier_b='J-J Hook 32" F-shape PCB', notes='')}

RM-4.7 connection pairs keyed by (a, b) shape names.

civilpy.structural.odot.roadway_portable_barrier.TOE_PLATE_IN = (108.0, 5.5, 0.625)

9 ft-0 in x 5-1/2 in x 5/8 in with 24 holes (1 in dia) at 4-3/4 in; anchors 7/8 x 6 in (CMS 712.01 or FF-S325 Grp VIII Type 1), >= 4 per end.

Type:

Toe plate along the base (CMS 711.01, galvanized 711.02)

civilpy.structural.odot.roadway_portable_barrier.TRANSITION_50_TO_32 = TransitionSection(scd='RM-4.1', name='50 in to 32 in portable barrier transition section', height_from_in=50.0, height_to_in=32.0, length_ft=6.0, notes="Tapers RM-4.1's 50 in barrier down to a 32 in end compatible with RM-4.2 or PCB-91; only this 32 in end may attach to an Impact Attenuator or to Guardrail per RM-4.2 notes/MT-101.80.")

The RM-4.1 50 in -> 32 in taper joining the two roadway PCB families.

class civilpy.structural.odot.roadway_portable_barrier.ThrieBeamPCBTransition(sheet: int, barrier_a: str, barrier_b: str, notes: str = '')[source]

Bases: object

One RM-4.7 connection pair (one sheet each). barrier_a / barrier_b name the generic/proprietary 32 in PCB shapes joined; the hardware set is common to all three pairs.

barrier_a: str
barrier_b: str
notes: str = ''
sheet: int
class civilpy.structural.odot.roadway_portable_barrier.TransitionSection(scd: str, name: str, height_from_in: float, height_to_in: float, length_ft: float, notes: str = '')[source]

Bases: object

A tapered end section joining two different barrier heights.

height_from_in: float
height_to_in: float
length_ft: float
name: str
notes: str = ''
scd: str
civilpy.structural.odot.roadway_portable_barrier.USE_LIMIT = 'once per mile with project engineer approval'

Deployment limits (general notes, all sheets).

civilpy.structural.odot.roadway_portable_barrier.roadway_portable_barrier(designation: str) BridgeRailing[source]

Look up a roadway portable barrier by its designation (e.g. "RM Portable (32 in, pin & loop)").

civilpy.structural.odot.roadway_portable_barrier.thrie_beam_pcb_transition(barrier_a: str, barrier_b: str) ThrieBeamPCBTransition[source]

Look up the RM-4.7 pair joining two PCB shapes (order-free). Raises ValueError naming the cataloged pairs otherwise — in particular there is no approved pair involving the J-J Hook 32 in New Jersey shape PCB.

civilpy.structural.odot.roadway_portable_barrier.thrie_beam_transition_notes() tuple[str, ...][source]

The deployment / payment rules common to every RM-4.7 pair.

civilpy.structural.odot.rocker_bolster module

Ohio DOT structural steel rockers and bolsters (RB-1-55).

Dimension and capacity table transcribed from the Ohio DOT Standard Bridge Drawing RB-1-55, “Rockers and Bolsters for Steel and Girder Bridges” (Office of Structural Engineering, 1955-03-01, rev. 2024-07-19).

Each row pairs a bolster (fixed bearing) with a rocker (expansion bearing) of the same rated capacity; the number in the B-xxx / R-xxx designation is the maximum load in kips. The dimension letters key the figure on RB-1-55 and are stored in dims (all inches). Per the drawing, this design is limited to anticipated movement of 2 in or less.

Dimensions in inches, weights in pounds, load in pounds. Spot-checked against the drawing in the test suite.

civilpy.structural.odot.rocker_bolster.DIM_LETTERS: tuple[str, ...] = ('A', 'B', 'C', 'D', 'F', 'G', 'H', 'K', 'L', 'M', 'R', 'T', 'Y')

Dimension letters in RB-1-55 table column order.

civilpy.structural.odot.rocker_bolster.MAX_MOVEMENT = 2.0

Maximum anticipated movement this bearing design allows, inches.

civilpy.structural.odot.rocker_bolster.ROCKER_BOLSTERS: dict[int, RockerBolster] = {75: RockerBolster(capacity_kips=75, bolster_no='', rocker_no='R-75', dims={'A': 2.5, 'B': 8, 'C': 2.5, 'D': 1.75, 'F': 0.5, 'G': 7, 'H': 9.625, 'K': 9, 'L': 18, 'M': 16, 'R': 5.5, 'T': 1.5, 'Y': 1.1875}, weight_bolster_lb=None, weight_rocker_lb=205, max_load_lb=75000.0), 100: RockerBolster(capacity_kips=100, bolster_no='B-100', rocker_no='R-100', dims={'A': 2.5, 'B': 10, 'C': 2.5, 'D': 2, 'F': 0.5, 'G': 7.5, 'H': 10.625, 'K': 9, 'L': 19, 'M': 17, 'R': 6.5, 'T': 1.5, 'Y': 1.1875}, weight_bolster_lb=225, weight_rocker_lb=250, max_load_lb=100000.0), 125: RockerBolster(capacity_kips=125, bolster_no='B-125', rocker_no='R-125', dims={'A': 3, 'B': 11, 'C': 3, 'D': 2, 'F': 0.5, 'G': 8, 'H': 12.125, 'K': 10.5, 'L': 20, 'M': 18, 'R': 7.5, 'T': 1.5, 'Y': 1.4375}, weight_bolster_lb=295, weight_rocker_lb=315, max_load_lb=125000.0), 150: RockerBolster(capacity_kips=150, bolster_no='B-150', rocker_no='R-150', dims={'A': 3, 'B': 12, 'C': 3, 'D': 2.25, 'F': 0.5, 'G': 8.5, 'H': 13.375, 'K': 11.5, 'L': 22, 'M': 19, 'R': 8.5, 'T': 1.75, 'Y': 1.4375}, weight_bolster_lb=360, weight_rocker_lb=400, max_load_lb=150000.0), 175: RockerBolster(capacity_kips=175, bolster_no='B-175', rocker_no='R-175', dims={'A': 3, 'B': 14, 'C': 3.5, 'D': 2.5, 'F': 0.5, 'G': 9, 'H': 15.125, 'K': 12, 'L': 23, 'M': 20, 'R': 9.5, 'T': 2, 'Y': 1.4375}, weight_bolster_lb=455, weight_rocker_lb=505, max_load_lb=175000.0), 200: RockerBolster(capacity_kips=200, bolster_no='B-200', rocker_no='R-200', dims={'A': 3, 'B': 16, 'C': 3.5, 'D': 2.75, 'F': 0.625, 'G': 9, 'H': 16.375, 'K': 12, 'L': 24, 'M': 21, 'R': 10.5, 'T': 2.25, 'Y': 1.4375}, weight_bolster_lb=540, weight_rocker_lb=605, max_load_lb=200000.0), 225: RockerBolster(capacity_kips=225, bolster_no='B-225', rocker_no='R-225', dims={'A': 3, 'B': 17, 'C': 3.5, 'D': 2.75, 'F': 0.625, 'G': 9, 'H': 16.875, 'K': 13, 'L': 25, 'M': 22, 'R': 11, 'T': 2.25, 'Y': 1.4375}, weight_bolster_lb=590, weight_rocker_lb=665, max_load_lb=225000.0), 250: RockerBolster(capacity_kips=250, bolster_no='B-250', rocker_no='R-250', dims={'A': 3.5, 'B': 18, 'C': 3.5, 'D': 2.75, 'F': 0.75, 'G': 10, 'H': 17.625, 'K': 13, 'L': 26, 'M': 23, 'R': 11.5, 'T': 2.5, 'Y': 1.6875}, weight_bolster_lb=695, weight_rocker_lb=775, max_load_lb=250000.0), 275: RockerBolster(capacity_kips=275, bolster_no='B-275', rocker_no='R-275', dims={'A': 3.5, 'B': 19, 'C': 3.5, 'D': 3.25, 'F': 0.75, 'G': 12, 'H': 18.375, 'K': 14, 'L': 27, 'M': 24, 'R': 12, 'T': 2.75, 'Y': 1.6875}, weight_bolster_lb=800, weight_rocker_lb=945, max_load_lb=275000.0), 300: RockerBolster(capacity_kips=300, bolster_no='B-300', rocker_no='R-300', dims={'A': 3.5, 'B': 20, 'C': 3.5, 'D': 3.25, 'F': 0.75, 'G': 12, 'H': 19.125, 'K': 14, 'L': 28, 'M': 25, 'R': 12.5, 'T': 3, 'Y': 1.6875}, weight_bolster_lb=895, weight_rocker_lb=1050, max_load_lb=300000.0)}

Rocker/bolster lines keyed by capacity in kips.

class civilpy.structural.odot.rocker_bolster.RockerBolster(capacity_kips: int, bolster_no: str, rocker_no: str, dims: dict[str, float], weight_bolster_lb: float | None, weight_rocker_lb: float, max_load_lb: float)[source]

Bases: object

One RB-1-55 rocker/bolster capacity line.

bolster_no is empty for the smallest line (R-75 has no matching bolster). dims is keyed by the letters in DIM_LETTERS.

bolster_no: str
capacity_kips: int
dims: dict[str, float]
max_load_lb: float
rocker_no: str
weight_bolster_lb: float | None
weight_rocker_lb: float
class civilpy.structural.odot.rocker_bolster.RockerBolsterLayout(rb: ~civilpy.structural.odot.rocker_bolster.RockerBolster, base_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], base_thickness_in: float, bolster_top: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], bolster_height_in: float, rocker_top_radius_in: float, rocker_height_in: float, notes: tuple[str, ...] = <factory>)[source]

Bases: object

The generated bolster + rocker pair for one capacity line, sharing the base-plate footprint origin at plan center, z = 0 at the bottom of the base plate.

base_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
base_thickness_in: float
bolster_height_in: float
bolster_top: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
notes: tuple[str, ...]
rb: RockerBolster
rocker_height_in: float
rocker_top_radius_in: float
civilpy.structural.odot.rocker_bolster.layout_rocker_bolster(rb: RockerBolster) RockerBolsterLayout[source]

Generate the drawable subset of one RB-1-55 capacity line: the shared base-plate footprint, the bolster’s tapered+flat-top body, and the rocker’s tapered+curved-top body.

civilpy.structural.odot.rocker_bolster.rocker_bolster(capacity_kips: int) RockerBolster[source]

Look up a rocker/bolster line by rated capacity in kips (75..300).

civilpy.structural.odot.rocker_bolster.smallest_for_load(load_lb: float) RockerBolster[source]

The lightest standard rocker/bolster whose maximum load covers load_lb; raises ValueError if the load exceeds the 300-kip line.

civilpy.structural.odot.rocker_bolster.top_bearing_plate_radius_in(a_in: float) float[source]
civilpy.structural.odot.rocker_bolster.top_bearing_web_radius_in(a_in: float) float[source]

civilpy.structural.odot.slab_bridge module

Ohio DOT single span slab bridges (SB-1-24).

Transcribed from Ohio DOT Standard Bridge Drawing SB-1-24, “Single Span Slab Bridges” (rev. 01-16-2026, 2 sheets). The drawing remains the controlling document.

Sheet 1’s SLAB DATA table gives the slab thickness and the A/B/M/N longitudinal reinforcing bar spacing/size for spans 11-38 ft; sheet 2’s EDGE BEAM SLAB DATA table gives the edge-beam depth D, taper X, and D/E-bar spacing/size for the two edge conditions (over-the-side drainage vs. a concrete parapet, which allows a shallower edge beam).

Design basis (sheet 2 notes): AASHTO LRFD 9th Ed. + ODOT BDM (July 2023); HL-93; FWS 60 lb/ft^2; 1 in monolithic wearing surface; concrete f’c = 4500 psi; reinforcing steel min. yield 60,000 psi, epoxy coated. Applicable for roadway widths >= 24 ft and skew <= 25 deg. For skew 0 < theta <= 25 deg, longitudinal bars stay parallel to the roadway centerline and transverse bars parallel to the pier/abutment skew line (the slab plan is a skewed parallelogram, same shear convention as every other flared/skewed layout in this package).

Conventions: X along stations, Y transverse, Z up; feet in plan, inches for section dimensions. The layout origin sits at the upstream bearing line, y = 0 at one slab edge, z = 0 at the top of slab.

civilpy.structural.odot.slab_bridge.BEARING_SEAT_IN = 9.0

Bearing-seat width at each abutment, inches (elevation view “9”/COS(theta)”).

class civilpy.structural.odot.slab_bridge.BarRun(mark: 'str', size: 'int', points: 'tuple[Point, ...]')[source]

Bases: object

mark: str
points: tuple[tuple[float, float, float], ...]
size: int
class civilpy.structural.odot.slab_bridge.BarSpec(spacing_in: 'float', size: 'int')[source]

Bases: object

size: int
spacing_in: float
civilpy.structural.odot.slab_bridge.EDGE_BEAM_DESIGNS: dict[int, EdgeBeamDesign] = {11: EdgeBeamDesign(span_ft=11, over_the_side=EdgeBarSpec(depth_in=20, taper_in=45, bar_size=7, bar_count=8), parapet=EdgeBarSpec(depth_in=18, taper_in=57, bar_size=7, bar_count=8)), 12: EdgeBeamDesign(span_ft=12, over_the_side=EdgeBarSpec(depth_in=20, taper_in=45, bar_size=7, bar_count=8), parapet=EdgeBarSpec(depth_in=18, taper_in=57, bar_size=7, bar_count=8)), 13: EdgeBeamDesign(span_ft=13, over_the_side=EdgeBarSpec(depth_in=20, taper_in=45, bar_size=7, bar_count=8), parapet=EdgeBarSpec(depth_in=18, taper_in=57, bar_size=7, bar_count=8)), 14: EdgeBeamDesign(span_ft=14, over_the_side=EdgeBarSpec(depth_in=20, taper_in=45, bar_size=7, bar_count=8), parapet=EdgeBarSpec(depth_in=18, taper_in=57, bar_size=7, bar_count=8)), 15: EdgeBeamDesign(span_ft=15, over_the_side=EdgeBarSpec(depth_in=20, taper_in=45, bar_size=7, bar_count=8), parapet=EdgeBarSpec(depth_in=18, taper_in=57, bar_size=7, bar_count=8)), 16: EdgeBeamDesign(span_ft=16, over_the_side=EdgeBarSpec(depth_in=20, taper_in=45, bar_size=7, bar_count=8), parapet=EdgeBarSpec(depth_in=18, taper_in=57, bar_size=8, bar_count=7)), 17: EdgeBeamDesign(span_ft=17, over_the_side=EdgeBarSpec(depth_in=20, taper_in=45, bar_size=8, bar_count=7), parapet=EdgeBarSpec(depth_in=18, taper_in=57, bar_size=8, bar_count=8)), 18: EdgeBeamDesign(span_ft=18, over_the_side=EdgeBarSpec(depth_in=20, taper_in=45, bar_size=8, bar_count=7), parapet=EdgeBarSpec(depth_in=18, taper_in=57, bar_size=8, bar_count=8)), 19: EdgeBeamDesign(span_ft=19, over_the_side=EdgeBarSpec(depth_in=20, taper_in=48, bar_size=8, bar_count=8), parapet=EdgeBarSpec(depth_in=18, taper_in=60, bar_size=8, bar_count=9)), 20: EdgeBeamDesign(span_ft=20, over_the_side=EdgeBarSpec(depth_in=20, taper_in=48, bar_size=8, bar_count=8), parapet=EdgeBarSpec(depth_in=18, taper_in=60, bar_size=8, bar_count=10)), 21: EdgeBeamDesign(span_ft=21, over_the_side=EdgeBarSpec(depth_in=20, taper_in=48, bar_size=9, bar_count=8), parapet=EdgeBarSpec(depth_in=18, taper_in=60, bar_size=8, bar_count=10)), 22: EdgeBeamDesign(span_ft=22, over_the_side=EdgeBarSpec(depth_in=20, taper_in=48, bar_size=9, bar_count=8), parapet=EdgeBarSpec(depth_in=18, taper_in=60, bar_size=9, bar_count=9)), 23: EdgeBeamDesign(span_ft=23, over_the_side=EdgeBarSpec(depth_in=20, taper_in=48, bar_size=9, bar_count=8), parapet=EdgeBarSpec(depth_in=18, taper_in=60, bar_size=9, bar_count=10)), 24: EdgeBeamDesign(span_ft=24, over_the_side=EdgeBarSpec(depth_in=20, taper_in=48, bar_size=9, bar_count=9), parapet=EdgeBarSpec(depth_in=18.25, taper_in=60, bar_size=9, bar_count=10)), 25: EdgeBeamDesign(span_ft=25, over_the_side=EdgeBarSpec(depth_in=20, taper_in=48, bar_size=9, bar_count=9), parapet=EdgeBarSpec(depth_in=18.75, taper_in=60, bar_size=9, bar_count=10)), 26: EdgeBeamDesign(span_ft=26, over_the_side=EdgeBarSpec(depth_in=20, taper_in=48, bar_size=10, bar_count=8), parapet=EdgeBarSpec(depth_in=19.25, taper_in=60, bar_size=9, bar_count=11)), 27: EdgeBeamDesign(span_ft=27, over_the_side=EdgeBarSpec(depth_in=20, taper_in=48, bar_size=10, bar_count=8), parapet=EdgeBarSpec(depth_in=19.75, taper_in=63, bar_size=10, bar_count=9)), 28: EdgeBeamDesign(span_ft=28, over_the_side=EdgeBarSpec(depth_in=20.5, taper_in=48, bar_size=10, bar_count=9), parapet=EdgeBarSpec(depth_in=20.5, taper_in=63, bar_size=10, bar_count=10)), 29: EdgeBeamDesign(span_ft=29, over_the_side=EdgeBarSpec(depth_in=21.0, taper_in=48, bar_size=10, bar_count=9), parapet=EdgeBarSpec(depth_in=21.0, taper_in=63, bar_size=10, bar_count=10)), 30: EdgeBeamDesign(span_ft=30, over_the_side=EdgeBarSpec(depth_in=21.5, taper_in=48, bar_size=10, bar_count=9), parapet=EdgeBarSpec(depth_in=21.5, taper_in=63, bar_size=10, bar_count=10)), 31: EdgeBeamDesign(span_ft=31, over_the_side=EdgeBarSpec(depth_in=22.25, taper_in=48, bar_size=10, bar_count=9), parapet=EdgeBarSpec(depth_in=22.0, taper_in=63, bar_size=10, bar_count=10)), 32: EdgeBeamDesign(span_ft=32, over_the_side=EdgeBarSpec(depth_in=22.75, taper_in=48, bar_size=10, bar_count=9), parapet=EdgeBarSpec(depth_in=22.75, taper_in=63, bar_size=10, bar_count=10)), 33: EdgeBeamDesign(span_ft=33, over_the_side=EdgeBarSpec(depth_in=23.25, taper_in=48, bar_size=10, bar_count=9), parapet=EdgeBarSpec(depth_in=23.25, taper_in=63, bar_size=10, bar_count=11)), 34: EdgeBeamDesign(span_ft=34, over_the_side=EdgeBarSpec(depth_in=23.75, taper_in=48, bar_size=10, bar_count=10), parapet=EdgeBarSpec(depth_in=23.75, taper_in=63, bar_size=10, bar_count=11)), 35: EdgeBeamDesign(span_ft=35, over_the_side=EdgeBarSpec(depth_in=24.25, taper_in=48, bar_size=10, bar_count=10), parapet=EdgeBarSpec(depth_in=24.25, taper_in=63, bar_size=10, bar_count=11)), 36: EdgeBeamDesign(span_ft=36, over_the_side=EdgeBarSpec(depth_in=25.0, taper_in=48, bar_size=10, bar_count=10), parapet=EdgeBarSpec(depth_in=25.0, taper_in=63, bar_size=10, bar_count=11)), 37: EdgeBeamDesign(span_ft=37, over_the_side=EdgeBarSpec(depth_in=25.5, taper_in=48, bar_size=10, bar_count=10), parapet=EdgeBarSpec(depth_in=25.5, taper_in=63, bar_size=10, bar_count=12)), 38: EdgeBeamDesign(span_ft=38, over_the_side=EdgeBarSpec(depth_in=26.0, taper_in=48, bar_size=10, bar_count=10), parapet=EdgeBarSpec(depth_in=26.0, taper_in=63, bar_size=10, bar_count=12))}

SB-1-24 EDGE BEAM SLAB DATA, keyed by span (ft).

class civilpy.structural.odot.slab_bridge.EdgeBarSpec(depth_in: 'float', taper_in: 'float', bar_size: 'int', bar_count: 'int')[source]

Bases: object

bar_count: int
bar_size: int
depth_in: float
taper_in: float
class civilpy.structural.odot.slab_bridge.EdgeBeamDesign(span_ft: int, over_the_side: EdgeBarSpec, parapet: EdgeBarSpec)[source]

Bases: object

One EDGE BEAM SLAB DATA table row (sheet 2): the edge-beam depth and D/E-bar schedule for both edge conditions.

over_the_side: EdgeBarSpec
parapet: EdgeBarSpec
span_ft: int
civilpy.structural.odot.slab_bridge.LAP_SPLICE_FT = {5: {'bot': 3.6666666666666665, 'top': 3.8333333333333335}, 7: {'bot': 4.416666666666667}, 8: {'bot': 7.25}, 9: {'bot': 8.916666666666666}, 10: {'bot': 10.916666666666666}}

{“top”/”bot”: length_ft}}. No.5 gives both faces; larger sizes are bottom-face laps only (sheet 2).

Type:

Lap splice lengths by bar size, feet

Type:

{size

civilpy.structural.odot.slab_bridge.SLAB_DESIGNS: dict[int, SlabDesign] = {11: SlabDesign(span_ft=11, thickness_in=11.25, a_bar=BarSpec(spacing_in=6, size=7), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5)), 12: SlabDesign(span_ft=12, thickness_in=11.75, a_bar=BarSpec(spacing_in=6, size=7), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5)), 13: SlabDesign(span_ft=13, thickness_in=12.5, a_bar=BarSpec(spacing_in=6, size=7), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5)), 14: SlabDesign(span_ft=14, thickness_in=13.0, a_bar=BarSpec(spacing_in=6, size=7), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5)), 15: SlabDesign(span_ft=15, thickness_in=13.5, a_bar=BarSpec(spacing_in=6, size=7), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5)), 16: SlabDesign(span_ft=16, thickness_in=14.0, a_bar=BarSpec(spacing_in=6, size=7), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5)), 17: SlabDesign(span_ft=17, thickness_in=14.75, a_bar=BarSpec(spacing_in=7, size=8), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5)), 18: SlabDesign(span_ft=18, thickness_in=15.25, a_bar=BarSpec(spacing_in=7, size=8), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5)), 19: SlabDesign(span_ft=19, thickness_in=15.75, a_bar=BarSpec(spacing_in=7, size=8), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5)), 20: SlabDesign(span_ft=20, thickness_in=16.25, a_bar=BarSpec(spacing_in=7, size=8), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5)), 21: SlabDesign(span_ft=21, thickness_in=16.75, a_bar=BarSpec(spacing_in=6, size=8), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5)), 22: SlabDesign(span_ft=22, thickness_in=17.25, a_bar=BarSpec(spacing_in=6, size=8), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5)), 23: SlabDesign(span_ft=23, thickness_in=17.75, a_bar=BarSpec(spacing_in=6, size=8), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5)), 24: SlabDesign(span_ft=24, thickness_in=18.25, a_bar=BarSpec(spacing_in=6, size=8), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5)), 25: SlabDesign(span_ft=25, thickness_in=18.75, a_bar=BarSpec(spacing_in=6, size=8), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5)), 26: SlabDesign(span_ft=26, thickness_in=19.25, a_bar=BarSpec(spacing_in=7, size=9), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5)), 27: SlabDesign(span_ft=27, thickness_in=19.75, a_bar=BarSpec(spacing_in=7, size=9), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5)), 28: SlabDesign(span_ft=28, thickness_in=20.5, a_bar=BarSpec(spacing_in=7, size=9), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5)), 29: SlabDesign(span_ft=29, thickness_in=21.0, a_bar=BarSpec(spacing_in=7, size=9), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5)), 30: SlabDesign(span_ft=30, thickness_in=21.5, a_bar=BarSpec(spacing_in=6, size=9), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5)), 31: SlabDesign(span_ft=31, thickness_in=22.25, a_bar=BarSpec(spacing_in=6, size=9), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5)), 32: SlabDesign(span_ft=32, thickness_in=22.75, a_bar=BarSpec(spacing_in=6, size=9), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5)), 33: SlabDesign(span_ft=33, thickness_in=23.25, a_bar=BarSpec(spacing_in=6, size=9), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5)), 34: SlabDesign(span_ft=34, thickness_in=23.75, a_bar=BarSpec(spacing_in=6, size=9), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5)), 35: SlabDesign(span_ft=35, thickness_in=24.25, a_bar=BarSpec(spacing_in=6, size=9), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5)), 36: SlabDesign(span_ft=36, thickness_in=25.0, a_bar=BarSpec(spacing_in=7, size=10), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5)), 37: SlabDesign(span_ft=37, thickness_in=25.5, a_bar=BarSpec(spacing_in=7, size=10), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5)), 38: SlabDesign(span_ft=38, thickness_in=26.0, a_bar=BarSpec(spacing_in=7, size=10), b_bar=BarSpec(spacing_in=12.0, size=5), m_bar=BarSpec(spacing_in=10.0, size=5), n_bar=BarSpec(spacing_in=12.0, size=5))}

SB-1-24 SLAB DATA, keyed by span (ft). B/M/N bars never vary across spans on this sheet (12 in #5 / 10 in #5 / 12 in #5) – transcribed in full per row anyway, since a future revision could change that.

class civilpy.structural.odot.slab_bridge.SlabBridgeComponent(inp: SlabBridgeInput)[source]

Bases: object

BridgeComponent implementation for a single-span slab bridge (SB-1-24).

calculate_l1_envelope(*, samples: int = 41)[source]

Calculates the L1 equivalent-strip moment envelope for the slab.

This uses the pure-Python girder_line_envelope which applies HL-93 live loads via influence lines and uniform dead loads, scaled by the AASHTO equivalent strip width.

Returns:

(stations, moments) ready for place_splices or results plotting.

Return type:

tuple[list[float], dict[str, list[float]]]

extract_bearing_reactions(model: StructuralModel) dict[source]

Extracts vertical reactions at supports from the StructuralModel results.

geometry() dict[source]

Returns the layout primitives for Rhino/Grasshopper.

reconcile_analysis(midas_results: dict | None = None) dict[source]

Compares pure-Python L1 results with MIDAS results.

If midas_results is provided (e.g. from MidasCivil.beam_forces), it calculates the error/reconciliation between the two models.

structural_model(level: str = 'L1') StructuralModel[source]

Returns a MIDAS-ready StructuralModel (L1 strip or L2 grillage).

class civilpy.structural.odot.slab_bridge.SlabBridgeInput(span_ft: int, width_ft: float, skew_deg: float = 0.0, edge_condition: Literal['over_the_side', 'parapet'] = 'over_the_side')[source]

Bases: object

Inputs for a single-span slab bridge.

edge_condition selects the edge-beam schedule: "over_the_side" (drainage over the fascia) or "parapet" (shallower edge beam under a concrete parapet, per the sheet’s edge-beam option).

edge_condition: Literal['over_the_side', 'parapet'] = 'over_the_side'

"over_the_side" (drainage over the fascia) or "parapet" (shallower edge beam under a parapet).

Type:

Edge-beam schedule

skew_deg: float = 0.0
span_ft: int
width_ft: float
class civilpy.structural.odot.slab_bridge.SlabBridgeLayout(inputs: ~civilpy.structural.odot.slab_bridge.SlabBridgeInput, outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], thickness_in: float, bridge_length_ft: float, bars: tuple[~civilpy.structural.odot.slab_bridge.BarRun, ...], edge_beam: ~civilpy.structural.odot.slab_bridge.EdgeBarSpec, notes: tuple[str, ...] = <factory>)[source]

Bases: object

The generated slab bridge. outline is the skewed plan parallelogram at z = 0 (top of slab); the slab extends down thickness_in. bars are the A/B/M/N longitudinal runs.

bars: tuple[BarRun, ...]
bridge_length_ft: float
edge_beam: EdgeBarSpec
inputs: SlabBridgeInput
notes: tuple[str, ...]
outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
thickness_in: float
class civilpy.structural.odot.slab_bridge.SlabDesign(span_ft: int, thickness_in: float, a_bar: BarSpec, b_bar: BarSpec, m_bar: BarSpec, n_bar: BarSpec)[source]

Bases: object

One SLAB DATA table row (sheet 1).

a_bar: BarSpec
b_bar: BarSpec
m_bar: BarSpec
n_bar: BarSpec
span_ft: int
thickness_in: float
civilpy.structural.odot.slab_bridge.bridge_length_ft(span_ft: float, skew_deg: float = 0.0) float[source]

BRIDGE LENGTH = SPAN + (1.5' / COS(theta)) (sheet 1).

civilpy.structural.odot.slab_bridge.edge_beam_design(span_ft: int) EdgeBeamDesign[source]

Look up the SB-1-24 edge-beam design for a span (feet, 11-38).

Raises ValueError naming the valid spans otherwise.

civilpy.structural.odot.slab_bridge.layout_slab_bridge(inp: SlabBridgeInput) SlabBridgeLayout[source]

Generate a single-span slab bridge: plan outline, thickness, and the A/B/M/N longitudinal bar mats.

Raises ValueError for an untabulated span, an unknown edge_condition, or a skew beyond the sheet’s 25 deg limit.

civilpy.structural.odot.slab_bridge.slab_design(span_ft: int) SlabDesign[source]

Look up the SB-1-24 slab design for a span (feet, 11-38 tabulated).

Raises ValueError naming the valid spans otherwise.

civilpy.structural.odot.slab_bridge.standard_hook_bar_length_ft(span_ft: float) float[source]

A/D/E-bar standard-hook length: span + 10" (the bending-diagram formula shared by all three bar marks).

civilpy.structural.odot.sleeper_slab module

ODOT AS-2-15 Approach Slab Installation — the drawable subset.

Transcribed from Ohio DOT Standard Construction Drawing AS-2-15 (revised 01-20-2023, 14 sheets). The drawing remains the controlling document.

AS-2-15 covers how the AS-1-15 approach slab meets the roadway: the reinforced concrete sleeper slab under the approach-slab/pavement joint (Type A and Type C installations), the 25-foot flexible pavement transition, underdrains, and the joint systems. The sleeper slab is the parametric geometry this module generates; the fourteen installation configurations are cataloged as data (INSTALLATION_INDEX). Type B has no sleeper slab — it uses a reinforced joint mesh measured by the square yard.

Design basis (sheet 14): AASHTO LRFD (2014) + ODOT BDM (2007); HL-93; FWS 0.060 ksf; concrete f’c = 4.5 ksi; fy = 60 ksi. The sleeper slab is measured by the linear foot along the skew at the end of the approach slab and placed parallel to that skew.

Conventions match civilpy.structural.odot.approach_slab: X along stations (increasing away from the bridge), Y transverse, Z up; feet in plan, inches for section dimensions. The layout origin sits on the sleeper slab centerline (directly under the approach-slab/pavement joint) at the y = 0 edge, with z = 0 at the TOP of the sleeper slab.

class civilpy.structural.odot.sleeper_slab.BarRun(mark: str, size: int, points: tuple[tuple[float, float, float], ...])[source]

Bases: object

mark: str
points: tuple[tuple[float, float, float], ...]
size: int
class civilpy.structural.odot.sleeper_slab.Installation(type: str, sheets: tuple[int, ...], wall: str, pavement: str, has_sleeper_slab: bool, joint: str)[source]

Bases: object

One AS-2-15 installation configuration.

has_sleeper_slab: bool
joint: str
pavement: str
sheets: tuple[int, ...]
type: str
wall: str
class civilpy.structural.odot.sleeper_slab.SleeperSlabInput(width_ft: float, skew_deg: float = 0.0, installation: str = 'A')[source]

Bases: object

Inputs for a Type A / Type C sleeper slab: the approach slab width it supports and the skew it parallels.

installation: str = 'A'
skew_deg: float = 0.0
width_ft: float
class civilpy.structural.odot.sleeper_slab.SleeperSlabLayout(inputs: ~civilpy.structural.odot.sleeper_slab.SleeperSlabInput, outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], thickness_in: float, bars: tuple[~civilpy.structural.odot.sleeper_slab.BarRun, ...], underdrain: tuple[tuple[float, float, float], tuple[float, float, float]], pma_joint: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], aggregate_drain: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], measured_length_ft: float, notes: tuple[str, ...] = <factory>)[source]

Bases: object

The generated sleeper slab. outline is the counterclockwise plan parallelogram at z = 0 (top of sleeper); the solid extends down SLEEPER_THICKNESS_IN. underdrain is the pipe centerline; pma_joint is the joint-system outline sitting on the sleeper top over the centerline, and aggregate_drain the trench outline below the slab.

aggregate_drain: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
bars: tuple[BarRun, ...]
inputs: SleeperSlabInput
measured_length_ft: float
notes: tuple[str, ...]
outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
pma_joint: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
thickness_in: float
underdrain: tuple[tuple[float, float, float], tuple[float, float, float]]
civilpy.structural.odot.sleeper_slab.installations(type_: str) tuple[Installation, ...][source]

All cataloged configurations of the given installation type.

civilpy.structural.odot.sleeper_slab.layout_sleeper_slab(inp: SleeperSlabInput) SleeperSlabLayout[source]

Generate the sleeper slab under the approach-slab/pavement joint.

Raises ValueError for a Type B installation (no sleeper slab), an unknown type, or out-of-range width/skew.

civilpy.structural.odot.sleeper_slab.ss501_length_ft(width_ft: float, skew_deg: float = 0.0) float[source]

SS501 length A = (W - 0.5’)/cos(theta) (sheet 1 bending table).

civilpy.structural.odot.sleeper_slab.ss502_count(width_ft: float) int[source]

SS502 bars at 1’-0” max, measured perpendicular to CL roadway, across the (W - 0.5) bar band — spaces rounded up.

civilpy.structural.odot.sleeper_slab.ss502_length_ft(skew_deg: float = 0.0) float[source]

SS502 length B = 7.5’/cos(theta) (sheet 1 bending table).

civilpy.structural.odot.strip_seal_joint module

Ohio DOT strip seal expansion joints for steel stringer structures (EXJ-4-87).

Transcribed from Ohio DOT Standard Bridge Drawing EXJ-4-87, “Strip Seal Expansion Joints, Steel Stringer Structures” (rev. 01-19-2024, 4 sheets). The drawing remains the controlling document.

Like BCHW/CPA-1-08, most of this sheet is a detailing template: the strip-seal gland itself is a manufacturer-generic elastomeric extrusion (not tabulated here), and the joint runs the full skewed width of the structure with project-specific stringer spacing. What is a genuine parametric formula (sheet 1, SECTION C-C) is the support-angle segment length at each stringer, which depends on the stringer top flange width and the skew angle:

a1 = top_flange_width / cos(theta) - 2 * (1” / cos(theta)) - 4” * tan(theta) a2 = 1” + 0.5 * top_flange_width / cos(theta) a3 = 1” + top_flange_width / cos(theta) + 4” * tan(theta) + 1” a4 = a3 - a2

(a1 is the clear gap the support angle must span between plate “A” retainers; a2/a3 lay out the angle relative to the stringer centerline; a4 = a3 - a2 is used directly in Sections B-B/C-C.) These mirror image for a left-forward skew (sheet’s own note).

Conventions match the rest of this package: X along stations, Y transverse, Z up; feet in plan, inches for section dimensions. The origin sits on the joint centerline (X = 0) at the top of deck (Z = 0), Y = 0 at one deck edge.

class civilpy.structural.odot.strip_seal_joint.StripSealJointInput(width_ft: float, skew_deg: float, stringer_stations_ft: tuple[float, ...], top_flange_width_in: float = 12.0)[source]

Bases: object

Inputs for one strip seal joint run.

stringer_stations_ft are the transverse stringer positions (Y, ft) across the deck width; top_flange_width_in is the (uniform, assumed) stringer top flange width used in the support-angle formulas.

skew_deg: float
stringer_stations_ft: tuple[float, ...]
top_flange_width_in: float = 12.0
width_ft: float
class civilpy.structural.odot.strip_seal_joint.StripSealJointLayout(inputs: ~civilpy.structural.odot.strip_seal_joint.StripSealJointInput, joint_line: tuple[tuple[float, float, float], tuple[float, float, float]], support_angles: tuple[~civilpy.structural.odot.strip_seal_joint.SupportAngleRun, ...], notes: tuple[str, ...] = <factory>)[source]

Bases: object

The generated joint: joint_line is the skewed gland centerline across the full deck width (z = 0, top of deck); support_angles is one short transverse segment per stringer station, sized by support_angle_lengths_in().

inputs: StripSealJointInput
joint_line: tuple[tuple[float, float, float], tuple[float, float, float]]
notes: tuple[str, ...]
support_angles: tuple[SupportAngleRun, ...]
class civilpy.structural.odot.strip_seal_joint.SupportAngleRun(station_ft: float, points: tuple[tuple[float, float, float], tuple[float, float, float]], a1_in: float, a2_in: float, a3_in: float, a4_in: float)[source]

Bases: object

a1_in: float
a2_in: float
a3_in: float
a4_in: float
points: tuple[tuple[float, float, float], tuple[float, float, float]]
station_ft: float
civilpy.structural.odot.strip_seal_joint.layout_strip_seal_joint(inp: StripSealJointInput) StripSealJointLayout[source]

Generate a strip seal joint: the skewed joint line and one support-angle run per stringer station.

Raises ValueError for a non-positive width or an empty stringer_stations_ft.

civilpy.structural.odot.strip_seal_joint.support_angle_lengths_in(top_flange_width_in: float, skew_deg: float) tuple[float, float, float, float][source]

The a1/a2/a3/a4 support-angle formulas (sheet 1, SECTION C-C).

Returns (a1, a2, a3, a4) in inches; mirror the sign convention for a left-forward skew per the sheet’s own note (use the same magnitude, mirrored in plan by the caller).

civilpy.structural.odot.strip_seal_joint_box_beam module

Ohio DOT strip seal expansion joints for concrete box beam structures (EXJ-5-93).

Transcribed from Ohio DOT Standard Bridge Drawing EXJ-5-93, “Strip Seal Expansion Joints, Concrete Box Beam Structures” (rev. 01-19-2024, 4 sheets). The drawing remains the controlling document. Same pattern as EXJ-4-87 (civilpy.structural.odot.strip_seal_joint) but for box beams instead of steel stringers: the strip-seal gland is again manufacturer-generic, and the joint runs the skewed width of the structure. What’s cataloged here is the plate “A”/”B”/”C” spacing table (keyed by beam width, END OF SUPERSTRUCTURE detail) and the joint-length formula (sheet 1’s own “LEGEND”):

L = [(N - 1) * (1/2) + N * W] / (12 * cos(theta))

L is the joint length edge-to-edge of deck (ft), N the number of beams, W the nominal beam width (inches, 36 or 48), theta the joint skew angle. The plates repeat A-B-B-C-B-B-C-… across the joint width, one A/B/C group per beam-to-beam gap (see the sheet’s “PLATE ‘A’ SPACING” callout row).

Conventions match the rest of this package: X along stations, Y transverse, Z up; feet in plan, inches for section dimensions. The origin sits on the joint centerline (X = 0) at the top of deck (Z = 0), Y = 0 at one deck edge.

class civilpy.structural.odot.strip_seal_joint_box_beam.BoxBeamJointInput(n_beams: int, beam_width_in: float, skew_deg: float = 0.0)[source]

Bases: object

beam_width_in: float
n_beams: int
skew_deg: float = 0.0
class civilpy.structural.odot.strip_seal_joint_box_beam.BoxBeamJointLayout(inputs: ~civilpy.structural.odot.strip_seal_joint_box_beam.BoxBeamJointInput, joint_line: tuple[tuple[float, float, float], tuple[float, float, float]], length_ft: float, beam_gap_stations_ft: tuple[float, ...], spacing: ~civilpy.structural.odot.strip_seal_joint_box_beam.PlateSpacing, notes: tuple[str, ...] = <factory>)[source]

Bases: object

The generated joint: joint_line is the skewed gland centerline across the full deck width (z = 0, top of deck); beam_gap_stations are the transverse (Y) positions of each beam-to-beam gap, where a plate “A”/”B”/”C” group sits.

beam_gap_stations_ft: tuple[float, ...]
inputs: BoxBeamJointInput
joint_line: tuple[tuple[float, float, float], tuple[float, float, float]]
length_ft: float
notes: tuple[str, ...]
spacing: PlateSpacing
civilpy.structural.odot.strip_seal_joint_box_beam.PLATE_SPACING: dict[float, PlateSpacing] = {36.0: PlateSpacing(beam_width_in=36.0, dim_a_in=6.0, dim_b_in=12.25, dim_c_in=12.0), 48.0: PlateSpacing(beam_width_in=48.0, dim_a_in=8.0, dim_b_in=16.25, dim_c_in=16.0)}

EXJ-5-93 plate “A”/”B”/”C” spacing table, keyed by beam width (inches).

class civilpy.structural.odot.strip_seal_joint_box_beam.PlateSpacing(beam_width_in: float, dim_a_in: float, dim_b_in: float, dim_c_in: float)[source]

Bases: object

beam_width_in: float
dim_a_in: float
dim_b_in: float
dim_c_in: float
civilpy.structural.odot.strip_seal_joint_box_beam.joint_length_ft(n_beams: int, beam_width_in: float, skew_deg: float = 0.0) float[source]

L = [(N-1)*(1/2) + N*W] / (12*cos(theta)) (sheet 1’s LEGEND): joint length edge-to-edge of deck, feet.

civilpy.structural.odot.strip_seal_joint_box_beam.layout_box_beam_joint(inp: BoxBeamJointInput) BoxBeamJointLayout[source]

Generate a box-beam strip seal joint: the skewed joint line and the beam-to-beam gap stations where plate “A”/”B”/”C” groups sit.

Raises ValueError for fewer than 2 beams or an untabulated beam width (plate_spacing()).

civilpy.structural.odot.strip_seal_joint_box_beam.plate_spacing(beam_width_in: float) PlateSpacing[source]

Look up the EXJ-5-93 plate spacing for a beam width (36 or 48 in).

Raises ValueError naming the valid widths otherwise.

civilpy.structural.odot.typical_abutment module

Ohio DOT typical abutment detail for bridges with expansion joints (A-1-20).

Transcribed from Ohio DOT Standard Bridge Drawing A-1-20, “Typical Abutment Detail for Bridges with Expansion Joints” (rev. 01-19-2024, 5 sheets). The drawing remains the controlling document. Steel girders are shown; PSID-1-13 covers the modifications for prestressed concrete I-beams.

This sheet is explicitly guidance, not a standalone standard (General note, sheet 1, verbatim): “Treat the abutment dimensions, construction joints and reinforcing shown in this drawing as MINIMUM VALUES and perform a complete design for the abutment. Do not reference these drawings in the contract plans and do not use as standalone construction drawings.” That is a stronger disclaimer than BCHW/CPA-1-08’s “insert design here” blanks – every dimension here is a floor, not a value to build to, and this module’s layout_typical_abutment should be read the same way: a reasonable visual check, never a substitute for the abutment design.

What’s fixed: two literal formulas (the bearing-seat dimension and the wingwall unsupported-length limit) plus a handful of section minimums (cover, bar spacing, backwall/footing minimum widths). Concrete f’c = 4.0 ksi, reinforcing steel min. yield 60 ksi; bars are #5 unless noted.

Conventions match the rest of this package: X along stations, Y transverse, Z up; feet in plan, inches for section dimensions. The origin sits on the abutment centerline at the low beam seat elevation (Z = 0), Y = 0 at the backwall centerline.

class civilpy.structural.odot.typical_abutment.AbutmentInput(width_ft: float, skew_deg: float, wingwall_length_ft: float, footing_depth_ft: float, backwall_height_ft: float)[source]

Bases: object

Project-supplied dimensions for a typical (girder-bridge) abutment.

wingwall_length_ft should not exceed WINGWALL_UNSUPPORTED_MAX_FT without an extended footing (the sheet’s own limit, not enforced here since “extend the footing” is itself a valid design response, not a hard cap on the wingwall).

backwall_height_ft: float
footing_depth_ft: float
skew_deg: float
width_ft: float
wingwall_length_ft: float
class civilpy.structural.odot.typical_abutment.AbutmentLayout(inputs: ~civilpy.structural.odot.typical_abutment.AbutmentInput, backwall_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], footing_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], wingwall_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], dim_a_ft: float, notes: tuple[str, ...] = <factory>)[source]

Bases: object

The generated abutment. backwall_outline is the backwall’s plan footprint (top of footing, z = 0) extending up backwall_height_ft; footing_outline is the footing plan rectangle (extending down footing_depth_ft); wingwall_outline is one flared wingwall plane, per WINGWALL_MIN_HEIGHT_FT.

backwall_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
dim_a_ft: float
footing_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
inputs: AbutmentInput
notes: tuple[str, ...]
wingwall_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
civilpy.structural.odot.typical_abutment.bearing_seat_dim_a_ft(skew_deg: float = 0.0) float[source]

DIM. A = 2'-0" / COS(skew) (sheet 2’s skewed part-plan).

civilpy.structural.odot.typical_abutment.layout_typical_abutment(inp: AbutmentInput) AbutmentLayout[source]

Generate a typical abutment backwall + footing + one flared wingwall from fully project-supplied dimensions.

Raises ValueError for a non-positive width/wingwall length/footing depth/backwall height.

civilpy.structural.odot.vandal_fence module

Ohio DOT vandal protection fence (VPF-1-24).

Transcribed from Ohio DOT Standard Bridge Drawing VPF-1-24, “Vandal Protection Fence” (rev. 01-17-2025, 6 sheets). The drawing remains the controlling document.

Mostly a materials/hardware specification (posts, rails, fabric, tension wire, fittings, base plates, anchors – General Notes 1-25) rather than a dimensioned standard; the one genuine geometric table is the three post sections (sheet 2), each pairing a post type with its base plate and maximum spacing. The designer specifies which post type/base plate to use and the actual post spacing on a project’s own schematic deck plan (sheet 1, note 25).

Conventions match the rest of this package: X along the fence run, Y transverse (fixed at the railing face), Z up; feet in plan. The origin sits at the first post, z = 0 at the base plate.

class civilpy.structural.odot.vandal_fence.FenceRunInput(length_ft: 'float', post_name: 'str' = 'PS-2/BP-1', spacing_ft: 'float | None' = None)[source]

Bases: object

length_ft: float
post_name: str = 'PS-2/BP-1'
spacing_ft: float | None = None
class civilpy.structural.odot.vandal_fence.FenceRunLayout(inputs: ~civilpy.structural.odot.vandal_fence.FenceRunInput, section: ~civilpy.structural.odot.vandal_fence.PostSection, post_stations_ft: tuple[float, ...], top_rail: tuple[tuple[float, float, float], tuple[float, float, float]], bottom_rail: tuple[tuple[float, float, float], tuple[float, float, float]], notes: tuple[str, ...] = <factory>)[source]

Bases: object

The generated fence run: post_stations_ft are evenly-spaced post positions along the run (never exceeding the section’s max spacing); top_rail/bottom_rail are the rail lines at post height / base.

bottom_rail: tuple[tuple[float, float, float], tuple[float, float, float]]
inputs: FenceRunInput
notes: tuple[str, ...]
post_stations_ft: tuple[float, ...]
section: PostSection
top_rail: tuple[tuple[float, float, float], tuple[float, float, float]]
civilpy.structural.odot.vandal_fence.POST_SECTIONS: dict[str, PostSection] = {'PS-1': PostSection(name='PS-1', base_plate='BP-3', height_ft=9.989583333333334, max_spacing_ft=7.0, curved=True, curve_radius_ft=2.6666666666666665, note='12 ft curved fence; extends over a steel railing on a concrete barrier'), 'PS-2/BP-1': PostSection(name='PS-2', base_plate='BP-1', height_ft=6.0, max_spacing_ft=10.0, curved=False, curve_radius_ft=None, note='6 ft straight fence on single slope railing'), 'PS-2/BP-2': PostSection(name='PS-2', base_plate='BP-2', height_ft=6.0, max_spacing_ft=5.0, curved=False, curve_radius_ft=None, note='6 ft straight fence on deflector railing (closer spacing)')}

VPF-1-24 post sections, keyed by name.

class civilpy.structural.odot.vandal_fence.PostSection(name: str, base_plate: str, height_ft: float, max_spacing_ft: float, curved: bool = False, curve_radius_ft: float | None = None, note: str = '')[source]

Bases: object

One VPF-1-24 post section (sheet 2).

base_plate: str
curve_radius_ft: float | None = None
curved: bool = False
height_ft: float
max_spacing_ft: float
name: str
note: str = ''
civilpy.structural.odot.vandal_fence.layout_fence_run(inp: FenceRunInput) FenceRunLayout[source]

Generate a fence run: evenly-spaced posts (spacing never exceeding the section’s tabulated maximum) plus top/bottom rail lines.

Raises ValueError for a non-positive length or an unknown post section name.

civilpy.structural.odot.vandal_fence.post_section(name: str) PostSection[source]

Look up a VPF-1-24 post section (“PS-1”, “PS-2/BP-1”, “PS-2/BP-2”).

Raises ValueError naming the valid names otherwise.

Module contents

Catalog of Ohio DOT Standard Construction Drawings (SCDs).

This package transcribes the geometry, reinforcement, and design data published on Ohio Department of Transportation standard bridge and roadway drawings into structured, queryable Python objects. Each catalog entry cites its SCD number and revision date; the underlying drawings are public-domain Ohio DOT documents.

Sub-modules:

bridge_railing

Bridge railings and barriers (BR, SBR, TST, DBR, TBR, PCB series), each carrying its NCHRP 350 / MASH crash test level so it links to the Table A13.2-1 design forces in civilpy.structural.aashto.lrfd.

guardrail

Midwest Guardrail System (MGS) roadway drawings: the standard system parameters (height, post spacing, blockouts, post sections) plus the series registry and the bridge terminal assemblies that tie a guardrail run into the cataloged bridge railings.

box_beam

Prestressed concrete box beam construction details (PSBD-1-25): tie rods, anchor dowels, shear keys, diaphragm placement rules, and the standard elastomeric bearing pads.

box_beam_design

Prestressed box beam standard designs and LRFR load ratings (PSBDD-1-25): strand patterns, eccentricities, camber, and rating factors for the composite (CB) and non-composite (B) families at five depths.

deck_design

ODOT BDM 309.3 reinforced concrete deck design: the minimum-thickness formula, the mandatory design policy (LRFD 9.7.3 strip method, HL-93), and the BDM Figure 309-3 standard deck designs by effective span.

rocker_bolster

Structural steel rocker and bolster bearing dimensions and capacities (RB-1-55), plus layout_rocker_bolster: the shared base plate, the bolster’s flat-top tapered body, and the rocker’s curved-top body (TOP BEARING DETAIL radius formula) behind the RB-1-55 component.

headwall

Cast-in-place half-height headwall dimension tables (HW-2.1 corrugated- metal/plastic, HW-2.2 concrete) plus the layout_headwall generator behind the HW-2.1 Grasshopper component: the rectangular circular-pipe headwall solid (end treatment “A”), battered back face, pipe opening.

approach_slab

Reinforced concrete approach slab (AS-1-15): the reinforcing steel table, bar count/length formulas, seat and joint details, and the pure-Python layout generator behind the AS-1-15 Grasshopper component.

drip_strip

Stainless steel drip strips for over-the-side drainage (DS-1-92): section profile, perforation pattern, railing-dependent placement, and the fascia run generator behind the DS-1-92 component.

portable_barrier

Portable concrete barrier geometry (PCB-91): the New Jersey shape section, segment/joint/anchor layout behind the PCB-91 component (crash test levels stay in bridge_railing).

sleeper_slab

Approach slab installation / sleeper slab (AS-2-15): the Type A/C reinforced concrete sleeper slab under the approach-slab/pavement joint, its SS501/SS502 reinforcement, underdrain and joint layout, and the installation-type catalog (Type B has no sleeper slab).

full_height_headwall

Full-height headwalls with wingwalls (HW-1.1): the pipe-diameter x skew-angle dimension/quantity table (0-84 in, skew 0-45 deg) and the layout_full_height_headwall generator behind the HW-1.1 component – Type A symmetric and Type B asymmetric (skewed) wingwalls.

box_culvert_headwall

Precast box culvert headwall/wingwall plan insert (BCHW): a detailing template rather than a dimensioned standard, so layout_wingwall takes every dimension as a project-supplied input; also catalogs the general notes (payment items, waterproofing, weepholes, PEJF, lap splices) and the eight standard rebar bend shapes (bend_shape, TYPE-1..``TYPE-8``) the bar list references.

slab_bridge

Single span slab bridges (SB-1-24): the span-keyed SLAB DATA table (thickness + A/B/M/N bar schedule, 11-38 ft) and EDGE BEAM SLAB DATA table (over-the-side-drainage vs. parapet edge conditions), and the layout_slab_bridge generator behind the SB-1-24 component.

capped_pile_abutment

Capped pile abutment for slab bridges (CPA-1-08), SB-1-24’s companion: fixed section constants, the reinforcing bend legend (bend_shape, Types 1-5; Type 6/D801 is approach_slab’s bar), and layout_capped_pile_abutment – another detailing-template sheet (like BCHW) whose overall dimensions are project-supplied.

capped_pile_pier

Capped pile pier for continuous slab bridges (CPP-1-08), CS-1-24’s companion: the sheet’s own pier-length formula (pier_length_ft), fixed cap width/end-radius, the P501-P504 bar bend data, and layout_capped_pile_pier – unlike the other capped-pile-cap sheets, this one is genuinely parametric (no blank “insert design here”), only pile count/spacing stay project-supplied.

continuous_slab_bridge

Three-span continuous slab bridges (CS-1-24), SB-1-24’s continuous sibling: the end-span-keyed SLAB DATA table (thickness + A/B bottom, C/D top, E top-at-pier bar schedule, 14-46 ft – the largest table in the SCD program, 779 numeric entries), the fixed 1.25x interior-span ratio, and layout_continuous_slab.

typical_abutment

Typical abutment detail for girder bridges with expansion joints (A-1-20): explicitly guidance/minimum-values, not a standalone standard (see the module docstring). The bearing-seat and wingwall-limit formulas, section minimums, and layout_typical_abutment for a visual check only.

fixed_bearing

Fixed (pin) bearings for steel beam and girder bridges (FB-1-82): the F-50..F-400 dimension/capacity table and layout_fixed_bearing (masonry plate + bearing pin + top plate) behind the FB-1-82 component.

strip_seal_joint

Strip seal expansion joints, steel stringer structures (EXJ-4-87): the support-angle length formulas (a1-a4, skew-dependent) and layout_strip_seal_joint – the gland itself is manufacturer- generic and not modeled.

strip_seal_joint_box_beam

Strip seal expansion joints, concrete box beam structures (EXJ-5-93): the plate “A”/”B”/”C” spacing table (36/48 in beams), the joint- length formula, and layout_box_beam_joint.

class civilpy.structural.odot.AbutmentInput(wingwall_length_ft: float, skew_deg: float, n_piles: int, pile_spacing_ft: float, footing_depth_ft: float, cap_width_ft: float = 3.0)[source]

Bases: object

Project-supplied dimensions for one capped pile abutment.

wingwall_length_ft is the “W” dimension (Section B-B/F-F); n_piles/pile_spacing_ft lay out the cap’s pile line; footing_depth_ft is the cap/footing depth below the bridge seat. Nothing here is cataloged – see the module docstring.

cap_width_ft: float = 3.0
footing_depth_ft: float
n_piles: int
pile_spacing_ft: float
skew_deg: float
wingwall_length_ft: float
class civilpy.structural.odot.AbutmentLayout(inputs: ~civilpy.structural.odot.capped_pile_abutment.AbutmentInput, cap_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], pile_points: tuple[tuple[float, float, float], ...], wingwall_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], notes: tuple[str, ...] = <factory>)[source]

Bases: object

The generated abutment. cap_outline is the cap’s plan footprint (top of cap, z = 0, the bridge seat) extending down footing_depth_ft; pile_points are the pile centerlines along the cap; wingwall_outline is one flared wingwall plane (mirrors layout_full_height_headwall()’s convention).

cap_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
inputs: AbutmentInput
notes: tuple[str, ...]
pile_points: tuple[tuple[float, float, float], ...]
structural_model(reaction: float = 0.0) StructuralModel[source]

Returns a MIDAS-ready StructuralModel of the abutment cap as a beam.

wingwall_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
class civilpy.structural.odot.AnchorDowelDetail(diameter: float = 1.0, beam_hole_diameter: float = 2.0, beam_hole_diameter_compression_seal: float = 2.5, fixed_substructure_hole_min: float = 1.0625, expansion_substructure_hole_min: float = 1.25)[source]

Bases: object

Anchor dowel details (PSBD-1-25 sheets 1 & 5).

beam_hole_diameter: float = 2.0
beam_hole_diameter_compression_seal: float = 2.5
diameter: float = 1.0
expansion_substructure_hole_min: float = 1.25
fixed_substructure_hole_min: float = 1.0625
class civilpy.structural.odot.ApproachSlabDesign(length_ft: float, thickness_in: float, a_bar_spacing_in: float, a_bar_mark: str, a_bar_length_ft: float, a_bar_dimension_ft: float, b501_bottom_spacing_in: float, b501_bottom_count: int, b501_top_count: int, c_bar_mark: str, c_bar_length_ft: float)[source]

Bases: object

One row of the AS-1-15 reinforcing steel table.

Lengths in feet, spacings/thicknesses in inches. Bar counts that depend on the slab width W are computed by the module-level functions, matching the tabulated formulas (e.g. 12(W-0.5)/K + 1).

a_bar_dimension_ft: float
a_bar_length_ft: float
a_bar_mark: str
a_bar_spacing_in: float
b501_bottom_count: int
b501_bottom_spacing_in: float
b501_top_count: int
c_bar_length_ft: float
c_bar_mark: str
length_ft: float
thickness_in: float
class civilpy.structural.odot.ApproachSlabInput(length_ft: float, width_ft: float, skew_deg: float = 0.0, end_thickness_in: float | None = None, seat_length_in: float = 9.0, backwall_thickness_in: float = 14.0)[source]

Bases: object

The design choices an engineer makes on the project plans.

length_ft must be one of the tabulated L values. width_ft is the approach slab width W per the sheet’s width-dimension figure (out-to-out without curbs, toe-to-toe of curbs, or toe-to-toe of barrier). end_thickness_in is X (thickness at the abutment end); the sheet requires X >= T and expresses X in feet in its formulas. seat_length_in is the bearing length on the seat/backwall (6 in to 1’-0” per section B-B). backwall_thickness_in selects the anchor bar (D801 needs >= 14 in; D802 covers the 11 in PS box beam case).

backwall_thickness_in: float = 14.0
end_thickness_in: float | None = None
length_ft: float
seat_length_in: float = 9.0
skew_deg: float = 0.0
width_ft: float
class civilpy.structural.odot.ApproachSlabLayout(inputs: ~civilpy.structural.odot.approach_slab.ApproachSlabInput, design: ~civilpy.structural.odot.approach_slab.ApproachSlabDesign, outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], profile: tuple[tuple[float, float], ...], bars: tuple[~civilpy.structural.odot.approach_slab.BarRun, ...], anchor_mark: str, anchor_length_ft: float, pay_area_sy: float, notes: tuple[str, ...] = <factory>)[source]

Bases: object

Everything the Grasshopper component draws.

outline is the counterclockwise plan parallelogram at z = 0 (top of slab), starting at the bridge-limit / y = 0 corner. profile is the longitudinal section polyline in (u, z) feet, u measured from the bridge limit along the roadway; it is swept transversely (with the skew shear) to form the solid.

anchor_length_ft: float
anchor_mark: str
bars: tuple[BarRun, ...]
design: ApproachSlabDesign
inputs: ApproachSlabInput
notes: tuple[str, ...]
outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
pay_area_sy: float
profile: tuple[tuple[float, float], ...]
class civilpy.structural.odot.BarMat(size: int, spacing: float)[source]

Bases: object

One reinforcing mat: bar size at a uniform spacing (in).

property area_per_ft: float

Provided steel area (in^2/ft of deck).

size: int
spacing: float
class civilpy.structural.odot.BarrierEndSection(scd: str, scd_date: str, designation: str, parent: str, total_length_ft: float, body_length_ft: float, face_transition_ft: float, vertical_run_in: float, end_taper_in: float, end_height_in: float, end_width_in: float, end_core_width_in: float, median: bool = True, notes: str = '')[source]

Bases: object

One RM-4.6 cast-in-place concrete barrier end section.

Steps the parent single-slope barrier down to a 32 in tall, vertical-faced end that a Bridge Terminal Assembly (SCD MGS-3.1/3.2/ 3.3, Item 606) or impact attenuator attaches to; the single-slope faces transition to vertical over 10 ft to prevent snagging, and the concrete end carries a 4:1 plan flare over the last 16 in. Paid as Item 622 “Concrete Barrier End Section, Type _”, Each.

body_length_ft: float

Full parent-profile run before the face transition, ft (the Type B1 body also tapers 57 -> 42 in tall across it).

designation: str
end_core_width_in: float

vertical-faced core between curbs

end_height_in: float
end_taper_in: float

1 concrete end flare

Type:

4

end_width_in: float

overall width across the curbs

face_transition_ft: float

vertical-face transition length

median: bool = True

median (two-sided) vs roadside

notes: str = ''
parent: str

RM-4.3 / RM-4.5 barrier designation

scd: str
scd_date: str
total_length_ft: float
vertical_run_in: float

full-height vertical-face run

class civilpy.structural.odot.BarrierEndSectionLayout(end_section: BarrierEndSection, stations: tuple[tuple[float, tuple[tuple[float, float], ...]], ...], notes: tuple[str, ...] = ())[source]

Bases: object

Stationed cross-sections of an RM-4.6 end section, ready to loft.

stations is a tuple of (station_ft, profile) pairs from the parent-barrier joint (station 0) to the end; each profile is a closed (offset_in, z_in) loop in the roadway-barrier convention. The 4:1 plan end flare inside the last 16 in is described in notes rather than drawn (it rounds the very end plan corners).

end_section: BarrierEndSection
notes: tuple[str, ...] = ()
stations: tuple[tuple[float, tuple[tuple[float, float], ...]], ...]
class civilpy.structural.odot.BarrierSegment(index: int, start_ft: float, end_ft: float)[source]

Bases: object

One placed segment: stations (ft) along the run.

end_ft: float
index: int
property length_ft: float
start_ft: float
class civilpy.structural.odot.BarrierTransitionLayout(barrier: RoadwayBarrier, kind: str, obstruction_width_in: float, stations: tuple[tuple[float, float], ...], total_length_ft: float, notes: tuple[str, ...] = ())[source]

Bases: object

Plan-view widening of an RM-4.4 single-slope barrier transition.

stations is a tuple of (station_ft, width_in) pairs of the barrier’s overall plan width from the start of the first taper; the cross-section at any station keeps the parent barrier’s height and 5.25:1 faces with the extra width filled solid between them.

barrier: RoadwayBarrier
kind: str
notes: tuple[str, ...] = ()
obstruction_width_in: float
stations: tuple[tuple[float, float], ...]
total_length_ft: float
class civilpy.structural.odot.BearingDesignData(durometer: int = 50, allowable_compressive_stress: float = 1.25, shear_modulus_compressive: float = 0.095, shear_modulus_horizontal: float = 0.13, creep_deflection_percent: float = 25.0, bearings_per_beam: int = 4, spec_edition: str = 'AASHTO LRFD BDS 10th Edition (2024)')[source]

Bases: object

Elastomeric bearing design data (PSBD-1-25 sheet 6/6).

allowable_compressive_stress: float = 1.25

Allowable compressive stress, ksi.

bearings_per_beam: int = 4

Bearings required per beam.

creep_deflection_percent: float = 25.0

25-year creep deflection / instantaneous deflection, percent.

durometer: int = 50
shear_modulus_compressive: float = 0.095

Shear modulus at 73 F for maximum compressive strength, ksi.

shear_modulus_horizontal: float = 0.13

Shear modulus at 73 F for horizontal forces, ksi.

spec_edition: str = 'AASHTO LRFD BDS 10th Edition (2024)'

Governing spec edition.

class civilpy.structural.odot.BearingPad(name: str, length: float, width: float, total_thickness: float, t_external: float, t_internal: float, t_steel: float, n_laminates: int, max_total_load: float, max_expansion_length: float, max_movement: float, rotation_capacity: float = 0.024)[source]

Bases: object

A standard steel-reinforced elastomeric bearing pad (PSBD-1-25 sheet 6/6 table). Lengths in inches, load in kips, expansion length in feet.

length: float
max_expansion_length: float
max_movement: float
max_total_load: float
n_laminates: int
name: str
rotation_capacity: float = 0.024
t_external: float
t_internal: float
t_steel: float
total_thickness: float
width: float
class civilpy.structural.odot.BeveledLoadPlate(min_thickness: float = 1.5, plate_grade: str = 'ASTM A709 Gr 50', anchor_rod_diameter: float = 0.75, plate_washer: str = '3 x 3 x 1/2', expansion_anchor_hole: float = 1.25, stud_yield: float = 50.0)[source]

Bases: object

Beveled steel load plate detail (BD-1-11).

anchor_rod_diameter: float = 0.75
expansion_anchor_hole: float = 1.25
min_thickness: float = 1.5
plate_grade: str = 'ASTM A709 Gr 50'
plate_washer: str = '3 x 3 x 1/2'
stud_yield: float = 50.0
class civilpy.structural.odot.BikewayRailingInput(length_ft: float, flared_ends: bool = True, low_shoulder: bool = False)[source]

Bases: object

One straight bikeway railing run. length_ft is the fence length between flares (as shown on plans); flared ends add FLARED_END_LENGTH_FT each when flared_ends.

flared_ends: bool = True
length_ft: float
low_shoulder: bool = False

< 1 ft graded shoulder (note 4)

class civilpy.structural.odot.BikewayRailingLayout(inputs: BikewayRailingInput, post_stations_ft: tuple[float, ...], midspan_stations_ft: tuple[float, ...], post_length_in: float, embedment_in: float, n_rail_pieces: int, total_length_ft: float, notes: tuple[str, ...] = ())[source]

Bases: object

Members of one bikeway railing run.

post_stations_ft are full-post centers from the run start; midspan_stations_ft the 18 in rail-stiffener posts centered in each bay. Rails run the full length in <= 20 ft pieces butt- jointed on posts (top rail and lower face rail staggered to alternate posts, note 6).

embedment_in: float
inputs: BikewayRailingInput
midspan_stations_ft: tuple[float, ...]
n_rail_pieces: int
notes: tuple[str, ...] = ()
post_length_in: float
post_stations_ft: tuple[float, ...]
total_length_ft: float
class civilpy.structural.odot.BoxBeamDesign(beam_type: str, box: str, depth: int, width: int, span: int, e_beam: float, e_composite: float | None, n_strands: int, strands_2in: int, strands_4in: int, strands_6in: int, stirrup_w_pairs: int, stirrup_zone_x: float, stirrup_y: float, stirrup_z: float, camber_d0: float, camber_d30: float, deflection: float, bearing_type: str)[source]

Bases: object

One standard box-beam design line (PSBDD-1-25 sheets 1 & 3).

e_composite is None for non-composite beams. strands_2in / strands_4in / strands_6in are the strand counts in the rows 2, 4, and 6 in above the soffit (their sum is n_strands). Camber values are at release (camber_d0) and erection (camber_d30); deflection is the residual midspan deflection under remaining dead load. All lengths in inches.

beam_type: str
bearing_type: str
box: str
camber_d0: float
camber_d30: float
deflection: float
depth: int
e_beam: float
e_composite: float | None
n_strands: int
span: int
stirrup_w_pairs: int
stirrup_y: float
stirrup_z: float
stirrup_zone_x: float
strands_2in: int
strands_4in: int
strands_6in: int
width: int
class civilpy.structural.odot.BoxBeamDesignSpec(fc_28day_range: tuple[float, float] = (5.5, 7.0), fci_release_range: tuple[float, float] = (4.0, 5.0), fc_cast_in_place: float = 4.5, fy_reinforcing: float = 60.0, strand_grade: int = 270, strand_diameter: float = 0.5, strand_area_options: tuple[float, ...] = (0.153, 0.167))[source]

Bases: object

Design-stress and material specifications (PSBD-1-25 sheet 1/6).

Concrete strengths are designer-selected ranges; the strand and reinforcing values are fixed by the standard. Stresses in ksi.

fc_28day_range: tuple[float, float] = (5.5, 7.0)

Designer-selected 28-day concrete strength range, ksi.

fc_cast_in_place: float = 4.5

Cast-in-place (composite topping) concrete strength, ksi.

fci_release_range: tuple[float, float] = (4.0, 5.0)

Designer-selected release strength range, ksi.

fy_reinforcing: float = 60.0

Reinforcing steel minimum yield, ksi (C&MS 709.00).

strand_area_options: tuple[float, ...] = (0.153, 0.167)

Nominal strand cross-sectional area options, in^2.

strand_diameter: float = 0.5

Strand diameter, inches (0.5 in, 7-wire low-relaxation).

strand_grade: int = 270

Prestressing strand grade (ASTM A416, C&MS 711.27).

class civilpy.structural.odot.BoxBeamJointInput(n_beams: int, beam_width_in: float, skew_deg: float = 0.0)[source]

Bases: object

beam_width_in: float
n_beams: int
skew_deg: float = 0.0
class civilpy.structural.odot.BoxBeamJointLayout(inputs: ~civilpy.structural.odot.strip_seal_joint_box_beam.BoxBeamJointInput, joint_line: tuple[tuple[float, float, float], tuple[float, float, float]], length_ft: float, beam_gap_stations_ft: tuple[float, ...], spacing: ~civilpy.structural.odot.strip_seal_joint_box_beam.PlateSpacing, notes: tuple[str, ...] = <factory>)[source]

Bases: object

The generated joint: joint_line is the skewed gland centerline across the full deck width (z = 0, top of deck); beam_gap_stations are the transverse (Y) positions of each beam-to-beam gap, where a plate “A”/”B”/”C” group sits.

beam_gap_stations_ft: tuple[float, ...]
inputs: BoxBeamJointInput
joint_line: tuple[tuple[float, float, float], tuple[float, float, float]]
length_ft: float
notes: tuple[str, ...]
spacing: PlateSpacing
class civilpy.structural.odot.BoxBeamRating(beam_type: str, box: str, width_ft: int, n_beams: int, span: int, rating_factors: dict[str, float]=<factory>)[source]

Bases: object

LRFR rating factors for one box / span / bridge width (PSBDD-1-25 sheets 2 & 4). rating_factors is keyed by RATING_VEHICLES.

beam_type: str
box: str
property inventory: float

HL-93 inventory rating factor.

n_beams: int
property operating: float

HL-93 operating rating factor.

rating_factors: dict[str, float]
span: int
width_ft: int
class civilpy.structural.odot.BoxSectionProperties(depth: int, width: float = 48.0, area: float = 0.0, i: float = 0.0, yb: float = 0.0, zt: float = 0.0, zb: float = 0.0, ic: float = 0.0, ybc: float = 0.0, ztc: float = 0.0, zbc: float = 0.0)[source]

Bases: object

Non-composite (“beam only”) and composite section properties for one standard box-beam depth (PSBD-1-25 sheet 4/6 tables). Lengths in inches; area in in^2, i/ic in in^4, zt/zb/ztc/zbc in in^3. The composite values assume the standard COMPOSITE_SLAB_STRUCTURAL_THICKNESS_IN topping at COMPOSITE_MODULAR_RATIO; they apply to any beam of this depth when a CIP composite slab is cast, independent of which design table (composite vs. non-composite strand pattern) governs the beam itself.

area: float = 0.0
depth: int
i: float = 0.0
ic: float = 0.0
width: float = 48.0
yb: float = 0.0
ybc: float = 0.0
zb: float = 0.0
zbc: float = 0.0
zt: float = 0.0
ztc: float = 0.0
class civilpy.structural.odot.BridgeRailing(scd: str, scd_date: str, designation: str, name: str, shape: str, material: str, test_level: str, height: float | None = None, base_width: float | None = None, top_width: float | None = None, section_area: float | None = None, f_c: float | None = None, f_y: float | None = None, vertical_bar_spacing: float | None = None, bar_sizes: tuple[int, ...] = (), transition_length_ft: float | None = None, transition_volume_cy: float | None = None, post_shape: str = '', post_spacing: float | None = None, rail_element: str = '', f_y_steel: float | None = None, weight_per_ft: float | None = None, segment_length_ft: tuple[float, ...] = (), rail_height_above_in: float | None = None, notes: str = '')[source]

Bases: object

One Ohio DOT standard bridge railing / barrier configuration.

test_level is the NCHRP 350 / MASH level stated on the drawing ("TL-2" .. "TL-6"); it keys TEST_LEVEL_LOADS. An empty string means the drawing states no numeric crash test level. Fields left as None / "" are not called out (or not applicable) on the drawing.

Concrete-parapet entries populate section_area (gross area of the standard, non-transition section), f_c/f_y, and the vertical-bar fields. Post-and-beam steel railings populate post_shape, post_spacing, rail_element, and f_y_steel instead.

bar_sizes: tuple[int, ...] = ()

Standard-bar designation numbers present in the section (#5, #6, …).

base_width: float | None = None
design_force_check(m_c: float, m_w: float, m_b: float = 0.0, end_region: bool = False)[source]

Run the AASHTO A13.3.1 yield-line check for this railing against its own test-level design forces.

Only meaningful for concrete-parapet entries. m_c (kip-ft/ft), m_w and m_b (kip-ft) are the wall’s flexural resistances; the railing’s catalog height (in) is converted to feet. Returns a CheckResult whose demand is the Table A13.2-1 transverse force Ft.

designation: str
f_c: float | None = None
f_y: float | None = None
f_y_steel: float | None = None

Structural / tube steel minimum yield, ksi.

height: float | None = None
material: str
meets_minimum_height() bool | None[source]

Whether the railing’s height satisfies the minimum rail height H for its test level (Table A13.2-1, h_min). None when the height or test level is not recorded.

For combination and post-and-beam railings height may be the crashworthy element height only; treat the result accordingly.

name: str
notes: str = ''
post_shape: str = ''

Steel post shape for post-and-beam railings (e.g. "W6x25").

post_spacing: float | None = None

Maximum post spacing, inches.

rail_element: str = ''

Longitudinal rail element(s) (e.g. "2 - TS 8x4x5/16").

rail_height_above_in: float | None = None

For a “combination” railing (full-height concrete barrier + steel tube pedestrian rail on top, e.g. BR-2-15): how far the steel tube assembly extends above the concrete barrier’s own height, inches.

scd: str
scd_date: str
section_area: float | None = None
segment_length_ft: tuple[float, ...] = ()

Precast segment length(s), feet (portable barrier).

shape: str
test_level: str
test_level_load() TestLevelLoad | None[source]

The Table A13.2-1 design forces for this railing’s test level, or None if the drawing states no numeric crash test level.

top_width: float | None = None
transition_length_ft: float | None = None

Length of the standard approach transition section, feet.

transition_volume_cy: float | None = None

Concrete volume of one transition section, cubic yards.

vertical_bar_spacing: float | None = None

Maximum on-center spacing of vertical reinforcing bars, inches.

weight_per_ft: float | None = None

Unit weight of the railing, lb/ft.

class civilpy.structural.odot.BridgeTerminalAssembly(scd: str, scd_date: str, designation: str, origin: str, start_offset_in: float, post_spacings_in: tuple[float, ...], post_groups: tuple[TerminalPostGroup, ...] = (), rail_elements: tuple[str, ...] = (), connection: str = '', curb_note: str = '', connects_to: tuple[str, ...] = (), pay_item: str = '', notes: str = '')[source]

Bases: object

One MGS bridge terminal assembly (SCD MGS-3.1 / 3.2 / 3.3).

post_spacings_in are the successive c/c spacings starting from origin (each sheet’s own stationing direction); start_offset_in is the distance from the origin to post 1. rail_elements list the transition rail pieces in the same order. Payment is Item 606, Each.

connection: str = ''
connects_to: tuple[str, ...] = ()
curb_note: str = ''
designation: str
property length_in: float

Origin to the last post, inches.

property n_posts: int
notes: str = ''
origin: str

what post 1 is measured from

pay_item: str = ''
post_groups: tuple[TerminalPostGroup, ...] = ()
post_spacings_in: tuple[float, ...]
post_stations_in() tuple[float, ...][source]

Post centers (inches) from origin.

rail_elements: tuple[str, ...] = ()
scd: str
scd_date: str
start_offset_in: float
class civilpy.structural.odot.BridgeTerminalLayout(terminal: BridgeTerminalAssembly, post_stations_in: tuple[float, ...], posts: tuple[tuple[int, str, float, str], ...], length_in: float, notes: tuple[str, ...] = ())[source]

Bases: object

Post stations and members of one MGS bridge terminal assembly.

length_in: float
notes: tuple[str, ...] = ()
post_stations_in: tuple[float, ...]
posts: tuple[tuple[int, str, float, str], ...]
terminal: BridgeTerminalAssembly
civilpy.structural.odot.CSBarRun

alias of BarRun

class civilpy.structural.odot.CSSlabDesign(end_span_ft: int, thickness_in: float, a_bar: ABarSpec, b_bar: LenBarSpec, c_bar: LenBarSpec, d_bar: LenBarSpec, e_bar: LenBarSpec | None, n_bar: CountBarSpec, m_bar: CountBarSpec, u_bar_count: int)[source]

Bases: object

One SLAB DATA table row (sheet 2), keyed by end span (ft).

a_bar: ABarSpec
b_bar: LenBarSpec
c_bar: LenBarSpec
d_bar: LenBarSpec
e_bar: LenBarSpec | None
end_span_ft: int
m_bar: CountBarSpec
n_bar: CountBarSpec
thickness_in: float
u_bar_count: int
class civilpy.structural.odot.ContinuousSlabInput(end_span_ft: int, width_ft: float, skew_deg: float = 0.0)[source]

Bases: object

Project dimensions for a 3-span continuous slab bridge (CS-1-24).

end_span_ft: int
skew_deg: float = 0.0
property total_length_ft: float

2 * end_span + interior_span.

Type:

Total length

width_ft: float
class civilpy.structural.odot.ContinuousSlabLayout(inputs: ~civilpy.structural.odot.continuous_slab_bridge.ContinuousSlabInput, outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], thickness_in: float, total_length_ft: float, pier_stations: tuple[float, float], bars: tuple[~civilpy.structural.odot.continuous_slab_bridge.BarRun, ...], notes: tuple[str, ...] = <factory>)[source]

Bases: object

The generated three-span continuous slab bridge. outline is the skewed plan parallelogram at z = 0 (top of slab, uniform thickness – haunches over the piers are not modeled); pier_stations are the two pier centerline X coordinates.

bars: tuple[BarRun, ...]
inputs: ContinuousSlabInput
notes: tuple[str, ...]
outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
pier_stations: tuple[float, float]
thickness_in: float
total_length_ft: float
civilpy.structural.odot.CpaRebarMark

alias of RebarMark

class civilpy.structural.odot.CurbType(sheet_labels: tuple[str, ...], name: str, height: float | None, top_width: float, base_width: float, toe_radius: float | None = None, notes: str = '')[source]

Bases: object

One BP-5.1 curb / combined curb-and-gutter cross section.

height is the curb’s own face height (in), None when it is the project-variable gutter-plate thickness T. top_width / base_width describe a schematic trapezoid of the curb’s concrete only (see module docstring for what is and isn’t modeled).

base_width: float
height: float | None
name: str
notes: str = ''
sheet_labels: tuple[str, ...]
toe_radius: float | None = None
top_width: float
class civilpy.structural.odot.DeckDesignPolicy(method: str = 'LRFD 9.7.3 approximate elastic (equivalent strip)', live_load: str = 'HL-93', future_wearing_surface_ksf: float = 0.06, monolithic_wearing_surface: float = 1.0, top_cover: float = 2.5, bottom_cover: float = 1.5, exposure_factor: float = 0.75, f_c: float = 4.5, f_y: float = 60.0, concrete_class: str = 'QC2', epoxy_coated: bool = True)[source]

Bases: object

ODOT concrete deck design requirements (BDM 309.3.2, 309.2, and the Figure 309-3 design assumptions). Thicknesses/covers in inches, pressures in ksf, strengths in ksi.

bottom_cover: float = 1.5
concrete_class: str = 'QC2'
epoxy_coated: bool = True
exposure_factor: float = 0.75
f_c: float = 4.5
f_y: float = 60.0
future_wearing_surface_ksf: float = 0.06
live_load: str = 'HL-93'
method: str = 'LRFD 9.7.3 approximate elastic (equivalent strip)'
monolithic_wearing_surface: float = 1.0
top_cover: float = 2.5
class civilpy.structural.odot.DripStripPlacement(railing: str, upper_strip_length_in: float, root_depth_in: float)[source]

Bases: object

Upper-strip length and the strip root depth below the deck (or wearing) surface for one railing type.

railing: str
root_depth_in: float
upper_strip_length_in: float
class civilpy.structural.odot.EdgeBarSpec(depth_in: 'float', taper_in: 'float', bar_size: 'int', bar_count: 'int')[source]

Bases: object

bar_count: int
bar_size: int
depth_in: float
taper_in: float
class civilpy.structural.odot.EdgeBeamDesign(span_ft: int, over_the_side: EdgeBarSpec, parapet: EdgeBarSpec)[source]

Bases: object

One EDGE BEAM SLAB DATA table row (sheet 2): the edge-beam depth and D/E-bar schedule for both edge conditions.

over_the_side: EdgeBarSpec
parapet: EdgeBarSpec
span_ft: int
class civilpy.structural.odot.EllipticalHeadwall(rise: float, span: float, width: float, height: float, thickness: float, concrete_cy: float)[source]

Bases: object

One HW-2.2 elliptical-pipe headwall line.

rise and span are the pipe rise R and span; width (W), height (H) and thickness (T) are the headwall dimensions; concrete_cy is the cast-in-place concrete quantity. All inches.

concrete_cy: float
height: float
rise: float
span: float
thickness: float
width: float
class civilpy.structural.odot.FenceRunInput(length_ft: 'float', post_name: 'str' = 'PS-2/BP-1', spacing_ft: 'float | None' = None)[source]

Bases: object

length_ft: float
post_name: str = 'PS-2/BP-1'
spacing_ft: float | None = None
class civilpy.structural.odot.FenceRunLayout(inputs: ~civilpy.structural.odot.vandal_fence.FenceRunInput, section: ~civilpy.structural.odot.vandal_fence.PostSection, post_stations_ft: tuple[float, ...], top_rail: tuple[tuple[float, float, float], tuple[float, float, float]], bottom_rail: tuple[tuple[float, float, float], tuple[float, float, float]], notes: tuple[str, ...] = <factory>)[source]

Bases: object

The generated fence run: post_stations_ft are evenly-spaced post positions along the run (never exceeding the section’s max spacing); top_rail/bottom_rail are the rail lines at post height / base.

bottom_rail: tuple[tuple[float, float, float], tuple[float, float, float]]
inputs: FenceRunInput
notes: tuple[str, ...]
post_stations_ft: tuple[float, ...]
section: PostSection
top_rail: tuple[tuple[float, float, float], tuple[float, float, float]]
class civilpy.structural.odot.FixedBearing(designation: str, max_load_lb: float, dims: dict[str, float], weight_lb: float, two_anchor_rods: bool = False, stiffeners_required: bool = False)[source]

Bases: object

One FB-1-82 fixed-bearing capacity line.

two_anchor_rods (note 1) is true only for F-50/F-100; otherwise 4 anchor rods are used (one per masonry-plate corner). stiffeners_required (note 2) is true only for F-350/F-400.

designation: str
dims: dict[str, float]
max_load_lb: float
stiffeners_required: bool = False
two_anchor_rods: bool = False
weight_lb: float
class civilpy.structural.odot.FixedBearingLayout(fb: civilpy.structural.odot.fixed_bearing.FixedBearing, base_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], base_thickness_in: float, top_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], top_z_in: float, pin_diameter_in: float, pin_center: tuple[float, float, float], notes: tuple[str, ...] = <factory>)[source]

Bases: object

base_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
base_thickness_in: float
fb: FixedBearing
notes: tuple[str, ...]
pin_center: tuple[float, float, float]
pin_diameter_in: float
top_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
top_z_in: float
class civilpy.structural.odot.FullHeightHeadwallDesign(diameter_in: float, height_ft: float, a_ft: float, b_ft: float, c_ft: float, ts_ft: float, bar_size: int, skews: tuple[SkewGroup, ...])[source]

Bases: object

One HW-1.1 table row (a pipe diameter), with all four skew columns.

a_ft: float
b_ft: float
bar_size: int
c_ft: float
diameter_in: float
height_ft: float
skew(skew_deg: float) SkewGroup[source]

The tabulated column for the nearest skew bucket to skew_deg.

skews: tuple[SkewGroup, ...]
ts_ft: float
civilpy.structural.odot.FullHeightHeadwallInput

alias of HeadwallInput

class civilpy.structural.odot.FullHeightHeadwallLayout(inputs: ~civilpy.structural.odot.full_height_headwall.HeadwallInput, table: ~civilpy.structural.odot.full_height_headwall.FullHeightHeadwallDesign, skew: ~civilpy.structural.odot.full_height_headwall.SkewGroup, skew_bucket_deg: float, type_: str, center_face: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], wing1: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], wing2: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], concrete_cy: float, steel_lb: float, notes: tuple[str, ...] = <factory>)[source]

Bases: object

The generated headwall+wingwall unit.

center_face is the vertical rectangular panel at the culvert centerline (X-Z plane at y = 0, width D centered on x = 0, height H); wing1/wing2 are the two wingwall planes as (near_top, near_base, far_base, far_top) quads swept from the center face’s top corners out to each wingwall’s far end. wing1 is the acute-side (L1/h1) wingwall, wing2 the obtuse-side (L2/h2) wingwall; for Type A (skew snapped to 0) both use the L2/h2 data and are mirror images. Origin: x = 0 on the culvert centerline, y = 0 at the headwall front face (wall behind, +y downstream), z = 0 at the flow line / wall base.

center_face: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
concrete_cy: float
inputs: HeadwallInput
notes: tuple[str, ...]
skew: SkewGroup
skew_bucket_deg: float
steel_lb: float
table: FullHeightHeadwallDesign
type_: str
wing1: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
wing2: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
class civilpy.structural.odot.Haunch(depth: float, flange_width: float)[source]

Bases: object

A concrete haunch per BDM 309.3.5: sides vertical and aligned with the edges of the top flange, so the haunch cross-section is simply flange_width x depth. Depths/widths in inches.

property area: float

Cross-sectional area (in^2).

dead_load_klf(unit_weight_kcf: float = 0.15) float[source]

Haunch self-weight per foot of girder (kip/ft).

depth: float
flange_width: float
class civilpy.structural.odot.Headwall(diameter: float, width: float, height: float, thickness: float, concrete_cy: float, note: str = '')[source]

Bases: object

One HW-2.1 circular-pipe headwall line.

diameter is the pipe inside diameter D; width (W), height (H) and thickness (T) are the headwall dimensions; concrete_cy is the cast-in-place concrete quantity. note flags special rows (e.g. pipe sizes between end treatments A and B).

concrete_cy: float
diameter: float
height: float
note: str = ''
thickness: float
width: float
civilpy.structural.odot.HeadwallSkewGroup

alias of SkewGroup

class civilpy.structural.odot.LoadPlateLayout(bevel_plate: BeveledLoadPlate, bottom_face: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], top_face: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], notes: tuple[str, ...] = ())[source]

Bases: object

The generated BD-1-11 beveled load plate, sized to a bearing pad’s plan footprint (bearing_pad(name).length x .width).

top_face carries the bevel: each corner’s Z is offset by its (x, y) distance from plate center times the transverse/longitudinal bevel slope, so the plate top is a single tilted plane (not warped).

bevel_plate: BeveledLoadPlate
bottom_face: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
notes: tuple[str, ...] = ()
top_face: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
class civilpy.structural.odot.MGSDrawing(scd: str, title: str, sheets: int, scd_date: str, category: str, connects_to: tuple[str, ...] = (), notes: str = '')[source]

Bases: object

One drawing in the Ohio DOT MGS roadway series.

category is one of standard, special, bridge_terminal, transition, anchor, terminal, layout, bridge. connects_to lists bridge-railing SCD numbers a terminal assembly ties into, where stated on the drawing.

category: str
connects_to: tuple[str, ...] = ()
notes: str = ''
scd: str
scd_date: str
sheets: int
title: str
class civilpy.structural.odot.MGSRunLayout(length_ft: float, spacing: PostSpacing, post_stations_ft: tuple[float, ...], n_panels: int, panel_length_ft: float, rail_height_in: float = 31.0, notes: tuple[str, ...] = ())[source]

Bases: object

Posts and W-beam panels of one straight standard-MGS run.

length_ft: float
n_panels: int
notes: tuple[str, ...] = ()
panel_length_ft: float
post_stations_ft: tuple[float, ...]
rail_height_in: float = 31.0
spacing: PostSpacing
class civilpy.structural.odot.MGSStandard(scd: str = 'MGS-2.1', scd_date: str = '2026-01-16', rail_height: float = 31.0, rail_height_tolerance_new: float = 1.0, rail_height_tolerance_existing: float = 3.0, rail: str = '12 gauge W-beam (CMS 606.02)', rail_panel_lengths: tuple[float, ...] = (12.5, 25.0), standard_post_length: float = 72.0, round_wood_post_length: float = 68.0, long_post_length: float = 97.0, embedment: float = 40.0, round_wood_embedment: float = 36.0, post_bolt_diameter: float = 0.625, blockout_section: str = '6 x 12', transition_rate_in_per_ft: float = 0.08)[source]

Bases: object

Standard Type MGS guardrail parameters (MGS-2.1).

Heights/lengths in inches; rail_panel_lengths (between splices) and transition rate are in feet.

blockout_section: str = '6 x 12'

Nominal blockout cross-section, inches.

embedment: float = 40.0

Standard embedment (steel / rectangular wood), inches.

long_post_length: float = 97.0

Long post length (steel / rectangular wood near slope break), inches.

post_bolt_diameter: float = 0.625

Post bolt diameter, inches.

post_spacing(name: str = 'standard') float[source]

On-center post spacing (inches) for "standard", "half", or "quarter" spacing.

rail: str = '12 gauge W-beam (CMS 606.02)'
rail_height: float = 31.0

Standard rail height to top of W-beam, inches.

rail_height_tolerance_existing: float = 3.0

Tolerance for existing guardrail after resurfacing, inches (+/-).

rail_height_tolerance_new: float = 1.0

Construction tolerance on initial install, inches (+/-).

rail_panel_lengths: tuple[float, ...] = (12.5, 25.0)

W-beam panel lengths between splices, feet.

round_wood_embedment: float = 36.0

Round wood post embedment, inches.

round_wood_post_length: float = 68.0

Round wood post length, inches.

scd: str = 'MGS-2.1'
scd_date: str = '2026-01-16'
standard_post_length: float = 72.0

Standard post length (steel / rectangular wood), inches.

transition_rate_in_per_ft: float = 0.08

Max rail-height transition rate (MGS-4.3), inches of height per foot.

class civilpy.structural.odot.PSIBeamLayout(section: ~civilpy.structural.odot.ps_i_beam.PSIBeamSection, profile: tuple[tuple[float, float], ...], length_ft: float, notes: tuple[str, ...] = <factory>)[source]

Bases: object

A simplified I-shaped cross-section profile (top flange, web, bottom flange) – straight-line approximation, no fillet/bulb radii – extruded length_ft. Profile points (y, z) inches, y transverse, z up from the bottom; the beam centerline is y = 0.

length_ft: float
notes: tuple[str, ...]
profile: tuple[tuple[float, float], ...]
section: PSIBeamSection
class civilpy.structural.odot.PSIBeamSection(name: str, depth_in: float, area_in2: float, weight_plf: float, yb_in: float, yt_in: float, i_in4: float, sb_in3: float, st_in3: float, vol_surf_ratio: float, top_flange_width_in: float, bottom_flange_width_in: float, max_bottom_flange_strands: int, web_in: float = 8.0, strand_rows: tuple = (), draped_required: tuple = (), shipping_strand_locations: tuple = ())[source]

Bases: object

One PSID-1-13 standard section (sheet 1 / sheet 3 SECTION PROPERTIES tables).

strand_rows is the sheet’s permissible strand grid: a tuple of (z, (y, ...)) rows – z inches above the beam bottom, y transverse offsets from the beam centerline (2 in lattice). The row totals equal max_bottom_flange_strands. draped_required lists the grid locations the sheet marks “if utilized, these strand locations must be draped” (WF sections’ upper web column). shipping_strand_locations are the optional debonded shipping strands the fabricator may add in the top flange (Modified AASHTO / WF sheets; the sheet ties them to general-note bonding rules – see SHIPPING_STRAND_BOND_FT).

area_in2: float
bottom_flange_width_in: float
depth_in: float
draped_required: tuple = ()
i_in4: float
max_bottom_flange_strands: int
name: str
sb_in3: float
shipping_strand_locations: tuple = ()
st_in3: float
strand_rows: tuple = ()
top_flange_width_in: float
vol_surf_ratio: float
web_in: float = 8.0
weight_plf: float
yb_in: float
yt_in: float
class civilpy.structural.odot.PierBarMark(mark: 'str', width_ft: 'float | None', height_is_q: 'bool', inside_radius_ft: 'float | None' = None, note: 'str' = '')[source]

Bases: object

height_is_q: bool
inside_radius_ft: float | None = None
mark: str
note: str = ''
width_ft: float | None
class civilpy.structural.odot.PierInput(slab_width_ft: float, skew_deg: float, n_piles: int, pile_spacing_ft: float, cap_depth_ft: float = 2.0)[source]

Bases: object

Inputs for a capped pile pier.

slab_width_ft is the bridge slab width (drives pier_length_ft()); n_piles/pile_spacing_ft lay out the pile line (spacing must not exceed MAX_PILE_SPACING_FT); cap_depth_ft defaults to the sheet’s fixed CAP_DEPTH_FT.

cap_depth_ft: float = 2.0
n_piles: int
pile_spacing_ft: float
skew_deg: float
slab_width_ft: float
class civilpy.structural.odot.PierLayout(inputs: ~civilpy.structural.odot.capped_pile_pier.PierInput, cap_outline: tuple[tuple[float, float, float], ...], pile_points: tuple[tuple[float, float, float], ...], length_ft: float, notes: tuple[str, ...] = <factory>)[source]

Bases: object

The generated pier. cap_outline is the rounded-end cap plan footprint (top of cap, z = 0) extending down cap_depth_ft; pile_points are the pile centerlines (top of pile, at the cap underside).

cap_outline: tuple[tuple[float, float, float], ...]
inputs: PierInput
length_ft: float
notes: tuple[str, ...]
pile_points: tuple[tuple[float, float, float], ...]
class civilpy.structural.odot.PlateSpacing(beam_width_in: float, dim_a_in: float, dim_b_in: float, dim_c_in: float)[source]

Bases: object

beam_width_in: float
dim_a_in: float
dim_b_in: float
dim_c_in: float
class civilpy.structural.odot.PostSection(name: str, base_plate: str, height_ft: float, max_spacing_ft: float, curved: bool = False, curve_radius_ft: float | None = None, note: str = '')[source]

Bases: object

One VPF-1-24 post section (sheet 2).

base_plate: str
curve_radius_ft: float | None = None
curved: bool = False
height_ft: float
max_spacing_ft: float
name: str
note: str = ''
class civilpy.structural.odot.PostSpacing(name: str, spacing: float, blockout_height: float)[source]

Bases: object

One MGS post-spacing option and the blockout height it requires (MGS-2.1 sheets P.1-P.2). spacing and blockout_height in inches.

blockout_height: float
name: str
spacing: float
class civilpy.structural.odot.RoadwayBarrier(scd: str, scd_date: str, designation: str, name: str, shape: str, material: str = 'reinforced concrete', height: float | None = None, top_width: float | None = None, base_width: float | None = None, slope_h_to_v: float | None = None, f_c: float | None = None, foundation: str = 'pavement', joint_spacing_ft: float | None = None, notes: str = '')[source]

Bases: object

One Ohio DOT standard roadway single-slope barrier type.

Mirrors the field names civilpy.structural.rhino_barrier .barrier_profile() reads (shape, height, base_width, top_width) so the same profile-sweep engine renders these as it does the structural bridge parapets.

base_width: float | None = None
designation: str
f_c: float | None = None
foundation: str = 'pavement'

“pavement” (cast on/dowelled to pavement), “leveling pad” (RM-4.8 Type N), “compacted soil” (RM-4.5 Type D), or “moment slab” (RM-4.9 Type E).

Type:

Foundation

height: float | None = None
joint_spacing_ft: float | None = None

Max unsealed-joint / contraction-joint spacing, ft.

material: str = 'reinforced concrete'
name: str
notes: str = ''
scd: str
scd_date: str
shape: str
slope_h_to_v: float | None = None
top_width: float | None = None
class civilpy.structural.odot.RoadwayBarrierInput(designation: str, length_ft: float)[source]

Bases: object

Inputs for one straight run of a roadway single-slope barrier.

designation: str
length_ft: float
class civilpy.structural.odot.RoadwayBarrierLayout(barrier: RoadwayBarrier, length_ft: float, profile: tuple[tuple[float, float], ...], notes: tuple[str, ...] = ())[source]

Bases: object

Symmetric cross-section plus run length for a roadway barrier.

profile is a closed list of (offset_in, z_in) vertices, offset measured from the barrier centerline and z from its base – the same convention civilpy.structural.rhino_barrier.barrier_profile() uses for a freestanding (side=0) section.

barrier: RoadwayBarrier
length_ft: float
notes: tuple[str, ...] = ()
profile: tuple[tuple[float, float], ...]
class civilpy.structural.odot.RockerBolster(capacity_kips: int, bolster_no: str, rocker_no: str, dims: dict[str, float], weight_bolster_lb: float | None, weight_rocker_lb: float, max_load_lb: float)[source]

Bases: object

One RB-1-55 rocker/bolster capacity line.

bolster_no is empty for the smallest line (R-75 has no matching bolster). dims is keyed by the letters in DIM_LETTERS.

bolster_no: str
capacity_kips: int
dims: dict[str, float]
max_load_lb: float
rocker_no: str
weight_bolster_lb: float | None
weight_rocker_lb: float
class civilpy.structural.odot.RockerBolsterLayout(rb: ~civilpy.structural.odot.rocker_bolster.RockerBolster, base_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], base_thickness_in: float, bolster_top: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], bolster_height_in: float, rocker_top_radius_in: float, rocker_height_in: float, notes: tuple[str, ...] = <factory>)[source]

Bases: object

The generated bolster + rocker pair for one capacity line, sharing the base-plate footprint origin at plan center, z = 0 at the bottom of the base plate.

base_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
base_thickness_in: float
bolster_height_in: float
bolster_top: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
notes: tuple[str, ...]
rb: RockerBolster
rocker_height_in: float
rocker_top_radius_in: float
class civilpy.structural.odot.ShearKeyDetail(grout_depth_from_top: float = 5.0, composite_backer_rod_min: float = 2.0, end_shear_key_depth: float = 1.0, end_shear_key_width: float = 38.0)[source]

Bases: object

Shear-key details between adjacent box beams (PSBD-1-25 sheets 1 & 5).

composite_backer_rod_min: float = 2.0

Backer rod diameter for composite beams, inches (min).

end_shear_key_depth: float = 1.0

End shear key depth at integral/semi-integral abutments, inches.

end_shear_key_width: float = 38.0

End shear key width at integral/semi-integral abutments, inches.

grout_depth_from_top: float = 5.0

Grout fill depth from top of beam to bottom of throat, inches.

civilpy.structural.odot.SlabBarSpec

alias of BarSpec

class civilpy.structural.odot.SlabBridgeInput(span_ft: int, width_ft: float, skew_deg: float = 0.0, edge_condition: Literal['over_the_side', 'parapet'] = 'over_the_side')[source]

Bases: object

Inputs for a single-span slab bridge.

edge_condition selects the edge-beam schedule: "over_the_side" (drainage over the fascia) or "parapet" (shallower edge beam under a concrete parapet, per the sheet’s edge-beam option).

edge_condition: Literal['over_the_side', 'parapet'] = 'over_the_side'

"over_the_side" (drainage over the fascia) or "parapet" (shallower edge beam under a parapet).

Type:

Edge-beam schedule

skew_deg: float = 0.0
span_ft: int
width_ft: float
class civilpy.structural.odot.SlabBridgeLayout(inputs: ~civilpy.structural.odot.slab_bridge.SlabBridgeInput, outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], thickness_in: float, bridge_length_ft: float, bars: tuple[~civilpy.structural.odot.slab_bridge.BarRun, ...], edge_beam: ~civilpy.structural.odot.slab_bridge.EdgeBarSpec, notes: tuple[str, ...] = <factory>)[source]

Bases: object

The generated slab bridge. outline is the skewed plan parallelogram at z = 0 (top of slab); the slab extends down thickness_in. bars are the A/B/M/N longitudinal runs.

bars: tuple[BarRun, ...]
bridge_length_ft: float
edge_beam: EdgeBarSpec
inputs: SlabBridgeInput
notes: tuple[str, ...]
outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
thickness_in: float
class civilpy.structural.odot.SlabDesign(span_ft: int, thickness_in: float, a_bar: BarSpec, b_bar: BarSpec, m_bar: BarSpec, n_bar: BarSpec)[source]

Bases: object

One SLAB DATA table row (sheet 1).

a_bar: BarSpec
b_bar: BarSpec
m_bar: BarSpec
n_bar: BarSpec
span_ft: int
thickness_in: float
civilpy.structural.odot.SleeperBarRun

alias of BarRun

civilpy.structural.odot.SleeperInstallation

alias of Installation

class civilpy.structural.odot.SleeperSlabInput(width_ft: float, skew_deg: float = 0.0, installation: str = 'A')[source]

Bases: object

Inputs for a Type A / Type C sleeper slab: the approach slab width it supports and the skew it parallels.

installation: str = 'A'
skew_deg: float = 0.0
width_ft: float
class civilpy.structural.odot.SleeperSlabLayout(inputs: ~civilpy.structural.odot.sleeper_slab.SleeperSlabInput, outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], thickness_in: float, bars: tuple[~civilpy.structural.odot.sleeper_slab.BarRun, ...], underdrain: tuple[tuple[float, float, float], tuple[float, float, float]], pma_joint: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], aggregate_drain: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], measured_length_ft: float, notes: tuple[str, ...] = <factory>)[source]

Bases: object

The generated sleeper slab. outline is the counterclockwise plan parallelogram at z = 0 (top of sleeper); the solid extends down SLEEPER_THICKNESS_IN. underdrain is the pipe centerline; pma_joint is the joint-system outline sitting on the sleeper top over the centerline, and aggregate_drain the trench outline below the slab.

aggregate_drain: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
bars: tuple[BarRun, ...]
inputs: SleeperSlabInput
measured_length_ft: float
notes: tuple[str, ...]
outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
pma_joint: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
thickness_in: float
underdrain: tuple[tuple[float, float, float], tuple[float, float, float]]
class civilpy.structural.odot.StandardDeckDesign(effective_span_ft: float, deck_thickness: float, overhang_thickness: float, transverse_top: BarMat, transverse_bottom: BarMat, longitudinal_top: BarMat, longitudinal_bottom: BarMat, overhang_bar_size: int | None, overhang_cutoff: float | None)[source]

Bases: object

One row of BDM Figure 309-3.

deck_thickness and overhang_thickness are totals including the 1 in monolithic wearing surface. overhang_bar_size / overhang_cutoff are the additional overhang bar and the length (in) beyond the fascia beam/girder centerline where it is no longer required (note 5); both are None where the figure tabulates none. Longitudinal spacings exclude the additional negative-moment reinforcement required over piers (note 6; LRFD 6.10.1.7 / 5.6.3.2).

deck_thickness: float
effective_span_ft: float
longitudinal_bottom: BarMat
longitudinal_top: BarMat
overhang_bar_size: int | None
overhang_cutoff: float | None
overhang_thickness: float
transverse_bottom: BarMat
transverse_top: BarMat
class civilpy.structural.odot.SteelPost(designation: str, fabrication: str, depth: float, flange_width: float, flange_thickness: float, web_thickness: float)[source]

Bases: object

An MGS steel beam post section (MGS-2.1 sheet P.2 table). All dimensions in inches.

depth: float
designation: str
fabrication: str
flange_thickness: float
flange_width: float
web_thickness: float
class civilpy.structural.odot.StripRun(kind: str, start_ft: float, end_ft: float)[source]

Bases: object

One strip piece along the fascia: stations in feet from the start of the run, plus which profile it carries.

end_ft: float
kind: str
property length_ft: float
start_ft: float
class civilpy.structural.odot.StripSealJointInput(width_ft: float, skew_deg: float, stringer_stations_ft: tuple[float, ...], top_flange_width_in: float = 12.0)[source]

Bases: object

Inputs for one strip seal joint run.

stringer_stations_ft are the transverse stringer positions (Y, ft) across the deck width; top_flange_width_in is the (uniform, assumed) stringer top flange width used in the support-angle formulas.

skew_deg: float
stringer_stations_ft: tuple[float, ...]
top_flange_width_in: float = 12.0
width_ft: float
class civilpy.structural.odot.StripSealJointLayout(inputs: ~civilpy.structural.odot.strip_seal_joint.StripSealJointInput, joint_line: tuple[tuple[float, float, float], tuple[float, float, float]], support_angles: tuple[~civilpy.structural.odot.strip_seal_joint.SupportAngleRun, ...], notes: tuple[str, ...] = <factory>)[source]

Bases: object

The generated joint: joint_line is the skewed gland centerline across the full deck width (z = 0, top of deck); support_angles is one short transverse segment per stringer station, sized by support_angle_lengths_in().

inputs: StripSealJointInput
joint_line: tuple[tuple[float, float, float], tuple[float, float, float]]
notes: tuple[str, ...]
support_angles: tuple[SupportAngleRun, ...]
class civilpy.structural.odot.SupportAngleRun(station_ft: float, points: tuple[tuple[float, float, float], tuple[float, float, float]], a1_in: float, a2_in: float, a3_in: float, a4_in: float)[source]

Bases: object

a1_in: float
a2_in: float
a3_in: float
a4_in: float
points: tuple[tuple[float, float, float], tuple[float, float, float]]
station_ft: float
class civilpy.structural.odot.TerminalPostGroup(first: int, last: int, post: str, length_in: float, blockout: str)[source]

Bases: object

A run of identical posts within a bridge terminal assembly. first/last are 1-based post numbers; lengths in inches.

blockout: str
property count: int
first: int
last: int
length_in: float
post: str
class civilpy.structural.odot.ThrieBeamPCBTransition(sheet: int, barrier_a: str, barrier_b: str, notes: str = '')[source]

Bases: object

One RM-4.7 connection pair (one sheet each). barrier_a / barrier_b name the generic/proprietary 32 in PCB shapes joined; the hardware set is common to all three pairs.

barrier_a: str
barrier_b: str
notes: str = ''
sheet: int
class civilpy.structural.odot.TieRodDetail(diameter: float = 1.0, thread_root_min_diameter: float = 0.838, torque_ft_lb: float = 250.0, plate_washer: str = '4 x 4 x 1/2', hole_min_diameter: float = 2.0, hole_max_diameter: float = 3.0, max_beams_per_rod: int = 3)[source]

Bases: object

Transverse tie rod details (PSBD-1-25 sheets 1 & 4).

diameter: float = 1.0
hole_max_diameter: float = 3.0
hole_min_diameter: float = 2.0
max_beams_per_rod: int = 3
plate_washer: str = '4 x 4 x 1/2'
thread_root_min_diameter: float = 0.838
torque_ft_lb: float = 250.0
vertical_position(beam_depth: int) float[source]

Tie-rod height above the beam soffit, inches: 9 in for 17-27 in deep beams, 14 in for 33-42 in deep beams (sheet 4/6).

class civilpy.structural.odot.TransitionSection(scd: str, name: str, height_from_in: float, height_to_in: float, length_ft: float, notes: str = '')[source]

Bases: object

A tapered end section joining two different barrier heights.

height_from_in: float
height_to_in: float
length_ft: float
name: str
notes: str = ''
scd: str
civilpy.structural.odot.TypicalAbutmentInput

alias of AbutmentInput

civilpy.structural.odot.TypicalAbutmentLayout

alias of AbutmentLayout

class civilpy.structural.odot.WingwallInput(length_ft: float, skew_deg: float, wall_height_ft: float, foreslope_height_ft: float, cutoff_wall_height_ft: float, footing_width_ft: float, box_wall_thickness_in: float, embankment_slope: float = 2.0)[source]

Bases: object

Project-supplied dimensions for one wingwall + foreslope wall (sheet 2/8 “WINGWALL ELEVATION” + “SECTION A-A”). All in feet unless named _in. Nothing here is cataloged – see the module docstring.

box_wall_thickness_in: float
cutoff_wall_height_ft: float
embankment_slope: float = 2.0
footing_width_ft: float
foreslope_height_ft: float
length_ft: float
skew_deg: float
wall_height_ft: float
class civilpy.structural.odot.WingwallLayout(inputs: ~civilpy.structural.odot.box_culvert_headwall.WingwallInput, wingwall_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], foreslope_section: tuple[tuple[float, float, float], ...], footing_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]], notes: tuple[str, ...] = <factory>)[source]

Bases: object

The generated wingwall + foreslope wall.

wingwall_outline is the wingwall’s flared elevation (top of footing at z = 0, box-face height H tapering to hf at y = L); foreslope_section is the Section A-A profile (cutoff wall, footing top, foreslope-wall stem with its t box thickness, 2:1 embankment line off the back face) in the Y-Z plane; footing_outline is the footing plan rectangle drawn at the bottom-of-cutoff elevation -hcw.

footing_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
foreslope_section: tuple[tuple[float, float, float], ...]
inputs: WingwallInput
notes: tuple[str, ...]
wingwall_outline: tuple[tuple[float, float, float], tuple[float, float, float], tuple[float, float, float], tuple[float, float, float]]
civilpy.structural.odot.anchor_bar_mark(backwall_thickness_in: float) str[source]

Which anchor bar the sheet permits for a given backwall thickness.

D801 cannot be used on backwalls less than 14 in thick; D802 is for prestressed box beam bridges with 11 in backwalls.

civilpy.structural.odot.anchor_hole_stations_ft(segment_length_ft: float) tuple[float, ...][source]

Anchor-hole stations along one segment (ft from its start): 1’-0” from each end, equally spaced at 2’-0” c/c (5 holes per row on a 10 ft segment, 6 on a 12 ft).

civilpy.structural.odot.approach_slab_design(length_ft: float) ApproachSlabDesign[source]

The standard design for an approach slab length L (ft).

civilpy.structural.odot.barrier_end_section(designation: str) BarrierEndSection[source]

Look up an RM-4.6 end section by designation ("Type B", "Type B1", "Type D").

civilpy.structural.odot.barrier_run(n_segments: int, segment_length_ft: float = 10.0, joint_gap_in: float = 0.25) tuple[BarrierSegment, ...][source]

Lay out n_segments along a straight run with the given joint gap (closed 1/4 in up to the fully-open 1-3/4 in max).

civilpy.structural.odot.bearing_pad(name: str) BearingPad[source]

Look up a standard bearing pad by name ("B1" or "B2").

civilpy.structural.odot.bearing_seat_dim_a_ft(skew_deg: float = 0.0) float[source]

DIM. A = 2'-0" / COS(skew) (sheet 2’s skewed part-plan).

civilpy.structural.odot.bend_shape(type_: str, **legs: float) tuple[tuple[float, float], ...][source]

The bend polyline for one of the BCHW legend shapes.

type_ is "TYPE-1" .. "TYPE-8"; legs supplies the leg lengths the sheet leaves blank (A, B, C, D as applicable, theta_deg for TYPE-2, skew_deg for TYPE-8). Raises ValueError naming the valid types and required legs.

civilpy.structural.odot.box_beam_design(box: str, span: int) BoxBeamDesign[source]

The design line for a box designation and span in feet.

civilpy.structural.odot.box_beam_rating(box: str, span: int, width_ft: int) BoxBeamRating[source]

The load rating for a box, span (ft), and bridge width (24/28/32 ft).

civilpy.structural.odot.box_section_properties(depth_in: int) BoxSectionProperties[source]

Look up the 48 in wide box-beam section properties for a standard depth (17/21/27/33/42 in).

civilpy.structural.odot.box_void_dimensions(depth_in: float, width_in: float = 48.0) tuple[float, float][source]

Void (width, height) in inches for a box beam of depth_in / width_in: BOX_WEB_THICKNESS_IN webs each side, BOX_FLANGE_THICKNESS_IN flanges top and bottom (PSBD-1-25 sheet 2/6 dimension chains).

civilpy.structural.odot.bridge_length_ft(span_ft: float, skew_deg: float = 0.0) float[source]

BRIDGE LENGTH = SPAN + (1.5' / COS(theta)) (sheet 1).

civilpy.structural.odot.bridge_terminal(designation: Literal['Type 1', 'Type 2', 'Type TST-2']) BridgeTerminalAssembly[source]

Look up a bridge terminal assembly ("Type 1", "Type 2", "Type TST-2").

civilpy.structural.odot.bridge_terminal_assemblies() list[MGSDrawing][source]

The MGS bridge terminal assemblies (transitions to bridge railings).

civilpy.structural.odot.cpa_bend_shape(bend_type: int, **legs: float) tuple[tuple[float, float], ...]

The bend polyline for one of CPA-1-08’s own legend shapes (1-5).

legs supplies whatever the sheet leaves blank (A, B, C as applicable). Raises ValueError naming the valid types (1-5; call into approach_slab for Type 6/D801) and required legs.

civilpy.structural.odot.cpa_rebar_mark(mark: str) tuple[RebarMark, ...]

All REBAR_TABLE rows for a bar mark (usually one; A801 has two – the standard anchor bar and the optional hooked-dowel alternate).

Raises ValueError naming the valid marks otherwise.

civilpy.structural.odot.cs_slab_design(end_span_ft: int) CSSlabDesign[source]

Look up the CS-1-24 slab design for an end span (feet, 14-46 tabulated; interior span is always 1.25x, see interior_span_ft()).

Raises ValueError naming the valid spans otherwise.

civilpy.structural.odot.curb_height_in(label: str, *, gutter_plate_t_in: float | None = None) float[source]

Resolved curb height (in): the catalog height if fixed, else the project gutter_plate_t_in (defaulting to DEFAULT_GUTTER_PLATE_T_IN) for the variable-height types.

civilpy.structural.odot.curb_profile_in(label: str, *, gutter_plate_t_in: float | None = None) tuple[tuple[float, float], ...][source]

Schematic closed trapezoid profile (in) for label, (offset, z) counterclockwise from the back-bottom corner, offset measured from the curb’s back face and z up from the pavement surface.

civilpy.structural.odot.curb_type(label: str) CurbType[source]

Look up a curb cross section by any of its sheet labels (e.g. "Type 2", "Type 2-A", "Type 10-B").

civilpy.structural.odot.designs_for_box(box: str) list[BoxBeamDesign][source]

All span designs for one box designation, shortest span first.

civilpy.structural.odot.diaphragm_count(span_ft: float) int[source]

Number of intermediate diaphragms for a span, per PSBD-1-25 sheet 4/6: 1 for spans <= 50 ft, 2 for 50 ft < span <= 75 ft, 3 for spans > 75 ft.

civilpy.structural.odot.diaphragm_end_offset(beam_depth: int) float[source]

Distance from beam end to the end diaphragm, inches (PSBD-1-25 sheet 4/6): 24 in for 17/21 in deep beams, 30 in for 27/33/42 in deep beams.

civilpy.structural.odot.diaphragm_stations_ft(span_ft: float, beam_depth: int) tuple[float, ...][source]

Station (ft, from the beam start) of every diaphragm, sorted: the two end diaphragms plus diaphragm_count() intermediate ones.

A 70 ft CB27-48 therefore has four – ends at 2.5 and 67.5 ft, intermediates at 24.17 and 45.83 – which is what PSBD-1-25 sheet 4/6 details and what the beam is cast solid at.

civilpy.structural.odot.drip_strip_runs(length_ft: float, post_stations_ft: tuple[float, ...], railing: str) tuple[StripRun, ...][source]

The strip pieces along ONE fascia edge: the continuous lower strip over the full length plus an upper strip centered at each railing post (clipped to the fascia). Raises ValueError for an unknown railing or non-positive length.

civilpy.structural.odot.edge_beam_design(span_ft: int) EdgeBeamDesign[source]

Look up the SB-1-24 edge-beam design for a span (feet, 11-38).

Raises ValueError naming the valid spans otherwise.

civilpy.structural.odot.elliptical_headwall_for_rise(rise: float) EllipticalHeadwall[source]

Look up the HW-2.2 concrete elliptical headwall by pipe rise (inches).

civilpy.structural.odot.end_diaphragm_stations_ft(span_ft: float, beam_depth: int) tuple[float, float][source]

Station (ft) of the two end diaphragms, one diaphragm_end_offset() in from each beam end (PSBD-1-25 sheet 4/6). These are cast inside the solid end blocks – see solid_end_block_in() – not in the voided length.

civilpy.structural.odot.fixed_bearing(designation: str) FixedBearing[source]

Look up a FB-1-82 fixed-bearing line by designation (“F-50”, …, “F-400”). Raises ValueError naming the valid designations otherwise.

civilpy.structural.odot.fixed_bearing_smallest_for_load(load_lb: float) FixedBearing

The lightest standard fixed bearing whose maximum load covers load_lb; raises ValueError if the load exceeds the F-400 line.

civilpy.structural.odot.full_height_headwall_design(diameter_in: float) FullHeightHeadwallDesign[source]

Look up the HW-1.1 table row for a pipe diameter (inches).

Raises ValueError naming the tabulated sizes if diameter_in is not one of them.

civilpy.structural.odot.haunch_depth_at(design_haunch: float, camber_residual: float) float[source]

Theoretical haunch depth (in) at a station where the girder sits camber_residual inches BELOW its theoretical profile (positive = girder low -> deeper haunch; negative = girder high -> shallower). The result may fall below MIN_DESIGN_HAUNCH — that is the signal the design haunch must be increased, not clamped away.

civilpy.structural.odot.headwall_for_diameter(diameter: float, concrete: bool = False) Headwall[source]

Look up the circular headwall for a pipe diameter (inches).

concrete=False uses the HW-2.1 corrugated-metal/plastic table; concrete=True uses the HW-2.2 concrete-pipe table. Raises KeyError if the diameter is not a tabulated size.

civilpy.structural.odot.i_beam_diaphragm_stations_ft(span_ft: float) list[float][source]

Intermediate-diaphragm centerline stations (ft from the span start) per sheet 5: one at midspan for spans up to 80 ft, at the quarter points beyond that. (Cast-in-place required under 60 in deep beams; 60/66/72 in beams may use the sheet 9 galvanized-steel diaphragms instead – sheet 10 general notes.)

civilpy.structural.odot.interior_span_ft(end_span_ft: float) float[source]

Interior span = end span * 1.25 (fixed ratio, sheet 2’s SLAB DATA “SPANS” column, e.g. 14 ft end -> 17.50 ft interior).

civilpy.structural.odot.intermediate_diaphragm_stations_ft(span_ft: float, beam_depth: int) tuple[float, ...][source]

Station (ft) of each intermediate diaphragm.

diaphragm_count() of them, dividing the length between the two end diaphragms into equal bays: one lands at midspan, two at the third points of that length, three at the quarter points. The drawing states the count and the end offset but not an explicit multi-diaphragm spacing rule; equal bays is the standard detailing assumption.

Note

This used to be folded into diaphragm_stations_ft with an k / (n - 1) interpolation, which for two diaphragms returned the two end stations and so produced no intermediate diaphragms at all – a 70 ft span came back as (2.5, 67.5). A model built on that had its tie rods buried in the end blocks and no diaphragm anywhere in the span.

civilpy.structural.odot.joint_length_ft(n_beams: int, beam_width_in: float, skew_deg: float = 0.0) float[source]

L = [(N-1)*(1/2) + N*W] / (12*cos(theta)) (sheet 1’s LEGEND): joint length edge-to-edge of deck, feet.

civilpy.structural.odot.lateral_clearance_in(superstructure_width_ft: float) float[source]

Lateral expansion clearance per end of the bearing pin (General Notes): 1/8 in normally, 1/4 in for a superstructure over 60 ft wide (up to the 120 ft this note addresses).

civilpy.structural.odot.layout_approach_slab(inp: ApproachSlabInput) ApproachSlabLayout[source]

Generate the AS-1-15 approach slab layout.

Raises ValueError when inputs leave the drawing’s assumptions (untabulated length, X < T, seat length outside 6-12 in, skew >= 60 degrees, or a backwall too thin for either anchor bar).

civilpy.structural.odot.layout_barrier_end_section(designation: str) BarrierEndSectionLayout[source]

Build the lofting stations for an RM-4.6 end section.

civilpy.structural.odot.layout_barrier_transition(designation: str, kind: str, *, obstruction_width_in: float | None = None, obstruction_length_ft: float = 0.0) BarrierTransitionLayout[source]

Build the RM-4.4 plan-width stations for a barrier transition.

designation is an RM-4.3 type (B/B1/C/C1); kind is "sign support" (light tower / sign foundation, 36-48 in wide, 10 ft run) or "pier" (48 in wide pier column protection; obstruction_length_ft is the variable column run between the two 5 ft shoulders). Raises ValueError for other barrier types or a sign-support width outside the sheet’s 36-48 in band.

civilpy.structural.odot.layout_bikeway_railing(inp: BikewayRailingInput) BikewayRailingLayout[source]

Lay out posts and rails for one RM-5.2 bikeway railing run.

Full posts at up to 10 ft centers with a mid-span stiffener post in each bay; each flared end (20 ft at 30 degrees away from the path) is treated as additional railing length with the same spacing. Raises ValueError for a non-positive length.

civilpy.structural.odot.layout_box_beam_joint(inp: BoxBeamJointInput) BoxBeamJointLayout[source]

Generate a box-beam strip seal joint: the skewed joint line and the beam-to-beam gap stations where plate “A”/”B”/”C” groups sit.

Raises ValueError for fewer than 2 beams or an untabulated beam width (plate_spacing()).

civilpy.structural.odot.layout_bridge_terminal(designation: Literal['Type 1', 'Type 2', 'Type TST-2']) BridgeTerminalLayout[source]

Expand a BRIDGE_TERMINALS entry into per-post members.

civilpy.structural.odot.layout_capped_pile_abutment(inp: AbutmentInput) AbutmentLayout[source]

Generate one capped pile abutment from fully project-supplied dimensions (no catalog lookup – see the module docstring).

Raises ValueError for a non-positive length/spacing/depth or fewer than 2 piles.

civilpy.structural.odot.layout_capped_pile_pier(inp: PierInput, *, n_arc_segments: int = 8) PierLayout[source]

Generate a capped pile pier: the rounded-end cap solid outline and the pile line, from the sheet’s own pier-length formula.

Raises ValueError for a non-positive slab width/pile spacing, fewer than 2 piles, a pile spacing beyond MAX_PILE_SPACING_FT, or a skew beyond MAX_SKEW_DEG.

civilpy.structural.odot.layout_continuous_slab(inp: ContinuousSlabInput) ContinuousSlabLayout[source]

Generate a three-span continuous slab bridge: plan outline, thickness, pier stations, and the A/B/C/D/E longitudinal bar mats (transverse N/M bars are cataloged by count, not separately drawn).

Raises ValueError for an untabulated end span or a skew beyond the sheet’s 25 deg limit.

civilpy.structural.odot.layout_fence_run(inp: FenceRunInput) FenceRunLayout[source]

Generate a fence run: evenly-spaced posts (spacing never exceeding the section’s tabulated maximum) plus top/bottom rail lines.

Raises ValueError for a non-positive length or an unknown post section name.

civilpy.structural.odot.layout_fixed_bearing(fb: FixedBearing) FixedBearingLayout[source]

Generate the drawable subset of one FB-1-82 line: the masonry plate, the top plate, and the bearing pin centerline.

E is used as the masonry plate thickness (it is the smallest tabulated dimension, consistent with a base-plate thickness) and H as the clearance from the top of that plate to the pin center, so the stack (plate + pin + top plate) is self-consistent even though the sheet does not label a dimension “base plate thickness” outright – see SCD_BUILD_QUESTIONS.md.

civilpy.structural.odot.layout_full_height_headwall(inp: HeadwallInput) FullHeightHeadwallLayout[source]

Generate the full-height headwall + wingwall solid.

Raises ValueError (via full_height_headwall_design()) for an untabulated pipe diameter, and (via nearest_skew_bucket()) for a skew beyond the table’s 45 deg range.

civilpy.structural.odot.layout_load_plate(bearing_pad_name: str, longitudinal_grade: float = 0.0, skew_deg: float = 0.0, plate: BeveledLoadPlate = BeveledLoadPlate(min_thickness=1.5, plate_grade='ASTM A709 Gr 50', anchor_rod_diameter=0.75, plate_washer='3 x 3 x 1/2', expansion_anchor_hole=1.25, stud_yield=50.0)) LoadPlateLayout[source]

Generate the BD-1-11 beveled load plate sized to bearing_pad_name ("B1" or "B2", bearing_pad()), tilted per load_plate_bevel(). Origin at plate-bottom center, z = 0 at the bottom face; x = bearing length (beam axis), y = bearing width.

civilpy.structural.odot.layout_mgs_run(length_ft: float, *, spacing: Literal['standard', 'half', 'quarter'] = 'standard', panel_length_ft: float = 25.0) MGSRunLayout[source]

Lay out a straight MGS-2.1 guardrail run: posts at the chosen spacing ("standard" / "half" / "quarter") and W-beam panels of panel_length_ft (12.5 or 25 ft between splices). Raises ValueError for a non-positive length, an unknown spacing, or a non-standard panel length.

civilpy.structural.odot.layout_ps_i_beam(name: str, length_ft: float, web_thickness_in: float = 8.0, flange_thickness_in: float = 8.0) PSIBeamLayout[source]

Generate a simplified I-beam cross-section profile for name (ps_i_beam_section()), extruded length_ft.

Raises ValueError for a non-positive length or an unknown section name.

civilpy.structural.odot.layout_roadway_barrier(inp: RoadwayBarrierInput) RoadwayBarrierLayout[source]

Build the symmetric single-slope cross-section for inp.

civilpy.structural.odot.layout_rocker_bolster(rb: RockerBolster) RockerBolsterLayout[source]

Generate the drawable subset of one RB-1-55 capacity line: the shared base-plate footprint, the bolster’s tapered+flat-top body, and the rocker’s tapered+curved-top body.

civilpy.structural.odot.layout_slab_bridge(inp: SlabBridgeInput) SlabBridgeLayout[source]

Generate a single-span slab bridge: plan outline, thickness, and the A/B/M/N longitudinal bar mats.

Raises ValueError for an untabulated span, an unknown edge_condition, or a skew beyond the sheet’s 25 deg limit.

civilpy.structural.odot.layout_sleeper_slab(inp: SleeperSlabInput) SleeperSlabLayout[source]

Generate the sleeper slab under the approach-slab/pavement joint.

Raises ValueError for a Type B installation (no sleeper slab), an unknown type, or out-of-range width/skew.

civilpy.structural.odot.layout_strip_seal_joint(inp: StripSealJointInput) StripSealJointLayout[source]

Generate a strip seal joint: the skewed joint line and one support-angle run per stringer station.

Raises ValueError for a non-positive width or an empty stringer_stations_ft.

civilpy.structural.odot.layout_typical_abutment(inp: AbutmentInput) AbutmentLayout[source]

Generate a typical abutment backwall + footing + one flared wingwall from fully project-supplied dimensions.

Raises ValueError for a non-positive width/wingwall length/footing depth/backwall height.

civilpy.structural.odot.layout_wingwall(inp: WingwallInput) WingwallLayout[source]

Generate one wingwall + foreslope wall from fully project-supplied dimensions (no catalog lookup – see the module docstring).

Raises ValueError for a non-positive length/height/width.

civilpy.structural.odot.load_plate_bevel(longitudinal_grade: float, skew_deg: float) tuple[float, float][source]

Transverse and longitudinal bevels of the BD-1-11 load plate.

The plate top is beveled to match the roadway grade resolved into the bearing’s local axes (BD-1-11 bevel notes): the component across the bearing width is grade * sin(skew) and the component along the bearing length is grade * cos(skew). longitudinal_grade is the roadway grade (rise/run, e.g. 0.04 for 4%); skew_deg is the structure skew angle in degrees. Returns (transverse, longitudinal) bevel slopes in the same rise/run units as the grade.

civilpy.structural.odot.m_bar_offset_in(bridge_limits_ft: float, n_m_bars: int, m_bar_spacing_ft: float) float[source]

Sheet 1’s Y formula: the offset from the bearing line to the first M-bar, Y = 1/2 * [bridge limits - (n_m_bars - 1) * spacing] * 12 (inches).

civilpy.structural.odot.mgs_drawing(scd: str) MGSDrawing[source]

Look up an MGS drawing by SCD number (e.g. "MGS-3.1").

civilpy.structural.odot.minimum_deck_thickness(effective_span_ft: float) float[source]

Minimum total deck thickness (in) per BDM 309.3.1.

Tmin = (S + 17)(12)/36 >= 8.5 in rounded up to the nearest 1/4 in, where effective_span_ft is the effective span length per LRFD 9.7.2.3. Includes the 1 in monolithic wearing surface; subtract DeckDesignPolicy.monolithic_wearing_surface for the structural design thickness.

civilpy.structural.odot.nearest_skew_bucket(skew_deg: float) float[source]

Snap a skew angle to the nearest tabulated bucket (0/15/30/45 deg).

The 0 deg cutoff is pinned to SKEW_TYPE_A_MAX_DEG (10 deg) – sheet 1’s own Type A/B boundary – rather than the halfway point (7.5 deg) so a skew that the sheet calls Type A never gets Type B’s asymmetric wingwall data; 15/30/45 split at their halfway points (22.5, 37.5) as plain nearest-neighbor. Raises ValueError for a skew outside the table’s range (sheet 1 tabulates through 45 deg only; beyond that the standard drawing does not apply).

civilpy.structural.odot.overhang_thickness(design: StandardDeckDesign, railing: str | None = None) float[source]

Overhang deck thickness (in) for a standard design, applying the note 2.k minimums for the TST steel-tube railings when they govern.

civilpy.structural.odot.pcb_profile_points_in(chamfered: bool = True) tuple[tuple[float, float], ...]

The closed New Jersey shape section, counterclockwise from the bottom-left corner, as (x, y) inches with x transverse from the barrier centerline and y up from the deck surface.

chamfered includes the 3/4 in top chamfers (the sheet allows a 1 in radius instead).

civilpy.structural.odot.pier_bar(mark: str) PierBarMark[source]

Look up a CPP-1-08 bar mark (P501-P504).

Raises ValueError naming the valid marks otherwise.

civilpy.structural.odot.pier_length_ft(slab_width_ft: float, skew_deg: float = 0.0) float[source]
civilpy.structural.odot.plate_spacing(beam_width_in: float) PlateSpacing[source]

Look up the EXJ-5-93 plate spacing for a beam width (36 or 48 in).

Raises ValueError naming the valid widths otherwise.

civilpy.structural.odot.post_section(name: str) PostSection[source]

Look up a VPF-1-24 post section (“PS-1”, “PS-2/BP-1”, “PS-2/BP-2”).

Raises ValueError naming the valid names otherwise.

civilpy.structural.odot.ps_i_beam_profile(name: str) tuple[tuple[float, float], ...][source]

The true tapered cross-section outline of a PSID-1-13 section as closed-polygon vertices (y, z) in inches, y transverse from the beam centerline, z up from the bottom – counter-clockwise, starting at the bottom-left corner. Straight-line approximation: fillet and 3/4 in chamfer radii are not modeled (unlike layout_ps_i_beam(), the flange tapers are).

civilpy.structural.odot.ps_i_beam_section(name: str) PSIBeamSection[source]

Look up a PSID-1-13 standard section by name.

Raises ValueError naming the valid sections otherwise.

civilpy.structural.odot.q_bend_height_ft(slab_thickness_in: float) float[source]
civilpy.structural.odot.railing(designation: str) BridgeRailing[source]

Look up a railing by its designation (e.g. "BR-1 (36 in)").

civilpy.structural.odot.railings_for_test_level(test_level: str) list[BridgeRailing][source]

All cataloged railings rated for test_level (e.g. "TL-4").

civilpy.structural.odot.roadway_barrier(designation: str) RoadwayBarrier[source]

Look up a roadway barrier type by its designation (e.g. "Type B", "Type N").

civilpy.structural.odot.roadway_portable_barrier(designation: str) BridgeRailing[source]

Look up a roadway portable barrier by its designation (e.g. "RM Portable (32 in, pin & loop)").

civilpy.structural.odot.rocker_bolster(capacity_kips: int) RockerBolster[source]

Look up a rocker/bolster line by rated capacity in kips (75..300).

civilpy.structural.odot.s_bar_length_ft(base_ft: float, skew_deg: float) float[source]

S501/S502/S503’s tabulated base/COS(theta) length formula.

civilpy.structural.odot.secondary_longitudinal_reinforcement(main: BarMat) BarMat[source]

Minimum longitudinal top-mat (secondary) reinforcement per BDM 309.3.4.1: at least 1/3 of the main (transverse) reinforcement, spaced uniformly, detailed as #4 bars — unless that would put the #4s closer than 3 in, in which case a larger bar at >= 3 in spacing is returned.

Applies the 1/3 rule to the provided main steel, which is slightly conservative against BDM Figure 309-3 (whose longitudinal mats derive from the required steel); for spans the figure tabulates, use the figure’s mats — this helper is for custom designs outside it.

civilpy.structural.odot.slab_design(span_ft: int) SlabDesign[source]

Look up the SB-1-24 slab design for a span (feet, 11-38 tabulated).

Raises ValueError naming the valid spans otherwise.

civilpy.structural.odot.sleeper_installations(type_: str) tuple[Installation, ...]

All cataloged configurations of the given installation type.

civilpy.structural.odot.smallest_for_load(load_lb: float) RockerBolster[source]

The lightest standard rocker/bolster whose maximum load covers load_lb; raises ValueError if the load exceeds the 300-kip line.

civilpy.structural.odot.solid_diaphragm_block_in(skew_deg: float = 0.0, width_in: float = 48.0) float[source]

Longitudinal length of an intermediate diaphragm’s solid block.

Zero skew gives SOLID_DIAPHRAGM_BLOCK_IN; a skewed beam needs X/2 + 6 inches, X = width * tan(skew), so the block still contains the full diaphragm once it runs on the bias.

civilpy.structural.odot.solid_end_block_in(depth_in: int) float[source]

Length of the solid end block for a beam of depth_in.

civilpy.structural.odot.ss501_length_ft(width_ft: float, skew_deg: float = 0.0) float[source]

SS501 length A = (W - 0.5’)/cos(theta) (sheet 1 bending table).

civilpy.structural.odot.ss502_count(width_ft: float) int[source]

SS502 bars at 1’-0” max, measured perpendicular to CL roadway, across the (W - 0.5) bar band — spaces rounded up.

civilpy.structural.odot.ss502_length_ft(skew_deg: float = 0.0) float[source]

SS502 length B = 7.5’/cos(theta) (sheet 1 bending table).

civilpy.structural.odot.standard_deck_design(effective_span_ft: float, *, railing: str | None = None, beam_lines: int | None = None, beam_spacing_ft: float | None = None, overhang_ft: float | None = None) StandardDeckDesign[source]

Look up the BDM Figure 309-3 standard design for an effective span.

effective_span_ft is the effective span length per LRFD 9.7.3.2; it is rounded up to the next tabulated 0.5 ft increment (note 2.k). The optional keywords assert the figure’s design assumptions — railing (SCD designation, note 2.k), beam_lines (>= 4, note 2.a), beam_spacing_ft (<= 15 ft, note 2.b) and overhang_ft (<= 4 ft, note 2.j) — and raise ValueError when the standard designs do not apply, in which case the deck must be designed per BDM 309.3.2 instead.

civilpy.structural.odot.standard_hook_bar_length_ft(span_ft: float) float[source]

A/D/E-bar standard-hook length: span + 10" (the bending-diagram formula shared by all three bar marks).

civilpy.structural.odot.strand_centroid_in(pattern: list[tuple[float, float]]) float[source]

Height of a strand pattern’s centroid above the beam bottom (in).

civilpy.structural.odot.strand_grid(name: str) list[tuple[float, float]][source]

Every permissible bottom-flange/web strand location of a section as (y, z) inches, in the standard fill order: row by row from the bottom up, outermost locations first within a row (the fill order keeps each partial pattern symmetric and its centroid low).

Locations in PSIBeamSection.draped_required come last so a straight-strand design never occupies them by accident.

civilpy.structural.odot.strand_group_height_in(design: BoxBeamDesign) float[source]

Height of the strand-group centroid above the soffit (in), the strand-count-weighted average of the 2/4/6 in row heights. A schematic single-height tendon path uses this; it is consistent with (Yb of the matching BoxSectionProperties) minus design.e_beam to within drawing rounding.

civilpy.structural.odot.strand_pattern(name: str, n_strands: int) list[tuple[float, float]][source]

The first n_strands locations of strand_grid() – the pattern the pipeline’s designer uses. Raises ValueError when n_strands exceeds the section’s permissible locations.

civilpy.structural.odot.strip_profile_in(kind: str, *, bent: bool = True, include_embedded: bool = True) tuple[tuple[float, float], ...][source]

Cross-section polyline of one strip, inches, in the (h, v) plane: h positive outward from the fascia face (h = 0 at the bend line), v positive up.

kind is "upper" (leg turned up 45 degrees) or "lower" (leg turned down). bent=False gives the pre-placement shape (leg vertical against the form). include_embedded=False returns only the exposed leg.

civilpy.structural.odot.structural_design_thickness(total_thickness: float) float[source]

Deck thickness used in structural design (in): the total thickness minus the monolithic wearing surface (BDM 309.3.1 / 309.1.A).

civilpy.structural.odot.support_angle_lengths_in(top_flange_width_in: float, skew_deg: float) tuple[float, float, float, float][source]

The a1/a2/a3/a4 support-angle formulas (sheet 1, SECTION C-C).

Returns (a1, a2, a3, a4) in inches; mirror the sign convention for a left-forward skew per the sheet’s own note (use the same magnitude, mirrored in plan by the caller).

civilpy.structural.odot.terminals_for_railing(scd: str) list[MGSDrawing][source]

MGS terminal assemblies that connect to bridge railing scd (e.g. "TST-2-21").

civilpy.structural.odot.thrie_beam_pcb_transition(barrier_a: str, barrier_b: str) ThrieBeamPCBTransition[source]

Look up the RM-4.7 pair joining two PCB shapes (order-free). Raises ValueError naming the cataloged pairs otherwise — in particular there is no approved pair involving the J-J Hook 32 in New Jersey shape PCB.

civilpy.structural.odot.thrie_beam_transition_notes() tuple[str, ...][source]

The deployment / payment rules common to every RM-4.7 pair.

civilpy.structural.odot.top_bearing_plate_radius_in(a_in: float) float[source]
civilpy.structural.odot.top_bearing_web_radius_in(a_in: float) float[source]