Convert input parsing to Pint (matching the other calculations), carry units in the YAML values, and drop unit suffixes from input keys, local variables, results keys, the Typst sheet, and tests.
146 lines
4.2 KiB
Python
146 lines
4.2 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
import math
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
try:
|
|
import yaml
|
|
except ImportError:
|
|
raise SystemExit("Install PyYAML: python -m pip install pyyaml")
|
|
|
|
try:
|
|
from pint import DimensionalityError, UndefinedUnitError, UnitRegistry
|
|
except ImportError:
|
|
raise SystemExit("Install dependencies: python -m pip install -r requirements.txt")
|
|
|
|
|
|
HERE = Path(__file__).resolve().parent
|
|
|
|
ureg = UnitRegistry()
|
|
ureg.define("kip = 1000 * force_pound")
|
|
ureg.define("ksi = kip / inch ** 2")
|
|
ureg.define("psf = force_pound / foot ** 2")
|
|
ureg.define("pcf = force_pound / foot ** 3")
|
|
|
|
|
|
def quantity(value, unit: str, name: str) -> float:
|
|
try:
|
|
q = ureg.Quantity(value).to(unit)
|
|
except (DimensionalityError, UndefinedUnitError, TypeError, ValueError) as exc:
|
|
raise ValueError(f"{name}: expected {unit}, got {value!r}") from exc
|
|
magnitude = float(q.magnitude)
|
|
if magnitude <= 0:
|
|
raise ValueError(f"{name} must be positive")
|
|
return magnitude
|
|
|
|
|
|
def compute(inp: dict) -> dict:
|
|
span = quantity(inp["span"], "ft", "span")
|
|
tributary = quantity(inp["tributary"], "ft", "tributary")
|
|
D = quantity(inp["D"], "psf", "D")
|
|
L = quantity(inp["L"], "psf", "L")
|
|
bw = quantity(inp["bw"], "in", "bw")
|
|
h = quantity(inp["h"], "in", "h")
|
|
d = quantity(inp["d"], "in", "d")
|
|
fc = quantity(inp["fc"], "ksi", "fc")
|
|
fy = quantity(inp["fy"], "ksi", "fy")
|
|
As = quantity(inp["As"], "in**2", "As")
|
|
concrete_density = quantity(inp["concrete_density"], "pcf", "concrete_density")
|
|
|
|
self_weight = (bw * h / 144.0) * concrete_density / 1000.0
|
|
wD = D * tributary / 1000.0 + self_weight
|
|
wL = L * tributary / 1000.0
|
|
wu = 1.2 * wD + 1.6 * wL
|
|
Mu = wu * span**2 / 8.0
|
|
Vu = wu * span / 2.0
|
|
|
|
a = As * fy / (0.85 * fc * bw)
|
|
beta1 = max(0.65, min(0.85, 0.85 - 0.05 * max(0.0, (fc * 1000.0 - 4000.0) / 1000.0)))
|
|
c = a / beta1
|
|
et = 0.003 * (d - c) / c if c > 0 else 0.0
|
|
if et >= 0.005:
|
|
phi = 0.90
|
|
else:
|
|
phi = max(0.65, min(0.90, 0.65 + (et - 0.002) * 250.0 / 3.0))
|
|
Mn = As * fy * (d - a / 2.0) / 12.0
|
|
phiMn = phi * Mn
|
|
|
|
rho_min = max(3.0 * math.sqrt(fc * 1000.0) / (fy * 1000.0), 200.0 / (fy * 1000.0))
|
|
As_min = rho_min * bw * d
|
|
|
|
Vc = 2.0 * math.sqrt(fc * 1000.0) * bw * d / 1000.0
|
|
phiVc = 0.75 * Vc
|
|
|
|
def q(value: float) -> float:
|
|
return round(value, 6)
|
|
|
|
return {
|
|
"tool": "concrete_beam",
|
|
"version": "0.1",
|
|
"project": inp.get("project", ""),
|
|
"prepared_by": inp.get("prepared_by", ""),
|
|
"values": {
|
|
"span": q(span),
|
|
"tributary": q(tributary),
|
|
"D": q(D),
|
|
"L": q(L),
|
|
"self_weight": q(self_weight),
|
|
"wD": q(wD),
|
|
"wL": q(wL),
|
|
"wu": q(wu),
|
|
"Mu": q(Mu),
|
|
"Vu": q(Vu),
|
|
"bw": q(bw),
|
|
"h": q(h),
|
|
"d": q(d),
|
|
"fc": q(fc),
|
|
"fy": q(fy),
|
|
"As": q(As),
|
|
"a": q(a),
|
|
"et": q(et),
|
|
"phi": q(phi),
|
|
"Mn": q(Mn),
|
|
"phiMn": q(phiMn),
|
|
"As_min": q(As_min),
|
|
"Vc": q(Vc),
|
|
"phiVc": q(phiVc),
|
|
},
|
|
"checks": {
|
|
"flexure": {
|
|
"demand": q(Mu),
|
|
"capacity": q(phiMn),
|
|
"ok": Mu <= phiMn,
|
|
},
|
|
"minimum_steel": {
|
|
"demand": q(As_min),
|
|
"capacity": q(As),
|
|
"ok": As >= As_min,
|
|
},
|
|
"shear": {
|
|
"demand": q(Vu),
|
|
"capacity": q(phiVc),
|
|
"ok": Vu <= phiVc,
|
|
},
|
|
},
|
|
}
|
|
|
|
|
|
def write_results(result: dict, path: Path) -> None:
|
|
path.write_text(json.dumps(result, indent=2) + "\n", encoding="utf-8")
|
|
|
|
|
|
def main() -> int:
|
|
input_path = Path(sys.argv[1]) if len(sys.argv) > 1 else HERE / "input.yaml"
|
|
output_path = Path(sys.argv[2]) if len(sys.argv) > 2 else input_path.with_name("results.json")
|
|
with input_path.open(encoding="utf-8") as handle:
|
|
inp = yaml.safe_load(handle)
|
|
result = compute(inp)
|
|
write_results(result, output_path)
|
|
print(output_path)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|