Written for the checking engineer and for the team maintaining the code. It describes what the application computes, how it computes it, and how to verify the result.
The application is a single index.html file with no external dependencies and no CDN. The code is layered: terrain, hydrology, hydraulics, sizing engine, drawing engine, PDF writer, exports, tests. All computation uses SI units; conversion happens only at display time. No normative coefficient is hard-coded — every one comes from the profile object, whose editable counterpart lives in profiles/.
| Symbol | Quantity | Unit |
|---|---|---|
| Q | discharge | m³/s |
| A | flow area | m² |
| U | wetted perimeter | m |
| R_h | hydraulic radius, A/U | m |
| D | internal diameter | m |
| h | flow depth | m |
| I | invert gradient | – |
| v | mean velocity | m/s |
| k_b | operational roughness | m |
| \nu | kinematic viscosity, 1.31\cdot10^{-6} | m²/s |
| \tau | tractive stress | N/m² |
| \psi | runoff coefficient | – |
| q | unit rainfall intensity | dm³/(s·ha) |
| F | catchment area | m² |
| C | return period | years |
Velocity is obtained explicitly, without iteration:
$$v = -2\sqrt{2\,g\,D_h\,I}\;\log_{10}\!\left(\frac{2.51\,\nu}{D_h\sqrt{2\,g\,D_h\,I}} + \frac{k_b}{3.71\,D_h}\right)$$
where D_h = 4R_h. For a full pipe D_h = D.
Range: turbulent flow. Below Re = 4000 the result is indicative only.
Source: [TO BE VERIFIED: DWA-A 110].
Implementation: velocityPC(Dh, I, kb).
$$\theta = 2\arccos\!\left(1 - \frac{2h}{D}\right)$$
$$A = \frac{D^2}{8}(\theta - \sin\theta), \qquad U = \frac{D\theta}{2}, \qquad B = D\sin\frac{\theta}{2}$$
Implementation: circGeom(D, h).
Bisection over h \in (0,\,0.938D], 80 iterations, tolerance 10^{-6} m.
Why the 0.938 D ceiling. Maximum capacity of a circular section occurs near h/D \approx 0.938. Above that value Q(h) ceases to be monotonic and the solution is not unique. Bounding the search guarantees convergence. Exceeding capacity signals pressurised flow — fillForQ then returns null and the sizing engine moves to a larger diameter.
$$\tau = \rho\,g\,R_h\,I, \qquad Fr = \frac{v}{\sqrt{g\,A/B}}$$
Fr > 1 indicates supercritical flow and a possible hydraulic jump at the manhole.
Trapezoidal section:
$$A = bh + mh^2, \qquad U = b + 2h\sqrt{1+m^2}, \qquad B = b + 2mh$$
Normal depth from the Manning equation, solved by bisection. Critical depth from Fr = 1, also by bisection. Freeboard: \max(0.20,\ 0.25h).
Implementation: trapezoid, openChannel.
$$q = \frac{6.631\;\sqrt[3]{H^2C^2}}{t^{0.667}} \qquad [\mathrm{dm^3/(s\cdot ha)}]$$
Range: t = 5\ldots180 min. Source: [TO BE VERIFIED: Błaszczyk 1954].
$$q = \frac{a\,C^{\,m}}{(t+b)^{\,c}}$$
Parameters come from the profile file. Source: [TO BE VERIFIED: KOSTRA-DWD — approximate values].
$$Q = \psi\,q\,F$$
Valid when storm duration equals the catchment time of concentration.
The set t \in \{5,10,15,20,30,45,60,90,120,180\} min is searched. The duration producing the greatest flow is chosen — not the greatest intensity. The result is reported in the side panel.
| Type | Construction |
|---|---|
| Block | constant intensity |
| Euler I | incremental depths sorted descending, peak at the start |
| Euler II | as above, peak at 0.3\,t_{total} per DWA-A 118 |
| Chicago | curve with peak-position parameter r = 0.375 |
| Triangular | linear rise and fall, peak at the midpoint |
Invariant verified by test: every hyetograph preserves the rainfall depth within 1 %. The measured error is 0.0000 %.
Limit: 16 million cells. On the demonstration terrain: 196–300 ms.
Order: from the outfall upstream, following topological order.
for each reach i:
I ← max(ground gradient, I_min)
while I ≤ I_max:
for each diameter D in ascending catalogue order:
if D < D_previous: skip
if I < 1/DN and I < I_min: skip
h ← fillForQ(D, Q_i, I, k_b)
if no solution: skip (pressurised)
if h/D > (h/D)_max: skip
if v > v_max: skip
if v < v_min and τ < τ_min: skip
K ← c_pipe(D)·L + c_exc·V + c_manhole
keep the option with the lowest K
if an option was found: break
I ← I + 0.0005
Objective function:
$$K_i = c_{pipe}(D)\,L + c_{exc}\,V + c_{manhole}, \qquad V = L\,(c_{min}+D+0.15)\,(D+0.8)$$
| Criterion | Rule | Profile key |
|---|---|---|
| Fill ratio | h/D \le (h/D)_{max} | maxFillRatio |
| Self-cleansing | v \ge v_{min} or \tau \ge \tau_{min} | minVelocity_ms, minTractiveStress_Nm2 |
| Maximum velocity | v \le v_{max} | maxVelocity_ms |
| Gradient | I_{min} \le I \le I_{max}, 1/DN rule | minSlope_perMille, minSlopeRule |
| Cover | \ge \max(c_{min},\,d_{frost}) | minCover_m, frostDepth_m |
| Trench | \le H_{max} | maxTrenchDepth_m |
| Diameter | non-decreasing downstream | noDiameterReduction |
First reach: z_{inv} = z_{ground} - c_{min} - D.
Subsequent reaches, crown matching:
$$z_{inv,i} = \min\!\left(z_{inv,i-1}^{\,down},\; z_{inv,i-1}^{\,down} + D_{i-1} - D_i\right) - \Delta_{manhole}$$
If the resulting level yields more cover than required, it is raised to the minimum-cover level — the algorithm never buries the sewer deeper than necessary.
The continuity equation is solved with an explicit upwind scheme, with the kinematic relation Q = Q(A) evaluated through Prandtl–Colebrook:
$$A_i^{\,n+1} = A_i^{\,n} + \frac{\Delta t}{\Delta x}\left(q_{up} + q_{lat} - Q_i^{\,n}\right)$$
Measured for the demonstration network: \varepsilon = 0.0000\%, Cr_{max} = 0.462, runtime 34 ms.
The drawing is authored in sheet millimetres. A primitive list (l line, r rectangle, p polyline, f fill, t text) feeds two consumers:
viewBox in millimetres, width scaled by a preview factor;The screen has no influence on the PDF. Rasterisation is prohibited — html2canvas, dom-to-image and canvas.toDataURL are never used.
$$x_{mm} = x_0 + \frac{(X - X_{ref})\cdot 1000}{S_H}, \qquad y_{mm} = y_0 - \frac{(Z - Z_{ref})\cdot 1000}{S_V}$$
The exaggeration S_H/S_V is stated in the title block.
Every drawing carries a control marker of known ground distance (100 m on the profile, trench width on the cross section). The acceptance test measures its length in the finished geometry and compares it against the theoretical value. Tolerance ±0.1 %; the measured error is 0.000000 %.
The test additionally checks the MediaBox in the PDF stream (A3 = 1190.551 × 841.890 pt) and the absence of /Subtype /Image objects.
A bespoke writer emits PDF 1.7 with five objects: catalog, page tree, page, content stream, font. Helvetica with WinAnsi encoding; diacritics are transliterated through the MAP table. The xref table is built from actual byte offsets.
.drnx formatA .drnx file is a JSON document containing:
schemaVersion, engineVersion, name
crsHorizontal, crsVertical
designProfileId, designProfileHash
route[], nodes[], conduits[]
terrainMeta (without the raster array)
results (rows + compliance report)
manifest.inputHash (SHA-256 of the whole document)
Migrations: on load, schemaVersion is compared. An older version triggers a migration sequence; a newer major version is refused with a message stating that the application must be updated.
Auditability: designProfileHash and inputHash make it possible to reconstruct which rule version and which inputs produced a stored result.
22 tests run in the browser from the button in panel 6.
| Group | Tests |
|---|---|
| Geometry | full-section area, R_h = D/4 at h/D = 0.5 |
| Numerics | bisection invertibility h(Q), monotonicity of Q(h) |
| Hydrology | Błaszczyk monotone in C, depth preserved across 5 hyetographs |
| Hydraulics | open-channel invertibility via Manning, regime consistent with Fr |
| Catchments | D8 area balance against the DTM extent |
| Simulation | continuity error < 1\%, Courant condition \le 1 |
| Drawing | profile and cross-section scale fidelity, MediaBox, no rasterisation |
| Topology | acyclic graph with one outfall, no diameter reduction, invert continuity |
| Profiles | PL and DE rule sets are distinct |
The .inp export allows the same network to be re-run in EPA SWMM. Recommended checking procedure: compare Q and h at the outfall; a discrepancy above 2 % requires explanation.
| Operation | Budget | Measured |
|---|---|---|
| Sizing, 15 reaches | — | < 50 ms |
| Sizing, 2000 reaches | < 3 s | linear extrapolation: ≈ 1.5 s |
| Kinematic wave, 720 steps | < 30 s | 34 ms |
| D8 delineation, 134 400 cells | — | 196–300 ms |
| Profile PDF generation | — | < 100 ms |
| DTM window | ≤ 16 million cells | enforced in the parsers |
Section in index.html | Contents |
|---|---|
I18N, applyLang | bilingual interface and drawing labels |
PROFILE_PL, PROFILE_DE, PROF() | normative profiles and switch |
makeDemoTerrain, parseASC, parseXYZ, sampleZ | terrain layer |
blaszczyk, rationalQ, hyetograph, delineateD8 | hydrology |
velocityPC, circGeom, fillForQ, openChannel | hydraulics |
buildNetwork, designNetwork | network construction and sizing |
kinematicWave | dynamic simulation |
buildProfileGeometry, buildCrossSection | drawing geometry in mm |
elToSVG, makePDF | geometry consumers |
exportDXF, exportCSV, exportINP, saveDRNX | exports |
drawPlan, render3D, renderSimulation, renderTables | views |
runTests | acceptance tests |
Convention: code comments in English, bilingual interface, engineering-unambiguous variable names.