Resources Numerical accuracy Calculation policy

Foundation settlement

Works out the stress under a loaded rectangle, immediate and consolidation settlement of a layered soil, and how settlement develops with time.

How the precision is kept

64-bit arithmetic on closed-form stress formulas, summed over sub-layers of at most a chosen thickness with the stress taken at each sub-layer's middle. The time rate is a series cut at 200 terms. The unit weight of water is 9.81 kN/m³.

Open item. Use the short-time form of the consolidation series for small time factors, where 200 terms do not converge.

Calculations under this policy

10 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.

geotech.js CivilCraft 0.8.1 64-bit 10 calculations Reviewed

Tests bin/test-civilcraft-geotech.mjs

Stress influence factor under a corner

64-bit

The share of the surface load felt at a depth under the corner of a loaded rectangle.

m = a ÷ z, n = b ÷ z, v = m² + n² + 1; I = [2mn√v ÷ (v + m²n²) × (v + 1) ÷ v + atan2(2mn√v, v − m²n²)] ÷ 4π

The angle is taken with atan2, which gives the right quadrant when m²n² exceeds m² + n² + 1, so no separate correction by π is needed. At zero depth the factor is returned as 0.25. The values for m = n = 1 and m = n = 2 were recomputed for this review: 0.1752 and 0.2325.

  • geotech.js
  • lines 400 to 406
  • CivilCraft 0.8.1
/** Vertical stress increase under the corner of a uniformly loaded rectangle a × b at depth z (Newmark 1935): Δσ = q·I, I from the closed form. */
export function influenceCorner(a, b, z) {
  if (z <= 0) return 0.25;
  const m = a / z, n = b / z, m2 = m * m, n2 = n * n, v = m2 + n2 + 1, v1 = m2 * n2, den = v - v1;
  const ang = Math.atan2(2 * m * n * Math.sqrt(v), den);
  return ((2 * m * n * Math.sqrt(v)) / (v + v1) * ((v + 1) / v) + (den > 0 ? ang : ang + Math.PI * 0) ) / (4 * Math.PI);
}

Stress under a footing

64-bit

The vertical stress increase under the center or a corner of a rectangular footing.

center: Δσ = 4·q·I(B ÷ 2, L ÷ 2, z); corner: Δσ = q·I(B, L, z)

Superposition of four corner rectangles for the center. One multiplication after the influence factor.

  • geotech.js
  • lines 407 to 408
  • CivilCraft 0.8.1
/** Under the centre of a B × L footing: four corner rectangles of B/2 × L/2. Under a corner: one. */
export const stressRect = (q, B, L, z, at = 'centre') => (at === 'corner' ? q * influenceCorner(B, L, z) : 4 * q * influenceCorner(B / 2, L / 2, z));

Stress by the 2:1 spread

64-bit

The average stress increase at a depth by the quick 2:1 rule.

Δσ = q·B·L ÷ ((B + z)·(L + z))

One expression. The rule is an approximation of the average stress, not the stress under a point.

  • geotech.js
  • lines 409 to 410
  • CivilCraft 0.8.1
/** 2:1 spread: Δσ = q·B·L / ((B+z)(L+z)). */
export const stress2to1 = (q, B, L, z) => (q * B * L) / ((B + z) * (L + z));

Elastic settlement under a corner

64-bit

The settlement of the corner of a flexible loaded rectangle on an elastic half-space.

w = q·(1 − ν²) ÷ (π·E) × [a·ln((b + d) ÷ a) + b·ln((a + d) ÷ b)], d = √(a² + b²)

The diagonal is by hypot. The logarithms divide by a and by b with no guard, so a zero side divides by zero.

  • geotech.js
  • lines 412 to 416
  • CivilCraft 0.8.1
/** Elastic settlement of the corner of a flexible a × b rectangle carrying q on a half-space of modulus E and Poisson ν (Timoshenko and Goodier). */
export function elasticCorner(q, a, b, E, nu) {
  const d = Math.hypot(a, b);
  return ((q * (1 - nu * nu)) / (Math.PI * E)) * (a * Math.log((b + d) / a) + b * Math.log((a + d) / b));
}

Settlement of a layered soil

64-bit

Consolidation and immediate settlement under a footing, sub-layer by sub-layer.

clay: s = Cc·Δz ÷ (1 + e₀) × log₁₀(σ′f ÷ σ′₀), with Cs below σ′c; sand: s = Δσ ÷ Es × Δz

Each layer is cut into equal sub-layers no thicker than the step, and stress is taken at each one's middle, so the total depends on the step. The present effective stress is floored at 0.1 kPa before the logarithm. Submerged weight is the saturated weight (or the unit weight when none is given) minus 9.81. The Poisson's ratio factor in the immediate term is multiplied by zero, so it is always 1.

  • geotech.js
  • lines 420 to 464
  • CivilCraft 0.8.1
/**
 * One-dimensional settlement of a stack of layers under a footing.
 *   layers: [{ top (elevation), bottom, soil kind: 'clay'|'sand', gamma, gammaSat, cc, cs, e0, sigmaC (kPa, effective), es, nu, cv, drain }]
 *   load: { q (kPa, net), B, L, depth (footing base elevation) , at: 'centre'|'corner', method: 'boussinesq' | '2:1' }
 *   water: elevation of the water table (null = none)
 * Compressible layers (cc given) are cut into sub-layers of at most `step` metres; granular layers (es given) give immediate settlement from
 * Δσ/Es·Δz (the strain method). Returns { consolidation, immediate, total, rows: [{ z, sigma0, dsigma, s, kind, layer }] }.
 */
export function settlement({ layers, load, water = null, ground = null, step = 1 }) {
  const rows = []; let sc = 0, si = 0;
  const base = load.depth ?? ground ?? layers[0].top;
  const sigmaAt = (z) => {   // effective vertical stress at elevation z, from the top of the first layer
    let s = 0, zt = ground ?? layers[0].top;
    for (const l of layers) {
      const hi = Math.min(zt, l.top), lo = Math.max(z, l.bottom);
      if (hi > lo) {
        const dry = water === null ? hi - lo : Math.max(0, Math.min(hi, Math.max(lo, water)) - lo) * 0 + Math.max(0, hi - Math.max(lo, water)), wet = hi - lo - dry;
        s += dry * l.gamma + wet * ((l.gammaSat ?? l.gamma) - G_W);
      }
      if (l.bottom <= z) break;
    }
    return s;
  };
  for (const [li, l] of layers.entries()) {
    const top = Math.min(l.top, base), bot = l.bottom;
    if (top <= bot) continue;
    const n = Math.max(1, Math.ceil((top - bot) / step)), dz = (top - bot) / n;
    for (let i = 0; i < n; i++) {
      const zm = top - (i + 0.5) * dz, depth = base - zm;
      const dsig = load.method === '2:1' ? stress2to1(load.q, load.B, load.L, depth) : stressRect(load.q, load.B, load.L, depth, load.at);
      if (l.cc !== undefined && l.e0 !== undefined) {
        const s0 = Math.max(sigmaAt(zm), 0.1), sf = s0 + dsig, sc0 = l.sigmaC ?? s0, cs = l.cs ?? l.cc / 5;
        let s;
        if (sc0 <= s0 * 1.0001) s = (l.cc * dz) / (1 + l.e0) * Math.log10(sf / s0);   // normally consolidated
        else if (sf <= sc0) s = (cs * dz) / (1 + l.e0) * Math.log10(sf / s0);   // stays below the preconsolidation stress
        else s = ((cs * dz) / (1 + l.e0)) * Math.log10(sc0 / s0) + ((l.cc * dz) / (1 + l.e0)) * Math.log10(sf / sc0);
        rows.push({ layer: li, z: zm, depth, sigma0: s0, dsigma: dsig, s, kind: 'consolidation' }); sc += s;
      } else if (l.es) {
        const s = (dsig / l.es) * dz * (1 - (l.nu ?? 0) * 0);
        rows.push({ layer: li, z: zm, depth, sigma0: Math.max(sigmaAt(zm), 0), dsigma: dsig, s, kind: 'immediate' }); si += s;
      }
    }
  }
  return { consolidation: sc, immediate: si, total: sc + si, rows };
}

Degree of consolidation

64-bit

The share of the final consolidation settlement reached at a time factor.

U = 1 − Σ (2 ÷ M²)·exp(−M²·Tv), M = π·(2m + 1) ÷ 2

At most 200 terms, stopped early once M²·Tv exceeds 60. For small time factors the series is not converged at 200 terms: recomputed for this review, Tv = 1e-6 gives 0.00139 against 0.00113 from the short-time form, and Tv = 1e-5 gives 0.003570 against 0.003568. At Tv = 1e-4, 1e-3 and 1e-2 the two agree to 12 digits or more.

  • geotech.js
  • lines 466 to 471
  • CivilCraft 0.8.1
/** Degree of consolidation for a time factor (Terzaghi, series). */
export function degreeOfConsolidation(Tv) {
  if (Tv <= 0) return 0;
  let s = 0; for (let m = 0; m < 200; m++) { const M = (Math.PI * (2 * m + 1)) / 2; s += (2 / (M * M)) * Math.exp(-M * M * Tv); if (M * M * Tv > 60) break; }
  return 1 - s;
}

Time factor for a degree of consolidation

64-bit

The time factor at which a given share of the settlement is reached.

Bisection on the series above between 0 and 10, always 80 halvings. The comment mentions closed forms below 60 %; the code uses bisection for every value. A share of 1 or more returns Infinity.

  • geotech.js
  • lines 472 to 477
  • CivilCraft 0.8.1
/** Time factor for a degree of consolidation: by the usual closed forms below 60 %, bisection above. */
export function timeFactor(U) {
  if (U <= 0) return 0; if (U >= 1) return Infinity;
  let lo = 0, hi = 10; for (let i = 0; i < 80; i++) { const mid = (lo + hi) / 2; if (degreeOfConsolidation(mid) < U) lo = mid; else hi = mid; }
  return (lo + hi) / 2;
}

Time to reach a degree of consolidation

64-bit

The time for a share of the consolidation settlement.

t = Tv·Hdr² ÷ cv

One expression after the time factor. The units of the result follow those of cv.

  • geotech.js
  • lines 478 to 479
  • CivilCraft 0.8.1
/** Time for U of the final consolidation settlement: t = Tv·Hdr² / cv. Hdr is the longest drainage path (m), cv in m²/year → years. */
export const timeFor = (U, Hdr, cv) => (timeFactor(U) * Hdr * Hdr) / cv;

Settlement against time

64-bit

The settlement curve from zero to a chosen time.

s(t) = s_final × U(cv·t ÷ Hdr²)

Times are tMax × i ÷ n, not a running sum. The first points of the curve have small time factors, where the series carries the truncation described under the degree of consolidation.

  • geotech.js
  • lines 480 to 484
  • CivilCraft 0.8.1
/** Settlement curve: [{ t, U, s }] for a final consolidation settlement `sFinal`. */
export function timeCurve(sFinal, Hdr, cv, tMax, n = 40) {
  const out = []; for (let i = 0; i <= n; i++) { const t = (tMax * i) / n, U = degreeOfConsolidation((cv * t) / (Hdr * Hdr)); out.push({ t, U, s: sFinal * U }); }
  return out;
}

Secondary compression

64-bit

Settlement from secondary compression between two times.

S = Cα·H ÷ (1 + ep) × log₁₀(t₂ ÷ t₁)

One expression. The ratio of times is not guarded against zero.

  • geotech.js
  • lines 485 to 486
  • CivilCraft 0.8.1
/** Secondary compression between t1 and t2 (Cα as e per log cycle, ep the void ratio at the end of primary, H the layer thickness). */
export const secondary = (Calpha, H, ep, t1, t2) => ((Calpha * H) / (1 + ep)) * Math.log10(t2 / t1);

In detail

Method
The header cites: Boussinesq stress under a rectangle corner as integrated by Newmark 1935; the 2:1 spread; consolidation S = Σ Cc·H ÷ (1 + e₀)·log₁₀((σ′₀ + Δσ) ÷ σ′₀), with Cs up to the preconsolidation stress (Terzaghi 1943); time rate U = 1 − Σ (2 ÷ M²)·exp(−M²·Tv); secondary compression (Mesri 1973); elastic corner settlement (Timoshenko and Goodier 1951).
Number types
64-bit numbers.
Tolerances
Normally consolidated when the preconsolidation stress is within 0.01 % above the present stress. Present effective stress floored at 0.1 kPa. Time factor from a degree of consolidation: 80 bisections between 0 and 10. Series stopped when M²·Tv exceeds 60 or at 200 terms.
Limits
For a time factor below about 1e-5 the 200 terms have not converged: at Tv = 1e-6 the function returns 0.00139 where the short-time form 2√(Tv ÷ π) gives 0.00113. Cs defaults to Cc ÷ 5 when not given. Poisson's ratio has no effect on the immediate settlement of a layer: its term is multiplied by zero in the code.

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