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