WillTools: precast shop-ticket QC and panel handling tools
ci / test (push) Has been cancelled

Public demo snapshot of an in-house pyRevit extension for precast concrete
shop-ticket QC (37 checks / 46 checklist rows) and a standalone panel
handling solver (PCI Chapter 8).

- No client, job, plant or product data: knowledge layers ship as
  structural templates only.
- Ticket QC's model-read escalation targets a LAN model server endpoint
  (configurable), not a cloud provider.
- Built from the private development repo via tools/make_dist.py.
This commit is contained in:
2026-09-03 16:33:47 -05:00
commit 52d94303bc
281 changed files with 155656 additions and 0 deletions
+110
View File
@@ -0,0 +1,110 @@
# -*- 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))