Resources Numerical accuracy Calculation policy

Forces and deflection along a member

The axial force, shears, torque, bending moments and deflected shape along each member, and the largest values the report and the design checks read.

How the precision is kept

Internal forces at a cut are exact statics from the member's end forces and the loads up to the cut, in 64-bit numbers. The deflection is the curvature integrated twice by the trapezoid rule on a grid 16 times finer than the stations. Largest values are the largest of the station values, so the number of stations sets how closely a peak between two stations is caught.

Open item. Add the points of zero shear and the point load positions to the stations, so the reported maximum moment is the true one and not the largest station value.

Calculations under this policy

4 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/frame-solve.js CadCraft 0.8.2 64-bit 4 calculations Reviewed

Tests bin/test-frame.mjs

Internal forces at a cut

64-bit

N, Vy, Vz, T, My and Mz at a distance x from the member's start.

S = −(F_i + ∫₀ˣ q); M = −(M_i + r × F_i + Σ r × q)

The distributed part is integrated by four Gauss points from the load's start to the cut each time; the integrand is at most quadratic, so the rule is exact up to rounding. A point load is counted when it lies more than 1e-9 mm before the cut, or within 1e-9 mm of it at the member's far end.

  • frame/frame-solve.js
  • lines 481 to 498
  • CadCraft 0.8.2
const at = (x) => {
  const S = [-end[0], -end[1], -end[2]];
  const Ms = [-end[3], -(end[4] + x * end[2]), -(end[5] - x * end[1])];
  for (const pz of loads) {
    const c = pz.comp;
    const force = (s, q) => {   // q along local axis c at s ≤ x; r = (s − x, 0, 0)
      S[c] -= q;
      if (c === 1) Ms[2] -= (s - x) * q;
      else if (c === 2) Ms[1] += (s - x) * q;
    };
    if (pz.kind === 'point') { if (pz.a < x - 1e-9 || (pz.a <= x + 1e-9 && x >= L - 1e-9)) force(pz.a, pz.P); continue; }
    const a = pz.a, b = Math.min(pz.b, x);
    if (b <= a) continue;
    const h = (b - a) / 2;
    for (const [g, wt] of GAUSS4) { const s = a + h * (g + 1); force(s, (pz.w1 + (pz.w2 - pz.w1) * (s - pz.a) / (pz.b - pz.a)) * wt * h); }
  }
  return { N: S[0], Vy: S[1], Vz: S[2], T: Ms[0], My: -Ms[1], Mz: Ms[2], MSy: Ms[1], MSz: Ms[2] };
};

Deflection along the member

64-bit

The member's displacement between its ends, from its curvature.

v″ = M_z ÷ (E I_z); w″ = −M_y ÷ (E I_y); u′ = N ÷ (E A); trapezoids, twice

The grid has max(8, n) × 16 intervals, so 640 for the report's 40 stations. The trapezoid rule is not exact for the curved moment diagram of a loaded member; its error falls with the square of the grid spacing. The integration constants are fixed by making both ends match the node displacements.

  • frame/frame-solve.js
  • lines 500 to 515
  • CadCraft 0.8.2
const nf = Math.max(8, n) * 16;
const xs = Array.from({ length: nf + 1 }, (_, k) => L * k / nf);
const acts = xs.map(at);
const integrate2 = (kappa) => { const th = [0], d = [0]; for (let k = 1; k <= nf; k++) { th.push(th[k - 1] + (kappa[k - 1] + kappa[k]) / 2 * (L / nf)); d.push(d[k - 1] + (th[k - 1] + th[k]) / 2 * (L / nf)); } return d; };
const integrate1 = (f) => { const d = [0]; for (let k = 1; k <= nf; k++) d.push(d[k - 1] + (f[k - 1] + f[k]) / 2 * (L / nf)); return d; };
const loc = (nd) => {
  const u = R.u.subarray(6 * nd, 6 * nd + 6), T = e.T;
  return [0, 1, 2].map((a) => T[a * 3] * u[0] + T[a * 3 + 1] * u[1] + T[a * 3 + 2] * u[2])
    .concat([0, 1, 2].map((a) => T[a * 3] * u[3] + T[a * 3 + 1] * u[4] + T[a * 3 + 2] * u[5]));
};
const ui = loc(e.i), uj = loc(e.j);
const dv = integrate2(acts.map((a) => a.MSz / (e.E * e.Iz)));
const dw = integrate2(acts.map((a) => -a.MSy / (e.E * e.Iy)));
const du = integrate1(acts.map((a) => a.N / (e.E * e.A)));
const fit = (d, a, b) => (k) => { const x = xs[k]; return a + (b - a - d[nf]) * x / L + d[k]; };
const vF = fit(dv, ui[1], uj[1]), wF = fit(dw, ui[2], uj[2]), uF = fit(du, ui[0], uj[0]);

Station values and deflection off the chord

64-bit

The values kept at each station, and how far the member bows from the straight line between its ends.

rel = √(v_rel² + w_rel²); v_rel = v − v_end × x ÷ L

Every sixteenth grid point is kept. The bow is one Math.hypot of the two transverse parts after the end value's straight line is taken off.

  • frame/frame-solve.js
  • lines 517 to 523
  • CadCraft 0.8.2
for (let k = 0; k <= nf; k += nf / n) {
  const a = acts[k], x = xs[k];
  out.x.push(x); out.N.push(a.N); out.Vy.push(a.Vy); out.Vz.push(a.Vz); out.T.push(a.T); out.My.push(a.My); out.Mz.push(a.Mz);
  out.dx.push(uF(k)); out.dy.push(vF(k)); out.dz.push(wF(k));
  const rv = dv[k] - dv[nf] * x / L, rw = dw[k] - dw[nf] * x / L;
  out.rel.push(Math.hypot(rv, rw));
}

Largest and smallest values along a member

64-bit

The maximum and minimum of each internal force, where they occur, and the largest deflection with its span ratio.

max and min over the stations; ratio = L ÷ deflection

The extremes are the largest and smallest station values, 41 stations by default; a peak between two stations is not searched for. The ratio L ÷ deflection is given when the deflection exceeds 1e-12 mm, an absolute limit.

  • frame/frame-solve.js
  • lines 527 to 541
  • CadCraft 0.8.2
/** Largest and smallest of each action along a member, and its largest deflection off the chord. */
export function memberExtremes(prep, R, m, n = 40) {
  const d = diagram(prep, R, m, n);
  const ext = {};
  for (const key of ['N', 'Vy', 'Vz', 'T', 'My', 'Mz']) {
    let max = -Infinity, min = Infinity, xMax = 0, xMin = 0;
    d[key].forEach((v, k) => { if (v > max) { max = v; xMax = d.x[k]; } if (v < min) { min = v; xMin = d.x[k]; } });
    ext[key] = { max, min, xMax, xMin, abs: Math.max(Math.abs(max), Math.abs(min)) };
  }
  let v = 0, xv = 0;
  d.rel.forEach((r, k) => { if (r > v) { v = r; xv = d.x[k]; } });
  const L = prep.mem[m].ax.L;
  ext.defl = { value: v, x: xv, ratio: v > 1e-12 ? L / v : Infinity };
  return ext;
}

In detail

Method
Statics from the i end with 4-point Gauss–Legendre quadrature for distributed loads; trapezoid rule twice for the deflection, then a straight-line correction so both ends match the node displacements.
Number types
64-bit numbers in plain arrays; end forces and displacements read from Float64Array.
Tolerances
A point load counts at a cut when it lies more than 1e-9 mm before it (absolute). The span-to-deflection ratio is given only when the deflection exceeds 1e-12 mm.
Limits
Extremes are taken at the stations only: 41 for the report, 49 for the steel checks, 25 for the concrete checks. The deflection grid has 16 intervals per station interval.

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