Resources Numerical accuracy Calculation policy

Concrete member strength to ACI 318-19

The design strengths of a rectangular reinforced concrete section in bending, shear and combined axial force and bending.

How the precision is kept

The formulas are the code's, in 64-bit numbers, with the SI coefficients the code prints. The axial force and moment diagram is a polygon through 121 sampled neutral axis depths plus the named points, and a load is checked against straight lines between them. The required steel formula subtracts nearly equal numbers for a small moment.

Open item. Compute the required steel as 2 Rn b d ÷ (fy (1 + √(1 − 2 Rn ÷ 0.85 f′c))), which is the same value without the subtraction of nearly equal numbers.

Calculations under this policy

9 calculations in 1 source file. The code is read from the released app when this page loads. It is the calculation people run, not a copy kept for this page.

frame/rc-aci318.js CadCraft 0.8.2 64-bit 9 calculations Reviewed

Tests tools/frame/test-rc.mjs

Stress block factor β₁

64-bit

The depth of the equivalent stress block as a share of the neutral axis depth.

0.85 for f′c ≤ 28; 0.85 − 0.05 (f′c − 28) ÷ 7; 0.65 for f′c ≥ 55

One linear expression between the two limits, with the code's own numbers.

  • frame/rc-aci318.js
  • lines 44 to 48
  • CadCraft 0.8.2
export function beta1(fc) {
  if (fc <= 28) return 0.85;
  if (fc >= 55) return 0.65;
  return 0.85 - 0.05 * (fc - 28) / 7;
}

Strength reduction factor

64-bit

The factor φ for axial force and bending from the strain in the extreme tension steel.

0.90 for ε_t ≥ ε_ty + 0.003; 0.65 (0.75 spiral) for ε_t ≤ ε_ty; a straight line between

The limits are compared without a tolerance here; the flexure function adds its own 1e-12 allowance when it reports whether a section is tension-controlled.

  • frame/rc-aci318.js
  • lines 49 to 54
  • CadCraft 0.8.2
export function phiAxialFlexure(epsT, epsTy, spiral = false) {
  const lo = spiral ? 0.75 : 0.65;
  if (epsT >= epsTy + 0.003) return 0.9;
  if (epsT <= epsTy) return lo;
  return lo + (0.9 - lo) * (epsT - epsTy) / 0.003;
}

Square root of the concrete strength in shear

64-bit

The √f′c used in the shear formulas.

min(√f′c, 8.3)

The cap of 8.3 MPa is the code's limit in 22.5.3.1.

  • frame/rc-aci318.js
  • line 56
  • CadCraft 0.8.2
const sqrtFc = (fc) => Math.min(Math.sqrt(fc), 8.3);

Bending strength of a beam section

64-bit

The nominal and design moment of a section at zero axial force, with the minimum steel and ductility tests.

c from P(c) = 0; Mn = M(c); φMn; As,min = max(0.25 √f′c ÷ fy, 1.4 ÷ fy) b d

The neutral axis comes from the bisection, so Mn carries its 1e-12 stopping tolerance. The minimum steel test allows 1e-9 mm² and the strain tests 1e-12, both absolute.

  • frame/rc-aci318.js
  • lines 60 to 75
  • CadCraft 0.8.2
export function beamFlexure(o) {
  const m = material(o), L = sectionLayers(o);
  const c = neutralAxisForP(L, 0, m);
  if (c === null) return { ok: false, why: 'no-equilibrium' };
  const f = forcesAt(L, c, m);
  const epsTy = m.fy / m.Es;
  const phi = phiAxialFlexure(f.epsT, epsTy, false);
  const As = L.layers.filter((l) => l.d > f.c).reduce((s, l) => s + l.As, 0);
  const d = As ? L.layers.filter((l) => l.d > f.c).reduce((s, l) => s + l.As * l.d, 0) / As : f.dt;   // centroid of the tension steel
  const AsMin = Math.max(0.25 * Math.sqrt(o.fc) / o.fy, 1.4 / o.fy) * L.width * d;
  return {
    ok: true, Mn: f.M, phi, phiMn: phi * f.M, c: f.c, a: f.a, epsT: f.epsT, dt: f.dt, d, epsTy, As, AsMin, AsMinOk: As >= AsMin - 1e-9,
    tensionControlled: f.epsT >= epsTy + 0.003 - 1e-12, ductile: f.epsT >= 0.004 - 1e-12, steel: f.steel, beta1: m.beta1,
    clauses: ['ACI 318-19 22.2', 'ACI 318-19 Table 21.2.2', 'ACI 318-19 9.3.3.1', 'ACI 318-19 9.6.1.2'],
  };
}

Steel required for a moment

64-bit

The steel area a singly reinforced section needs for a factored moment.

Rn = Mu ÷ (φ b d²); As = (0.85 f′c ÷ fy) (1 − √(1 − 2 Rn ÷ 0.85 f′c)) b d

For a small moment the square root is close to 1 and 1 − √(…) subtracts two nearly equal numbers, so the required area loses digits. A section too small for the moment returns nothing.

  • frame/rc-aci318.js
  • lines 77 to 82
  • CadCraft 0.8.2
export function requiredAs({ b, d, fc, fy, Mu, phi = 0.9 }) {
  const Rn = Mu / (phi * b * d * d);
  const disc = 1 - 2 * Rn / (0.85 * fc);
  if (disc < 0) return null;
  return 0.85 * fc / fy * (1 - Math.sqrt(disc)) * b * d;
}

One-way shear strength

64-bit

The concrete and stirrup contributions to shear strength, the minimum stirrups and the spacing limit.

Vc by Table 22.5.5.1 (a), (b) or (c); λs = min(1, √(2 ÷ (1 + 0.004 d))); Vs = Av fyt d ÷ s; φVn = 0.75 (Vc + Vs)

Closed-form expressions with the code's SI coefficients (0.17, 0.66, 0.42, 0.083, 0.062, 0.35). The cube root is Math.cbrt. Comparisons with limits allow 1e-9 in N, mm² or mm, absolute.

  • frame/rc-aci318.js
  • lines 84 to 106
  • CadCraft 0.8.2
export function beamShear({ bw, d, h, fc, fyt, Av = 0, s = 0, Vu = 0, Nu = 0, As = 0, lambda = 1, Ag = bw * h }) {
  const fytUse = Math.min(fyt, 420);
  const rf = sqrtFc(fc);
  const AvMin = s > 0 ? Math.max(0.062 * Math.sqrt(fc), 0.35) * bw * s / fytUse : Infinity;
  const hasMin = Av > 0 && s > 0 && Av >= AvMin - 1e-9;
  const rho = Math.max(As / (bw * d), 0);
  const axial = Math.min(Nu / (6 * Ag), 0.05 * fc);                 // Nu compression +; tension negative (not capped below)
  const lamS = Math.min(1, Math.sqrt(2 / (1 + 0.004 * d)));
  let Vc, eq;
  if (hasMin) {
    const a = (0.17 * lambda * rf + axial) * bw * d, b = (0.66 * lambda * Math.cbrt(rho) * rf + axial) * bw * d;
    Vc = Math.max(a, b); eq = a >= b ? '(a)' : '(b)';
  } else { Vc = (0.66 * lamS * lambda * Math.cbrt(rho) * rf + axial) * bw * d; eq = '(c)'; }
  Vc = Math.max(0, Math.min(Vc, 0.42 * lambda * rf * bw * d));
  const Vs = Av > 0 && s > 0 ? Av * fytUse * d / s : 0;
  const Vn = Vc + Vs, phiVn = PHI_SHEAR * Vn;
  const VsMax = 0.66 * rf * bw * d;                                  // 22.5.1.2 as a limit on Vs
  const sizeOk = Math.abs(Vu) <= PHI_SHEAR * (Vc + VsMax) + 1e-9;
  const AvMinNeeded = Math.abs(Vu) > PHI_SHEAR * 0.083 * lambda * rf * bw * d;
  const sMax = Vs > 0.33 * rf * bw * d ? Math.min(d / 4, 300) : Math.min(d / 2, 600);
  return { Vc, Vs, Vn, phiVn, eq, lamS, rho, AvMin, hasMin, AvMinNeeded, AvMinOk: !AvMinNeeded || hasMin, sMax, sOk: !(s > 0) || s <= sMax + 1e-9, sizeOk, fytUse,
    clauses: ['ACI 318-19 22.5.1.1', 'ACI 318-19 Table 22.5.5.1', 'ACI 318-19 22.5.8.5.3', 'ACI 318-19 22.5.1.2', 'ACI 318-19 9.6.3.1', 'ACI 318-19 9.6.3.4', 'ACI 318-19 9.7.6.2.2'] };
}

Axial force and moment diagram

64-bit

The nominal and design strength outline of a column section for bending about one axis.

(Mn, Pn) at 121 depths c from 20 h down to 0.001 h, plus the balanced, tension-controlled and P = 0 points; Po = 0.85 f′c (Ag − Ast) + fy Ast

Each point is exact strain compatibility for its depth; the outline between points is a straight line. The depths are spaced by a constant ratio. Design axial strength is capped at φ times 0.80 Po (0.85 with a spiral).

  • frame/rc-aci318.js
  • lines 108 to 133
  • CadCraft 0.8.2
export function interaction({ b, h, bars, layers, fc, fy, Es = ES, axis = 'y', spiral = false, n = 120 }) {
  const m = material({ fc, fy, Es });
  const L = layers ? { depth: h, width: b, layers } : layersFor({ b, h, bars }, axis, 1);
  const Ast = L.layers.reduce((s, l) => s + l.As, 0), Ag = b * h;
  const Po = 0.85 * fc * (Ag - Ast) + fy * Ast;
  const PnMax = (spiral ? 0.85 : 0.8) * Po;
  const lo = spiral ? 0.75 : 0.65, epsTy = fy / m.Es;
  const dt = Math.max(...L.layers.map((l) => l.d));
  const pts = [];
  // c from deep (nearly pure compression) to shallow, geometric, plus the named points
  const cs = new Set();
  for (let k = 0; k <= n; k++) cs.add(L.depth * 20 * Math.pow(1e-3 / 20, k / n));
  cs.add(dt * 0.003 / (0.003 + epsTy));                              // balanced (εt = εty)
  cs.add(dt * 0.003 / (0.006 + epsTy));                              // tension-controlled limit (εt = εty + 0.003)
  const c0 = neutralAxisForP(L, 0, m);
  if (c0) cs.add(c0);
  for (const c of [...cs].sort((x, y) => y - x)) {
    const f = forcesAt(L, c, m);
    const phi = phiAxialFlexure(f.epsT, epsTy, spiral);
    pts.push({ c, Pn: f.P, Mn: f.M, phi, phiPn: Math.min(phi * f.P, lo * PnMax), phiMn: phi * f.M, epsT: f.epsT, capped: phi * f.P > lo * PnMax });
  }
  const Pnt = -fy * Ast;
  pts.push({ c: 0, Pn: Pnt, Mn: 0, phi: 0.9, phiPn: 0.9 * Pnt, phiMn: 0, epsT: Infinity, capped: false });
  return { points: pts, Po, PnMax, phiPnMax: lo * PnMax, Pnt, phiPnt: 0.9 * Pnt, Ast, Ag, axis, spiral,
    clauses: ['ACI 318-19 22.4.2.1', 'ACI 318-19 22.4.2.2', 'ACI 318-19 22.4.3.1', 'ACI 318-19 Table 21.2.2', 'ACI 318-19 22.2'] };
}

Utilization on the diagram

64-bit

How far a factored axial force and moment are along the ray from the origin to the diagram.

ratio = √(Mu² + Pu²) ÷ t, t = where the ray meets the outline

The ray's direction is rebuilt from the angle atan2(Pu, Mu) with a cosine and a sine. A segment nearly parallel to the ray is skipped when the cross product is below 1e-18, an absolute limit. A load below 1e-12 in size returns 0.

  • frame/rc-aci318.js
  • lines 135 to 152
  • CadCraft 0.8.2
/** Utilisation of (Pu, Mu) against the φ diagram: |(Mu, Pu)| over the distance to the diagram along the same ray. */
export function pmRatio(D, Pu, Mu) {
  const M = Math.abs(Mu);
  // the closed φ outline: (0, φPn,max cap) … (φMn, φPn) … (0, φPnt), polar about the origin
  const poly = [{ x: 0, y: D.phiPnMax }, ...D.points.map((p) => ({ x: p.phiMn, y: p.phiPn }))];
  if (Math.hypot(M, Pu) < 1e-12) return 0;
  const ang = Math.atan2(Pu, M);
  for (let k = 0; k + 1 < poly.length; k++) {
    const A = poly[k], B = poly[k + 1];
    // ray t·(cos, sin) meets segment A + s (B − A)
    const dx = Math.cos(ang), dy = Math.sin(ang), ex = B.x - A.x, ey = B.y - A.y;
    const den = dx * ey - dy * ex;
    if (Math.abs(den) < 1e-18) continue;
    const t = (A.x * ey - A.y * ex) / den, s = (A.x * dy - A.y * dx) / den;
    if (t > 0 && s >= -1e-12 && s <= 1 + 1e-12) return Math.hypot(M, Pu) / t;
  }
  return Infinity;
}

Threshold torsion

64-bit

The torque above which torsion would have to be designed for.

φ Tth = 0.75 × 0.083 λ √f′c Acp² ÷ pcp

One product with the code's SI coefficient 0.083.

  • frame/rc-aci318.js
  • lines 154 to 157
  • CadCraft 0.8.2
export function torsionThreshold({ b, h, fc, lambda = 1 }) {
  const Acp = b * h, pcp = 2 * (b + h);
  return PHI_SHEAR * 0.083 * lambda * sqrtFc(fc) * Acp * Acp / pcp;
}

In detail

Method
ACI 318-19 (SI): 22.2 strain compatibility, Table 21.2.2 strength reduction, 22.4 axial strength, 9.6.1.2 minimum steel, 22.5 one-way shear, 22.7.4.1 threshold torsion. Each result carries its clauses.
Number types
64-bit numbers. Units mm, N, MPa, N·mm.
Tolerances
Comparisons allow 1e-9 on areas, forces and spacings and 1e-12 on strains (absolute). The ray test on the diagram skips a segment when the cross product is below 1e-18 and accepts a hit within 1e-12 of a segment's ends.
Limits
Rectangular nonprestressed sections. √f′c is capped at 8.3 MPa in shear. Between two sampled points the diagram is a straight line.

Approach: 64-bit, stated limit

The arithmetic is 64-bit, but the method or the data sets the accuracy: a solver tolerance, a mesh, a step size, a datum shift, a table. The limit is stated where the result is shown.

Every policy that takes this approach