Files
willtools-demo/panellift/tests/conftest.py
T
will 25592fa6c2
ci / test (push) Successful in 6m14s
WillTools 2026-09-09 -- clean snapshot of the development repo for review
History-free snapshot of the private development repository at 77a82eb.
Code, docs and the public catalogue only: no plant or job knowledge
layers, no client, job or producer names (tools/scrub.py clean against
the widened term list; a second word-level grep clean). The intro deck is
left out because its slide images cannot be checked for job drawings.
2026-09-09 08:35:15 -05:00

121 lines
3.6 KiB
Python

# -*- coding: utf-8 -*-
"""Shared fixtures, built from the ASPIRE Winter 2019 worked examples.
Brown, K. "Calculations for Handling and Shipping Precast Concrete Deck
Panels." ASPIRE, Winter 2019, pp. 24-27. The article reproduces PCI Design
Handbook Table 8.3.1 and Figure 8.3.2 and works two examples end to end, which
makes it the one published check available without a PCI licence.
Panel: 10 ft x 32 ft x 8.75 in., normalweight, f'ci = 4000, f'c = 5000,
four-point pick at the Figure 8.3.2 locations.
"""
import sys
from pathlib import Path
import pytest
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / 'src'))
from panellift.model import Blockout, Lifter, Panel, Rigging, Stage # noqa: E402
from panellift import pci # noqa: E402
WIDTH_FT = 10.0
LENGTH_FT = 32.0
THICKNESS_IN = 8.75
# The article's rounded values, quoted so a failure names the source number.
ASPIRE = {
'w_psf': 109.4,
'moment_lbft': 23973.0,
's_solid_in3': 1531.0,
's_pocketed_in3': 1148.0,
'strip_stress_psi': 244.0,
'strip_allowable_psi': 316.0,
'ship_stress_psi': 282.0,
'ship_allowable_psi': 354.0,
'pocketed_strip_stress_psi': 326.0,
'pocketed_ship_stress_psi': 376.0,
}
def four_point_lifters(length_ft=LENGTH_FT, width_ft=WIDTH_FT):
"""Two lines of two, at the Figure 8.3.2 equalising positions."""
left, right = pci.optimal_two_line_supports(length_ft)
ys = (0.25 * width_ft, 0.75 * width_ft)
return [Lifter(mark='L{0}'.format(i + 1), family='TEST_LIFTER',
x=x, y=y, role='strip', capacity_lb=8000.0)
for i, (x, y) in enumerate([(left, ys[0]), (left, ys[1]),
(right, ys[0]), (right, ys[1])])]
def make_panel(mark='ASPIRE-1', blockouts=None):
"""A fresh panel every time.
Built by a plain function rather than by one fixture mutating another:
pytest caches a fixture per test, so a test asking for both the solid and
the pocketed panel would otherwise be handed the same object twice and
quietly compare it with itself.
"""
return Panel(
mark=mark,
length_ft=LENGTH_FT,
width_ft=WIDTH_FT,
thickness_in=THICKNESS_IN,
unit_weight_pcf=150.0,
fci_psi=4000.0,
fc_psi=5000.0,
finish='smooth',
product_type='flat',
lifters=four_point_lifters(),
blockouts=list(blockouts or []),
)
def aspire_pockets():
"""Five 6 in. x 24 in. full-depth pockets in one row across the width.
The article puts them 'at or near the lifting points' and notes that is
not good practice -- it is the location of maximum moment. Five pockets
six inches wide take 2.5 ft out of a 10 ft width, giving S = 1148 in^3.
"""
left, _ = pci.optimal_two_line_supports(LENGTH_FT)
return [Blockout(name='P{0}'.format(i + 1),
x0=left - 1.0, y0=1.0 + i * 1.5,
length=2.0, width=0.5)
for i in range(5)]
@pytest.fixture
def solid_panel():
return make_panel()
@pytest.fixture
def pocketed_panel():
return make_panel(mark='ASPIRE-2', blockouts=aspire_pockets())
@pytest.fixture
def stripping():
return Stage(name='stripping',
multiplier=pci.stripping_multiplier('flat', 'smooth'),
fc_psi=4000.0)
@pytest.fixture
def shipping():
return Stage(name='transportation',
multiplier=pci.TRANSPORTATION_MULTIPLIER,
fc_psi=5000.0)
@pytest.fixture
def rolling():
return Rigging(mode='rolling', sling_angle_deg=90.0)
@pytest.fixture
def static_lift():
return Rigging(mode='static', sling_angle_deg=90.0)