Formula (extracted LaTeX)
\[= (sel, root=document) => Array.from(root.querySelectorAll(sel)); const clamp = (v,min,max)=> Math.max(min, Math.min(max, v)); // Elements const state = { units: 'us', shape: 'rect', tieType: 'tied', steelMode: 'pct' }; const el = { // groups dimRect1: $('#dim-rect'), dimRect2: $('#dim-rect-2'), dimCirc: $('#dim-circ'), groupRho: $('#group-rho'), groupAs: $('#group-As'), // inputs b: $('#b'), h: $('#h'), D: $('#D'), fc: $('#fc'), fy: $('#fy'), rho: $('#rho'), As: $('#As'), cover: $('#cover'), db: $('#db'), Pu: $('#Pu'), Mux: $('#Mux'), Muy: $('#Muy'), // units spans u: { b: $('#unit-b'), h: $('#unit-h'), D: $('#unit-D'), fc: $('#unit-fc'), fy: $('#unit-fy'), As: $('#unit-As'), cover: $('#unit-cover'), db: $('#unit-db'), Pu: $('#unit-Pu'), Mu: $('#unit-Mu'), Mu2: $('#unit-Mu2') }, // results resAg: $('#resAg'), resAs: $('#resAs'), resPhi: $('#resPhi'), resPhiP0: $('#resPhiP0'), resPhiMnx0: $('#resPhiMnx0'), resPhiMny0: $('#resPhiMny0'), resR: $('#resR'), resU: $('#resU'), resStatus: $('#resStatus'), // buttons calcBtn: $('#calcBtn'), resetBtn: $('#resetBtn') }; // Accessible tooltips\]
= (sel, root=document) => Array.from(root.querySelectorAll(sel)); const clamp = (v,min,max)=> Math.max(min, Math.min(max, v)); // Elements const state = { units: 'us', shape: 'rect', tieType: 'tied', steelMode: 'pct' }; const el = { // groups dimRect1: $('#dim-rect'), dimRect2: $('#dim-rect-2'), dimCirc: $('#dim-circ'), groupRho: $('#group-rho'), groupAs: $('#group-As'), // inputs b: $('#b'), h: $('#h'), D: $('#D'), fc: $('#fc'), fy: $('#fy'), rho: $('#rho'), As: $('#As'), cover: $('#cover'), db: $('#db'), Pu: $('#Pu'), Mux: $('#Mux'), Muy: $('#Muy'), // units spans u: { b: $('#unit-b'), h: $('#unit-h'), D: $('#unit-D'), fc: $('#unit-fc'), fy: $('#unit-fy'), As: $('#unit-As'), cover: $('#unit-cover'), db: $('#unit-db'), Pu: $('#unit-Pu'), Mu: $('#unit-Mu'), Mu2: $('#unit-Mu2') }, // results resAg: $('#resAg'), resAs: $('#resAs'), resPhi: $('#resPhi'), resPhiP0: $('#resPhiP0'), resPhiMnx0: $('#resPhiMnx0'), resPhiMny0: $('#resPhiMny0'), resR: $('#resR'), resU: $('#resU'), resStatus: $('#resStatus'), // buttons calcBtn: $('#calcBtn'), resetBtn: $('#resetBtn') }; // Accessible tooltips
Formula (extracted LaTeX)
\[('input, select').forEach(inp=>{ inp.addEventListener('blur', ()=> validateField(inp)); }); // Conversions const conv = { // Return consistent internal units: // US: in, kip, psi; Metric: mm, kN, MPa lenToIn: (x) => state.units==='us' ? x : x * 0.0393700787, inToLen: (x) => state.units==='us' ? x : x / 0.0393700787, areaToIn2: (x) => state.units==='us' ? x : x * (0.0393700787**2), // Forces: kip vs kN forceToKip: (x) => state.units==='us' ? x : x * 0.22480894387, // kN to kip // Moments: kip-ft vs kN-m momentToKipFt: (x) => state.units==='us' ? x : x * 0.737562149, // kN-m to kip-ft // Stresses: psi vs MPa fcToPsi: (x) => state.units==='us' ? x : x * 145.0377377, // MPa to psi fyToPsi: (x) => state.units==='us' ? x*1000 : x * 145.0377377 // ksi to psi if US; MPa to psi if metric }; // Calculation core function compute(){ if(!validateAll(true)) return; // Read inputs (convert to internal US units: in, psi, kip, kip-ft) const shape = state.shape; const tied = state.tieType === 'tied'; const b_in = shape==='rect' ? conv.lenToIn(Number(el.b.value)) : null; const h_in = shape==='rect' ? conv.lenToIn(Number(el.h.value)) : null; const D_in = shape==='circ' ? conv.lenToIn(Number(el.D.value)) : null; const fc_psi = conv.fcToPsi(Number(el.fc.value)); const fy_psi = conv.fyToPsi(Number(el.fy.value)); // psi const cover_in = conv.lenToIn(Number(el.cover.value)); const db_in = conv.lenToIn(Number(el.db.value)); const dPrime = cover_in + db_in/2; const Pu_kip = conv.forceToKip(Number(el.Pu.value)); const Mux_kipft = conv.momentToKipFt(Number(el.Mux.value)); const Muy_kipft = conv.momentToKipFt(Number(el.Muy.value)); let Ag_in2 = 0; if(shape==='rect'){ Ag_in2 = b_in * h_in; } else { Ag_in2 = Math.PI * (D_in**2) / 4; } let As_in2 = 0; if(state.steelMode === 'pct'){ const rho = Number(el.rho.value)/100; As_in2 = rho * Ag_in2; } else { As_in2 = state.units==='us' ? Number(el.As.value) : conv.areaToIn2(Number(el.As.value)); } // Strength reduction factor const phi = tied ? 0.65 : 0.75; // Concentric nominal axial strength const P0n_kip = (0.85*fc_psi*(Ag_in2 - As_in2) + fy_psi*As_in2) / 1000.0; // psi*in^2 -> pounds -> /1000 = kips const phiP0 = phi * P0n_kip; // Pure bending nominal strengths (approximate) // Use As,t = As/2 (symmetric), singly reinforced approximation const As_t = As_in2 / 2; let Mnx0_kipin = 0; let Mny0_kipin = 0; if(shape==='rect'){ // About x: compression width b, depth h const bx = b_in, hx = h_in; const dx = hx - dPrime; const ax = (As_t * fy_psi) / (0.85 * fc_psi * Math.max(bx, 1e-9)); Mnx0_kipin = As_t * fy_psi * Math.max(dx - ax/2, 0) / 1000; // kip-in // About y: compression width h, depth b const by = h_in, hy = b_in; const dy = hy - dPrime; const ay = (As_t * fy_psi) / (0.85 * fc_psi * Math.max(by, 1e-9)); Mny0_kipin = As_t * fy_psi * Math.max(dy - ay/2, 0) / 1000; // kip-in } else { // Circular: equivalent rectangular width 0.85D; depth D const beff = 0.85 * D_in; const d = D_in - dPrime; const a = (As_t * fy_psi) / (0.85 * fc_psi * Math.max(beff, 1e-9)); const Mn = As_t * fy_psi * Math.max(d - a/2, 0) / 1000; // kip-in Mnx0_kipin = Mn; Mny0_kipin = Mn; } // Convert nominal moments to kip-ft const Mnx0_kipft = Mnx0_kipin / 12; const Mny0_kipft = Mny0_kipin / 12; const phiMnx0 = phi * Mnx0_kipft; const phiMny0 = phi * Mny0_kipft; // Bresler exponent const n = phiP0 > 0 ? Pu_kip / phiP0 : 1; const r = clamp(2 - n, 1, 2); // Interaction sides const left = Math.pow(phiMnx0>0 ? (Mux_kipft/phiMnx0) : Infinity, r) + Math.pow(phiMny0>0 ? (Muy_kipft/phiMny0) : Infinity, r); const right = Math.pow(Math.max(1 - (phiP0>0 ? Pu_kip/phiP0 : 1), 0), r); let U = left / (right>0 ? right : 1e-9); if(!isFinite(U)) U = 999; // Present results in chosen units for user function fmt(val, unit){ if(!isFinite(val)) return '—'; const abs = Math.abs(val); const digits = abs >= 1000 ? 0 : abs >= 100 ? 1 : 2; return `${val.toFixed(digits)} ${unit}`; } // Output conversions back to UI units // Areas const Ag_disp = state.units==='us' ? Ag_in2 : Ag_in2 / (0.0393700787**2); const As_disp = state.units==='us' ? As_in2 : As_in2 / (0.0393700787**2); el.resAg.textContent = fmt(Ag_disp, state.units==='us' ? 'in²' : 'mm²'); el.resAs.textContent = fmt(As_disp, state.units==='us' ? 'in²' : 'mm²'); el.resPhi.textContent = phi.toFixed(2); // Axial capacity const phiP0_disp = state.units==='us' ? phiP0 : phiP0 / 0.22480894387; // kip -> kN el.resPhiP0.textContent = fmt(phiP0_disp, state.units==='us' ? 'kip' : 'kN'); // Moments const phiMnx0_disp = state.units==='us' ? phiMnx0 : phiMnx0 / 0.737562149; // kip-ft -> kN-m const phiMny0_disp = state.units==='us' ? phiMny0 : phiMny0 / 0.737562149; el.resPhiMnx0.textContent = fmt(phiMnx0_disp, state.units==='us' ? 'kip-ft' : 'kN-m'); el.resPhiMny0.textContent = fmt(phiMny0_disp, state.units==='us' ? 'kip-ft' : 'kN-m'); el.resR.textContent = isFinite(r) ? r.toFixed(2) : '—'; el.resU.textContent = isFinite(U) ? (U>100 ? '>100' : U.toFixed(2)) : '—'; // Status badge const badge = document.createElement('span'); badge.className = `badge ${U <= 1 ? 'pass' : 'fail'}`; badge.textContent = U <= 1 ? 'PASS (U ≤ 1.0)' : 'FAIL (U > 1.0)'; el.resStatus.innerHTML = ''; el.resStatus.appendChild(badge); } // Reset function reset(){ // Clear only numeric inputs; keep toggles [el.b, el.h, el.D, el.fc, el.fy, el.rho, el.As, el.cover, el.db, el.Pu, el.Mux, el.Muy].forEach(inp=>{ if(!inp) return; if(inp === el.rho) { inp.value = 2.0; return; } if(inp === el.cover) { inp.value = state.units==='us' ? 1.5 : 40; return; } if(inp === el.db) { inp.value = state.units==='us' ? 1.0 : 25; return; } inp.value = ''; clearError(inp); }); // Clear results [el.resAg, el.resAs, el.resPhi, el.resPhiP0, el.resPhiMnx0, el.resPhiMny0, el.resR, el.resU].forEach(n=> n.textContent='—'); el.resStatus.innerHTML = '<span class="badge">—</span>'; } // Attach el.calcBtn.addEventListener('click', compute); el.resetBtn.addEventListener('click', reset); // Recompute on change for responsiveness (without spamming errors)\]
('input, select').forEach(inp=>{ inp.addEventListener('blur', ()=> validateField(inp)); }); // Conversions const conv = { // Return consistent internal units: // US: in, kip, psi; Metric: mm, kN, MPa lenToIn: (x) => state.units==='us' ? x : x * 0.0393700787, inToLen: (x) => state.units==='us' ? x : x / 0.0393700787, areaToIn2: (x) => state.units==='us' ? x : x * (0.0393700787**2), // Forces: kip vs kN forceToKip: (x) => state.units==='us' ? x : x * 0.22480894387, // kN to kip // Moments: kip-ft vs kN-m momentToKipFt: (x) => state.units==='us' ? x : x * 0.737562149, // kN-m to kip-ft // Stresses: psi vs MPa fcToPsi: (x) => state.units==='us' ? x : x * 145.0377377, // MPa to psi fyToPsi: (x) => state.units==='us' ? x*1000 : x * 145.0377377 // ksi to psi if US; MPa to psi if metric }; // Calculation core function compute(){ if(!validateAll(true)) return; // Read inputs (convert to internal US units: in, psi, kip, kip-ft) const shape = state.shape; const tied = state.tieType === 'tied'; const b_in = shape==='rect' ? conv.lenToIn(Number(el.b.value)) : null; const h_in = shape==='rect' ? conv.lenToIn(Number(el.h.value)) : null; const D_in = shape==='circ' ? conv.lenToIn(Number(el.D.value)) : null; const fc_psi = conv.fcToPsi(Number(el.fc.value)); const fy_psi = conv.fyToPsi(Number(el.fy.value)); // psi const cover_in = conv.lenToIn(Number(el.cover.value)); const db_in = conv.lenToIn(Number(el.db.value)); const dPrime = cover_in + db_in/2; const Pu_kip = conv.forceToKip(Number(el.Pu.value)); const Mux_kipft = conv.momentToKipFt(Number(el.Mux.value)); const Muy_kipft = conv.momentToKipFt(Number(el.Muy.value)); let Ag_in2 = 0; if(shape==='rect'){ Ag_in2 = b_in * h_in; } else { Ag_in2 = Math.PI * (D_in**2) / 4; } let As_in2 = 0; if(state.steelMode === 'pct'){ const rho = Number(el.rho.value)/100; As_in2 = rho * Ag_in2; } else { As_in2 = state.units==='us' ? Number(el.As.value) : conv.areaToIn2(Number(el.As.value)); } // Strength reduction factor const phi = tied ? 0.65 : 0.75; // Concentric nominal axial strength const P0n_kip = (0.85*fc_psi*(Ag_in2 - As_in2) + fy_psi*As_in2) / 1000.0; // psi*in^2 -> pounds -> /1000 = kips const phiP0 = phi * P0n_kip; // Pure bending nominal strengths (approximate) // Use As,t = As/2 (symmetric), singly reinforced approximation const As_t = As_in2 / 2; let Mnx0_kipin = 0; let Mny0_kipin = 0; if(shape==='rect'){ // About x: compression width b, depth h const bx = b_in, hx = h_in; const dx = hx - dPrime; const ax = (As_t * fy_psi) / (0.85 * fc_psi * Math.max(bx, 1e-9)); Mnx0_kipin = As_t * fy_psi * Math.max(dx - ax/2, 0) / 1000; // kip-in // About y: compression width h, depth b const by = h_in, hy = b_in; const dy = hy - dPrime; const ay = (As_t * fy_psi) / (0.85 * fc_psi * Math.max(by, 1e-9)); Mny0_kipin = As_t * fy_psi * Math.max(dy - ay/2, 0) / 1000; // kip-in } else { // Circular: equivalent rectangular width 0.85D; depth D const beff = 0.85 * D_in; const d = D_in - dPrime; const a = (As_t * fy_psi) / (0.85 * fc_psi * Math.max(beff, 1e-9)); const Mn = As_t * fy_psi * Math.max(d - a/2, 0) / 1000; // kip-in Mnx0_kipin = Mn; Mny0_kipin = Mn; } // Convert nominal moments to kip-ft const Mnx0_kipft = Mnx0_kipin / 12; const Mny0_kipft = Mny0_kipin / 12; const phiMnx0 = phi * Mnx0_kipft; const phiMny0 = phi * Mny0_kipft; // Bresler exponent const n = phiP0 > 0 ? Pu_kip / phiP0 : 1; const r = clamp(2 - n, 1, 2); // Interaction sides const left = Math.pow(phiMnx0>0 ? (Mux_kipft/phiMnx0) : Infinity, r) + Math.pow(phiMny0>0 ? (Muy_kipft/phiMny0) : Infinity, r); const right = Math.pow(Math.max(1 - (phiP0>0 ? Pu_kip/phiP0 : 1), 0), r); let U = left / (right>0 ? right : 1e-9); if(!isFinite(U)) U = 999; // Present results in chosen units for user function fmt(val, unit){ if(!isFinite(val)) return '—'; const abs = Math.abs(val); const digits = abs >= 1000 ? 0 : abs >= 100 ? 1 : 2; return `${val.toFixed(digits)} ${unit}`; } // Output conversions back to UI units // Areas const Ag_disp = state.units==='us' ? Ag_in2 : Ag_in2 / (0.0393700787**2); const As_disp = state.units==='us' ? As_in2 : As_in2 / (0.0393700787**2); el.resAg.textContent = fmt(Ag_disp, state.units==='us' ? 'in²' : 'mm²'); el.resAs.textContent = fmt(As_disp, state.units==='us' ? 'in²' : 'mm²'); el.resPhi.textContent = phi.toFixed(2); // Axial capacity const phiP0_disp = state.units==='us' ? phiP0 : phiP0 / 0.22480894387; // kip -> kN el.resPhiP0.textContent = fmt(phiP0_disp, state.units==='us' ? 'kip' : 'kN'); // Moments const phiMnx0_disp = state.units==='us' ? phiMnx0 : phiMnx0 / 0.737562149; // kip-ft -> kN-m const phiMny0_disp = state.units==='us' ? phiMny0 : phiMny0 / 0.737562149; el.resPhiMnx0.textContent = fmt(phiMnx0_disp, state.units==='us' ? 'kip-ft' : 'kN-m'); el.resPhiMny0.textContent = fmt(phiMny0_disp, state.units==='us' ? 'kip-ft' : 'kN-m'); el.resR.textContent = isFinite(r) ? r.toFixed(2) : '—'; el.resU.textContent = isFinite(U) ? (U>100 ? '>100' : U.toFixed(2)) : '—'; // Status badge const badge = document.createElement('span'); badge.className = `badge ${U <= 1 ? 'pass' : 'fail'}`; badge.textContent = U <= 1 ? 'PASS (U ≤ 1.0)' : 'FAIL (U > 1.0)'; el.resStatus.innerHTML = ''; el.resStatus.appendChild(badge); } // Reset function reset(){ // Clear only numeric inputs; keep toggles [el.b, el.h, el.D, el.fc, el.fy, el.rho, el.As, el.cover, el.db, el.Pu, el.Mux, el.Muy].forEach(inp=>{ if(!inp) return; if(inp === el.rho) { inp.value = 2.0; return; } if(inp === el.cover) { inp.value = state.units==='us' ? 1.5 : 40; return; } if(inp === el.db) { inp.value = state.units==='us' ? 1.0 : 25; return; } inp.value = ''; clearError(inp); }); // Clear results [el.resAg, el.resAs, el.resPhi, el.resPhiP0, el.resPhiMnx0, el.resPhiMny0, el.resR, el.resU].forEach(n=> n.textContent='—'); el.resStatus.innerHTML = '<span class="badge">—</span>'; } // Attach el.calcBtn.addEventListener('click', compute); el.resetBtn.addEventListener('click', reset); // Recompute on change for responsiveness (without spamming errors)