Use Pint and unit-free variable names in concrete-beam
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.
This commit is contained in:
parent
27a9cdd707
commit
8f91baee41
6 changed files with 176 additions and 165 deletions
|
|
@ -10,54 +10,68 @@ try:
|
|||
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 _require_positive(name: str, value: float) -> float:
|
||||
if value <= 0:
|
||||
|
||||
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 value
|
||||
return magnitude
|
||||
|
||||
|
||||
def compute(inp: dict) -> dict:
|
||||
span_ft = _require_positive("span_ft", float(inp["span_ft"]))
|
||||
tributary_ft = _require_positive("tributary_ft", float(inp["tributary_ft"]))
|
||||
D_psf = _require_positive("D_psf", float(inp["D_psf"]))
|
||||
L_psf = _require_positive("L_psf", float(inp["L_psf"]))
|
||||
bw_in = _require_positive("bw_in", float(inp["bw_in"]))
|
||||
h_in = _require_positive("h_in", float(inp["h_in"]))
|
||||
d_in = _require_positive("d_in", float(inp["d_in"]))
|
||||
fc_ksi = _require_positive("fc_ksi", float(inp["fc_ksi"]))
|
||||
fy_ksi = _require_positive("fy_ksi", float(inp["fy_ksi"]))
|
||||
As_in2 = _require_positive("As_in2", float(inp["As_in2"]))
|
||||
concrete_pcf = _require_positive("concrete_pcf", float(inp["concrete_pcf"]))
|
||||
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_klf = (bw_in * h_in / 144.0) * concrete_pcf / 1000.0
|
||||
wD_klf = D_psf * tributary_ft / 1000.0 + self_weight_klf
|
||||
wL_klf = L_psf * tributary_ft / 1000.0
|
||||
wu_klf = 1.2 * wD_klf + 1.6 * wL_klf
|
||||
Mu_kipft = wu_klf * span_ft**2 / 8.0
|
||||
Vu_kip = wu_klf * span_ft / 2.0
|
||||
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
|
||||
|
||||
fc_psi = fc_ksi * 1000.0
|
||||
fy_psi = fy_ksi * 1000.0
|
||||
a_in = As_in2 * fy_ksi / (0.85 * fc_ksi * bw_in)
|
||||
beta1 = max(0.65, min(0.85, 0.85 - 0.05 * max(0.0, (fc_psi - 4000.0) / 1000.0)))
|
||||
c_in = a_in / beta1
|
||||
et = 0.003 * (d_in - c_in) / c_in if c_in > 0 else 0.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_kipft = As_in2 * fy_ksi * (d_in - a_in / 2.0) / 12.0
|
||||
phiMn_kipft = phi * Mn_kipft
|
||||
Mn = As * fy * (d - a / 2.0) / 12.0
|
||||
phiMn = phi * Mn
|
||||
|
||||
rho_min = max(3.0 * math.sqrt(fc_psi) / fy_psi, 200.0 / fy_psi)
|
||||
As_min_in2 = rho_min * bw_in * d_in
|
||||
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_kip = 2.0 * math.sqrt(fc_psi) * bw_in * d_in / 1000.0
|
||||
phiVc_kip = 0.75 * Vc_kip
|
||||
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)
|
||||
|
|
@ -68,46 +82,46 @@ def compute(inp: dict) -> dict:
|
|||
"project": inp.get("project", ""),
|
||||
"prepared_by": inp.get("prepared_by", ""),
|
||||
"values": {
|
||||
"span_ft": q(span_ft),
|
||||
"tributary_ft": q(tributary_ft),
|
||||
"D_psf": q(D_psf),
|
||||
"L_psf": q(L_psf),
|
||||
"self_weight_klf": q(self_weight_klf),
|
||||
"wD_klf": q(wD_klf),
|
||||
"wL_klf": q(wL_klf),
|
||||
"wu_klf": q(wu_klf),
|
||||
"Mu_kipft": q(Mu_kipft),
|
||||
"Vu_kip": q(Vu_kip),
|
||||
"bw_in": q(bw_in),
|
||||
"h_in": q(h_in),
|
||||
"d_in": q(d_in),
|
||||
"fc_ksi": q(fc_ksi),
|
||||
"fy_ksi": q(fy_ksi),
|
||||
"As_in2": q(As_in2),
|
||||
"a_in": q(a_in),
|
||||
"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_kipft": q(Mn_kipft),
|
||||
"phiMn_kipft": q(phiMn_kipft),
|
||||
"As_min_in2": q(As_min_in2),
|
||||
"Vc_kip": q(Vc_kip),
|
||||
"phiVc_kip": q(phiVc_kip),
|
||||
"Mn": q(Mn),
|
||||
"phiMn": q(phiMn),
|
||||
"As_min": q(As_min),
|
||||
"Vc": q(Vc),
|
||||
"phiVc": q(phiVc),
|
||||
},
|
||||
"checks": {
|
||||
"flexure": {
|
||||
"demand": q(Mu_kipft),
|
||||
"capacity": q(phiMn_kipft),
|
||||
"ok": Mu_kipft <= phiMn_kipft,
|
||||
"demand": q(Mu),
|
||||
"capacity": q(phiMn),
|
||||
"ok": Mu <= phiMn,
|
||||
},
|
||||
"minimum_steel": {
|
||||
"demand": q(As_min_in2),
|
||||
"capacity": q(As_in2),
|
||||
"ok": As_in2 >= As_min_in2,
|
||||
"demand": q(As_min),
|
||||
"capacity": q(As),
|
||||
"ok": As >= As_min,
|
||||
},
|
||||
"shear": {
|
||||
"demand": q(Vu_kip),
|
||||
"capacity": q(phiVc_kip),
|
||||
"ok": Vu_kip <= phiVc_kip,
|
||||
"demand": q(Vu),
|
||||
"capacity": q(phiVc),
|
||||
"ok": Vu <= phiVc,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -705,28 +705,25 @@ o
|
|||
endstream
|
||||
endobj
|
||||
208 0 obj
|
||||
<</Length 4688/Filter/FlateDecode>>
|
||||
<</Length 4693/Filter/FlateDecode>>
|
||||
stream
|
||||
xœÝYtTÕ¹þöùÏžI&™ÉÌ0yBd’8’IB"bbÕÉ‹ &€ ¢„LB"I&f<12>¦(–‹VF¯i›Zj[û¸\Kéh0EÁªE¯µ@ë«õ]K<>´×‚ZŒ›®½ÏL2 ˆ®ë½«kÝ™•™}öÙûû¿ÿûÿ½÷&` | ||||