Resources Numerical accuracy Calculation policy

Water treatment unit processes and sludge sizing

Works out head losses through screens and filters, settling removal, disinfection contact time, sludge age, and the size of an activated-sludge tank and clarifier.

How the precision is kept

Each result is one closed-form 64-bit expression of the inputs a person gives. Inputs are checked for sign before use, and nothing is rounded before it is returned.

Calculations under this policy

10 calculations in 2 source files. 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.

process/env/water.js CadCraft 0.8.2 64-bit 7 calculations Reviewed

Tests tools/process-test/test-env.mjs

Bar-screen head loss

64-bit

The head lost through a bar screen.

h = β × (w ÷ b)^(4/3) × v² ÷ 2g × sin θ

One 64-bit expression with g = 9.80665 and the angle converted with Math.PI ÷ 180.

  • process/env/water.js
  • lines 148 to 149
  • CadCraft 0.8.2
/** Bar-screen head loss (m) by Kirschmer: beta bar shape factor (the person's), w bar width, b clear spacing, v velocity through the bars (m/s), theta degrees from horizontal. */
export function screenLoss({ beta, w, b, v, theta = 60 }) { if (!(beta > 0 && w > 0 && b > 0 && v > 0)) throw new Error('Screen loss needs beta, bar width, clear spacing and velocity.'); return beta * Math.pow(w / b, 4 / 3) * v * v / (2 * 9.80665) * Math.sin(theta * Math.PI / 180); }

Ideal settling basin

64-bit

The overflow rate and the fraction of particles removed.

v₀ = Q ÷ A; removal = min(1, vs ÷ v₀)

Two divisions; the removal is capped at 1.

  • process/env/water.js
  • lines 150 to 151
  • CadCraft 0.8.2
/** Ideal settling basin: removal fraction of particles settling at vs (m/d) in a basin of area A (m2) at flow Q (m3/d). */
export function idealClarifier({ Q, A, vs }) { if (!(Q > 0 && A > 0 && vs >= 0)) throw new Error('Clarifier needs Q, area and a settling velocity.'); const vo = Q / A; return { overflowRate: vo, removal: Math.min(1, vs / vo) }; }

Granular filter head loss

64-bit

The head lost through a clean filter bed in laminar flow.

h = 180 × L × ν × (1 − ε)² × v ÷ (g × ε³ × d²)

One 64-bit expression; products and one division, so nothing cancels. Porosity must be strictly between 0 and 1.

  • process/env/water.js
  • lines 152 to 153
  • CadCraft 0.8.2
/** Laminar granular-filter head loss (m of water) through depth L (m) at approach velocity v (m/s), grain diameter d (m), porosity eps, kinematic viscosity nu (m2/s). */
export function filterLoss({ L, v, d, eps, nu }) { if (!(L > 0 && v >= 0 && d > 0 && eps > 0 && eps < 1 && nu > 0)) throw new Error('Filter loss needs depth, velocity, grain size, porosity and viscosity.'); return L * 180 * nu * (1 - eps) ** 2 * v / (9.80665 * eps ** 3 * d * d); }

Disinfection survival

64-bit

The fraction of organisms surviving a contact time, and the log removal.

s = exp(−k × Cⁿ × t); log removal = −log₁₀(s)

The log removal is taken from the computed survival, not from the exponent. When the exponent is large enough for exp to underflow to 0 the log removal becomes Infinity.

  • process/env/water.js
  • lines 154 to 155
  • CadCraft 0.8.2
/** Chick-Watson: fraction surviving after contact time t with concentration C. → { surviving, log10 } (log10 removal). */
export function chickWatson({ k, n = 1, C, t }) { if (!(k >= 0 && C >= 0 && t >= 0)) throw new Error('Disinfection needs k, a concentration and a contact time.'); const s = Math.exp(-k * Math.pow(C, n) * t); return { surviving: s, log10: -Math.log10(s) }; }

Contact time for a log removal

64-bit

The contact time needed to reach a wanted log removal.

t = log₁₀ removal × ln 10 ÷ (k × Cⁿ)

One expression using Math.LN10.

  • process/env/water.js
  • lines 156 to 157
  • CadCraft 0.8.2
/** Contact time needed for a log10 removal at concentration C. */
export function ctFor({ k, n = 1, C, log10 }) { if (!(k > 0 && C > 0 && log10 > 0)) throw new Error('Needs k, C and a log removal.'); return log10 * Math.LN10 / (k * Math.pow(C, n)); }

Sludge retention time

64-bit

The mass of sludge in the system divided by the mass leaving per day.

SRT = V × X ÷ (Qw × Xw + Qe × Xe)

One expression; returns Infinity when nothing leaves.

  • process/env/water.js
  • lines 158 to 159
  • CadCraft 0.8.2
/** Sludge retention time (d): mass in the system over mass leaving. */
export function srtOf({ V, X, Qw, Xw, Qe = 0, Xe = 0 }) { const out = Qw * Xw + Qe * Xe; return out > 0 ? V * X / out : Infinity; }

Tank footprints for the site plan

64-bit

The plan area and the side of a square footprint for each tank.

area = V ÷ depth; side = √area

One division and one square root per tank, unrounded. The depth defaults to 4 m when none is given.

  • process/env/water.js
  • lines 166 to 169
  • CadCraft 0.8.2
/** Plan footprints for the site (CivilCraft): each tank as an area from volume and water depth. depths { tankId: m } or one number. */
export function siteLinks(plant, depths = 4) {
  return (plant.tanks || []).map((t) => { const d = typeof depths === 'number' ? depths : (depths[t.id] ?? 4), area = t.V / d; return { id: t.id, kind: 'basin', volume: t.V, depth: d, area, side: Math.sqrt(area), aerated: !!t.aerated, note: 'Square footprint as a placeholder; the shape is the designer\'s.' }; });
}
process/env/design.js CadCraft 0.8.2 64-bit 3 calculations Reviewed

Tests tools/process-test/test-chem4.mjs

Complete-mix tank sizing

64-bit

Sludge production, tank volume, retention time, food-to-mass ratio and oxygen demand.

Px = Y × Q × (S₀ − S) ÷ (1 + kd × θc); V = θc × Px ÷ X; O₂ = Q × (S₀ − S) − 1.42 × Px

64-bit closed forms. Unit changes are a division and a multiplication by 1000; the oxygen demand subtracts 1.42 × Px from the substrate removed. Every input except S and kd must be above 0.

  • process/env/design.js
  • lines 2 to 17
  • CadCraft 0.8.2
/**
 * design.js — activated-sludge and clarifier sizing by the classic design equations (0.8 Track CH, CH.20; DOM-free). The kinetic constants (Y, kd) and the
 * design targets are the PERSON'S inputs (no default: they depend on the wastewater); the equations are those of the textbooks (Metcalf and Eddy, Wastewater
 * Engineering; Grady, Daigger and Lim). A drafting and study aid, not an engineering approval.
 *   completeMix({ Q (m3/d), S0, S (mg/L soluble BOD or COD in and out), Y (g VSS/g), kd (1/d), thetaC (d), X (mg VSS/L in the tank) })
 *       Px = Y Q (S0 - S)/(1 + kd thetaC) (kg VSS/d);  V = thetaC Px / X (m3);  tau = V/Q;  F/M = Q S0 / (V X);  oxygen = Q (S0 - S) - 1.42 Px (kg/d).
 *   returnRatio({ X, Xr, Xe = 0 })        solids balance on the reactor and clarifier: Qr/Q = (X - Xe...) / (Xr - X)  (Xe the effluent solids, small)
 *   clarifier({ Q, Qr, X, A })            surface overflow rate Q/A (m/d) and solids loading (Q+Qr) X / A (kg/m2/h)
 */
export function completeMix({ Q, S0, S, Y, kd, thetaC, X }) {
  for (const [k, v] of Object.entries({ Q, S0, Y, thetaC, X })) if (!(v > 0)) throw new Error('activated sludge: give ' + k + ' (it has no default)');
  if (!(S >= 0 && S < S0)) throw new Error('the effluent S must be 0 or more and below the influent S0');
  if (!(kd >= 0)) throw new Error('give kd (1/d)');
  const dS = Q * (S0 - S) / 1000, Px = Y * dS / (1 + kd * thetaC), V = thetaC * Px * 1000 / X;       // kg/d, m3 (X in g/m3)
  return { Px, V, tau: V / Q, tauHours: 24 * V / Q, FM: Q * S0 / (V * X), oxygen: dS - 1.42 * Px, thetaC, source: 'Metcalf and Eddy, complete-mix activated sludge design equations' };
}

Return sludge ratio

64-bit

The return flow as a fraction of the plant flow.

Qr ÷ Q = (X − Xe) ÷ (Xr − X)

The denominator is a difference; the function refuses Xr at or below X, but a return concentration only slightly above X makes the ratio sensitive to both inputs.

  • process/env/design.js
  • lines 18 to 21
  • CadCraft 0.8.2
export function returnRatio({ X, Xr, Xe = 0 }) {
  if (!(Xr > X && X > 0)) throw new Error('the return sludge must be thicker than the tank: Xr > X > 0');
  return { ratio: (X - Xe) / (Xr - X), note: 'neglects the solids lost in the effluent beyond Xe' };
}

Clarifier loadings

64-bit

Surface overflow rate and solids loading of a clarifier.

overflow = Q ÷ A; solids = (Q + Qr) × X ÷ 1000 ÷ A ÷ 24

Divisions applied in sequence in 64-bit; no rounding.

  • process/env/design.js
  • lines 22 to 25
  • CadCraft 0.8.2
export function clarifier({ Q, Qr, X, A }) {
  if (!(A > 0)) throw new Error('give the clarifier area A (m2)');
  return { overflowRate: Q / A, solidsLoading: (Q + Qr) * X / 1000 / A / 24, units: { overflowRate: 'm/d', solidsLoading: 'kg/m2/h' } };
}

In detail

Method
Kirschmer bar-screen loss, ideal settling basin, laminar granular-filter loss with coefficient 180, Chick-Watson disinfection, and the complete-mix activated-sludge design equations the file attributes to Metcalf and Eddy.
Number types
64-bit numbers. g = 9.80665 m/s².
Limits
The oxygen equivalent of biomass is the constant 1.42. Kinetic constants are inputs with no default.

Approach: 64-bit, direct

Every value is a 64-bit number from input to result. Formulas are closed form or a direct solve, and every comparison uses a stated tolerance.

Every policy that takes this approach