Files
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

111 lines
4.4 KiB
Python

# -*- coding: utf-8 -*-
"""The beam solver must reproduce PCI Figure 8.3.2 from first principles.
This is the test the whole design rests on. Figure 8.3.2's coefficients are
not a separate method -- they are the closed-form solution of a uniformly
loaded beam with two overhangs, with the supports placed where the positive
and negative moments come out equal. If our solver cannot land on 0.0214 with
the supports there, it cannot be trusted with the supports somewhere else,
which is the only case anyone actually needs it for.
"""
import math
from panellift import pci, section, statics
from panellift.model import Stage
from conftest import ASPIRE, LENGTH_FT, WIDTH_FT
def test_optimal_support_fraction_is_the_root_of_the_quadratic():
a = pci.OPTIMAL_TWO_LINE_FRACTION
assert abs(4 * a ** 2 + 4 * a - 1) < 1e-12
assert abs(a - 0.20710678) < 1e-7
def test_closed_form_coefficient_is_pcis_0_0214():
"""M = w*(aL)^2/2 with a = (sqrt(2)-1)/2 gives 0.02145, printed as 0.0214."""
a = pci.OPTIMAL_TWO_LINE_FRACTION
coefficient = a ** 2 / 2.0
assert abs(coefficient - 0.0214) < 0.0001
def test_solver_reproduces_my_coefficient(solid_panel, rolling):
"""The numerical diagram must match 0.0214 w a b^2 to within 0.5%."""
stage = Stage(name='unfactored', multiplier=1.0, fc_psi=4000.0)
result = statics.analyse(solid_panel, stage, rolling,
reconcile_weight=False)
w_psf = section.unit_weight_psf(solid_panel)
_, expected = pci.fig_832_four_point(w_psf, WIDTH_FT, LENGTH_FT)
_, m_pos = result.diagram.max_positive
_, m_neg = result.diagram.max_negative
assert abs(m_pos - expected) / expected < 0.005
assert abs(abs(m_neg) - expected) / expected < 0.005
def test_positive_and_negative_moments_are_equal_at_the_optimum(solid_panel,
rolling):
"""That equality is the definition of the Figure 8.3.2 layout."""
stage = Stage(name='unfactored', multiplier=1.0, fc_psi=4000.0)
result = statics.analyse(solid_panel, stage, rolling,
reconcile_weight=False)
_, m_pos = result.diagram.max_positive
_, m_neg = result.diagram.max_negative
assert abs(m_pos - abs(m_neg)) / m_pos < 0.01
def test_unit_weight_matches_the_article(solid_panel):
assert abs(section.unit_weight_psf(solid_panel) -
ASPIRE['w_psf']) < 0.1
def _peak_abs_moment(result):
"""The governing moment, whichever sign it has.
Bunching the picks inboard turns the panel into two long cantilevers, and
then the whole interior hogs -- the largest positive moment is zero, at
the ends. Comparing only sagging would read that as an improvement.
"""
_, positive = result.diagram.max_positive
_, negative = result.diagram.max_negative
return max(abs(positive), abs(negative))
def test_moving_the_supports_inboard_raises_the_governing_moment(solid_panel,
rolling):
"""A sanity check that the solver is solving, not returning a constant."""
stage = Stage(name='unfactored', multiplier=1.0, fc_psi=4000.0)
optimum = _peak_abs_moment(
statics.analyse(solid_panel, stage, rolling, reconcile_weight=False))
for lifter in solid_panel.lifters:
lifter.x = LENGTH_FT / 2.0 + math.copysign(
4.0, lifter.x - LENGTH_FT / 2.0)
moved = _peak_abs_moment(
statics.analyse(solid_panel, stage, rolling, reconcile_weight=False))
assert moved > optimum * 1.5
def test_the_optimum_layout_really_is_the_optimum(solid_panel, rolling):
"""No other support position beats (sqrt(2)-1)/2. Worth proving once.
This is what makes the PCI layout a benchmark the report can measure a
detailer's actual layout against, rather than just another arrangement.
"""
stage = Stage(name='unfactored', multiplier=1.0, fc_psi=4000.0)
best = _peak_abs_moment(
statics.analyse(solid_panel, stage, rolling, reconcile_weight=False))
for fraction in (0.10, 0.15, 0.18, 0.23, 0.26, 0.30):
left = fraction * LENGTH_FT
for lifter in solid_panel.lifters:
lifter.x = left if lifter.x < LENGTH_FT / 2.0 else LENGTH_FT - left
trial = _peak_abs_moment(
statics.analyse(solid_panel, stage, rolling,
reconcile_weight=False))
assert trial >= best * 0.999, (
'fraction {0} beat the supposed optimum'.format(fraction))