SWMM 1 Runoff Engine

SWMM 1 Runoff Engine — the 1971 Fortran, rebuilt from the printed listing, running as WebAssembly

Source: EPA 11024 DOC 10/71, Vol. IV Program Listing, Section 2 (Runoff Block) Engine: C translation → wasm32, 0 imports, output byte-identical to the native build AI use: see About v1.4

Card deck (unit 5)

Engine loading…

Continuity (from the printout)

Run the deck to see totals

Rainfall hyetograph (in/hr)

Hydrographs at saved points (cfs) — from the interface tape, unit 8

Pollutographs at saved points — SFQUAL, from the rewritten interface tape (NQUAL = 3)

Overland flow depth on each subarea plane (ft) — from blank COMMON at the last step

—
No run yet.
Run a deck first.

  

Lines decided by judgement (not by a clean read)

CardAs transcribedWhy it needed a decision
WSHE 73IF(DELR.LT..0001*WDEPTH(J,K)) GO TO 280The constant is smudged in the print (..0021 / ..0014 in OCR). .0001 fits the role: a tolerance after the 11-pass Newton loop fails. Only affects whether a "NO CONVERGENCE" line is printed, not the depth.
GUTT 13WCON(160,3),NAMEW(160),PCIMP(160)Blurred in GUTTER; confirmed by the same COMMON statement printed clearly in HCURVE, HYDRO, RHYDRO and WSHED.
HCUR 22–27DATA TITL / … / VER / … /Hollerith strings read from the image; the exact blank padding inside 4H fields matters only for the printer-plot titles.
RHYD 32… ZERO DETENTION DEPTH')Literal breaks across a continuation line at column 72 (DE / PTH); joined as the compiler would.
RUNO 9CALL GRAPH(0)Argument reads as 0 or O; GRAPH is the Executive Block printer-plot driver, not implemented here.
SFQU 13CBASTM(160)Printed as CBASTH/CBASTM in the COMMON; every use is CBASTM, so CBASTM.
SFQU245C PRESENT COMPUTATIONS ASSUME CBS EFFECT ONLY BODThe C in column 1 is missing on the page; it can only be a comment.
SFQU221–224IF(KLAND(J).EQ.1)SFCOLI(JJ)=590000000*…Nine- and ten-digit coliform factors read from the image; KLAND is subscripted J (the inlet pointer), not JJ, as printed.
SFQU326–343, 462–464FORMAT 630 / 605 / 616 dash rulesDash counts inferred from column 72 of each continuation card; cosmetic only.
SFQU371631 FORMAT(' ',I5,I7,T17,F8.2,T25,F11.2,T39,F11.2,T52,F8.2,T62,F8.2,T72,F8.2)Smudged; taken to be the first half of FORMAT 612, which is clear.
page / 248 Open the tab to load the listing (5.1 MB).

Card group A — title (2 cards, 20A4, RHYD 20)

Two 80-column cards of text, stored in TITLE(40), echoed on the printout and written as record 1 of the interface tape.

Card B — run control (2I5,I3,I2,F5.1,I5,F5.0, RHYD 22)

ColsFieldMeaningDefault
1–5INLETInlet (manhole) number this deck drains to; a label only—
6–10NSTEPNumber of integration time steps—
11–13NHRStart hour of the storm0
14–15NMNStart minute0
16–20DELTIntegration time step, minutes—
21–25NRGAGNumber of rain gages (max 10)—
26–30PCTZERPercent of impervious area with zero detention storage25

Card C — hyetograph control (I5,F5.0, RHYD 37)

ColsFieldMeaning
1–5NHISTONumber of rainfall intensity values per gage (max 160)
6–10THISTORainfall interval, minutes

Cards D — rainfall intensities (10F5.0, RHYD 44), NRGAG sets

NHISTO values in inches per hour, ten per card, as many cards as needed per gage. Converted internally to ft/s (÷ 43200).

Cards E — subareas (3I5,3F5.0,7F5.3,F10.5, RHYD 72), one per subarea, ended by a card with cols 6–10 blank/zero

1971 trap: the read loop is DO 340 I=1,NW with NW = 160, so after exactly 160 subarea cards it stops without looking for a terminator — punch the blank card only when there are fewer than 160. The same holds for the 160 gutter cards (RHYD 144). The converter follows this rule.

ColsFieldMeaningDefault when 0
1–5JKRain gage number1
6–10NSubarea number (1–160); zero ends the group—
11–15NGOTOGutter/pipe number it drains to; 0 = direct to inletinlet
16–20W1Width of overland flow, ft—
21–25W2Area, acres—
26–30W3Percent impervious—
31–35W4Ground slope, ft/ft0.03
36–40W5Manning n, impervious0.013
41–45W6Manning n, pervious0.25
46–50W7Detention storage, impervious, inches0.062
51–55W8Detention storage, pervious, inches0.184
56–60W9Horton maximum infiltration, in/hr3.0
61–65W10Horton minimum infiltration, in/hr0.52
66–75W11Horton decay rate, 1/second0.00115

Cards F — gutters and pipes (4I5,7F8.0, RHYD 145), one per element, ended by a card with cols 6–10 blank/zero

ColsFieldMeaningNote
1–5JKUnused (printed in error messages as "inlet")
6–10NGutter/pipe number (1–160)
11–15NGOTODownstream gutter/pipe; 0 = discharges to the inlet
16–20NP1 = trapezoidal gutter, 2 = circular pipe3 is created internally for a manhole with no element
21–28G1Bottom width (trapezoid) or diameter (pipe), ft
29–36G2Length, ft
37–44G3Invert slope, ft/ftused as 1.486·√S/n
45–52G4Left side slope, horizontal per verticaltrapezoid
53–60G5Right side slopetrapezoid
61–68G6Manning n
69–76G7Overflow depth, trapezoid (the header says IN, the code uses it in FT; 0 → 10 ft). Pipes always use 2.62 rad = 93 % of diameter.

Card G — hydrographs to save (16I5, RHYD 262)

NSAVE on one card, then the gutter numbers whose inflow is written to the interface tape (unit 8) every step. These are what the chart shows.

Card H — hydrographs to print (16I5, RHYD 277)

NPRNT, INTERV on one card, then the gutter numbers to list on the printout every INTERV steps.

Surface quality cards (SFQUAL) — optional; if none follow, the engine prints a note and skips SFQUAL

Card Q1 — control (2I5,F5.0,4I5, SFQU 21)

ColsFieldMeaning
1–5KTNUMNumber of quality subarea cards (Q4)
6–10NINLTSNumber of sewer inputs = must equal NSAVE (SFQU 122 stops otherwise)
11–15DTTime step, minutes (same as DELT)
16–20KHOURStart hour
21–25KMINStart minute
26–30NTSTEPNumber of steps = number of records GUTTER wrote on the scratch tape (NSTEP rounded up to a multiple of M = (NSTEP+99)/100)
31–35NPRINT0 = one summary table; n > 0 = per-input time tables every n steps

Card Q2 — street condition (2F10.0,I5, SFQU 31)

ColsFieldMeaning
1–10DRYDAYDry days before the storm
11–20CLFREQStreet-cleaning interval, days
21–25NOPASSSweeper passes: 1, 2 or 3 (sets the removal efficiency REFF with CLFREQ)

Card Q3 — catch basins (3F10.0, SFQU 53)

ColsFieldMeaning
1–10CBDENCatch basins per acre (0 = none)
11–20CBBODBOD of the stored liquid, mg/l
21–30CBVOLStored volume per basin, gallons

Cards Q4 — quality subareas (3I5,2F10.2, SFQU 73), KTNUM cards, grouped by INPUT

ColsFieldMeaning
1–5KNUMSubarea number (label)
6–10INPUTSewer input it drains to = one of the saved gutter numbers (card G); consecutive cards with the same INPUT form one input area
11–15KLANDLand use: 1 single-family, 2 multi-family, 3 commercial, 4 industrial, 5 undeveloped/park (sets the dust-and-dirt, BOD and coliform factors from the Chicago APWA study)
16–25ASUBArea, acres
26–35GUTTERCurb/gutter length, hundreds of feet (0 = no washoff from this subarea)

Start with what the machine was

In 1971 a storm-water model was a box of punched cards, a reel of tape and a line printer. You read the cards once, in order, through unit 5; you wrote your report to unit 6, one line at a time, with the first character of each line telling the printer whether to skip to a new page; and you left your real results on a tape for the next program in the chain. The Runoff Block of SWMM Version 1 is about a thousand cards of Fortran IV written for an IBM 360, and every design decision in it comes from that environment. Keep that in mind and the code stops looking odd and starts looking sensible.

This app runs that code. Not a re-derivation of it, not a modern model with a 1971 label — the same statements, in the same order, translated into C with the names and labels kept, compiled to WebAssembly, fed the same 80-column cards. If the original authors could watch, they would recognize every line of the printout.

The watershed as three buckets

A subarea in SWMM 1 is not one surface. RHYDRO splits every subarea into three planes and WSHED solves each of them separately (figure 1). Plane 1 is the impervious ground that holds some water before it runs off — roofs and pavement with their puddles. Plane 2 is the pervious ground, the only one that infiltrates. Plane 3 is the share of the impervious area the modeler says has no depression storage at all: the default is a quarter of it, PCTZER = 25, and it starts running off the instant the rain starts. That third plane is why a SWMM 1 hydrograph rises at the first drop instead of waiting for the puddles to fill. It is a small idea with a big effect on the first ten minutes.

K=1 impervious K=2 pervious K=3 impervious, no storage PCIMP·(100−PCTZER)/10⁴ of A storage WSTORE(J,1)=W7/12 no infiltration n = W5 (0.013) (100−PCIMP)/100 of A storage WSTORE(J,2)=W8/12 Horton infiltration RLOSS n = W6 (0.25) PCIMP·PCTZER/10⁴ of A storage = 0 no infiltration n = W5 WFLOW(J) = Σ WFLO of the three planes All three planes share width W1, slope W4 and the gage JK; each keeps its own depth WDEPTH(J,K). (WSHE 36–46, RHYD 95–108)
Figure 1. One subarea, three planes. WSHED loops K = 1, 2, 3 for every subarea every time step; the areas, storages and losses differ, the width and slope do not.

All three planes share the subarea width W1 and slope W4. The width is the one number a modeler has to think about: it is the length of the imaginary curb the sheet of water flows over, and it sets how fast the plane drains. The 1971 manual told you to take the area divided by the average overland flow length, and that advice has not changed in fifty years.

Rain in, water out: the nonlinear reservoir

Each plane is a reservoir with a leak that depends on how full it is. Water depth d on the plane rises with rain i, falls with infiltration f, and falls with outflow, and the outflow is Manning's equation applied to the sheet of water above the depression storage dp:

dd/dt = i − f − (1.486/n)·√S·(W/A)·(d − dp)^(5/3) in the cards: WCON(N,K) = −(1.486/n)·√W4·W1·100/(WAREA·PCIMP) (RHYD 105–106) F = DELR − DELT·(WCON·D0^1.6666667 + (RI − RLOSS)) (WSHE 66) DF = 1 − DELT·(0.83333333·WCON·D0^0.6666667) (WSHE 67)

There is no closed form for that, so WSHED does what an engineer with a desk calculator would do: guess the change in depth over the step, evaluate the balance at the midpoint depth, correct the guess by Newton's method, and stop when the correction is under one percent of the change. Eleven passes are allowed; it usually needs two or three. The sign convention is worth a second look — WCON is stored negative, so the whole Manning term carries its own minus sign, and D0 is the depth above the puddles at mid-step, clamped at zero. If the rain and the stored water together cannot even fill the depression storage, the code skips the solver entirely and just adds the water to the puddle (WSHE 62, 285). Nothing runs off a plane until its puddles are full. Figure 2 shows how steep that leak is: outflow goes with the five-thirds power of the excess depth, so a plane that has a quarter inch standing on it drains an order of magnitude faster than one with a tenth.

Figure 2. Outflow from a 10-acre plane against the depth standing on it, for the default impervious roughness and a 2 % slope. Below the 0.062-inch depression storage nothing leaves.

Horton's law of diminishing returns

The pervious plane loses water to the soil at a rate that starts high and decays to a floor — Horton's equation, with the three numbers that every SWMM user since has typed in: a maximum rate (3 in/hr), a minimum rate (0.52 in/hr) and a decay constant (0.00115 per second, which is 4.14 per hour). SWMM 1 evaluates it against time since the start of the storm, not against cumulative infiltration, and it does not recover during dry spells — the decay runs on the clock, which is the right model for a single storm and the wrong one for a week of weather. There is one more guard: if the loss over a step would take more water than the plane has, the loss is cut to what is there (WSHE 52–58). That keeps the mass balance honest when a light shower falls on dry ground.

f = fc + (fo − fc)·e^(−k·t) RLOSS = WLMIN + (WLMAX − WLMIN)/EXP(DECAY·TIME2) (WSHE 50–51)
Figure 3. The default Horton curve. After three hours it is within two percent of the floor.

Gutters and pipes: the same trick with geometry

A gutter in SWMM 1 is also a reservoir with a Manning leak, only the geometry is honest about the cross section. GUTTER takes the inflow from the subareas and the upstream elements that drain to it, and solves for the depth at the end of the step so that the change in stored volume equals inflow minus the average outflow over the step. Newton again, up to thirty passes, converged when the volume residual is under a tenth of a cubic foot.

NP = 1 trapezoidal gutter GWIDTH = G1 (bottom width) GS1GS2 depth D A = ½(GS1+GS2)·D² + GWIDTH·D P = D·(√(GS1²+1) + √(GS2²+1)) + GWIDTH NP = 2 circular pipe θ "depth" is the half-angle θ (rad); GWIDTH = diameter A = (D²/4)(θ − ½ sin 2θ), P = D·θ, full at θ = 2.62 rad (0.93 D)
Figure 4. The two cross sections GUTTER knows. For the pipe the state variable is the half-angle θ, not the depth; it makes the area and wetted perimeter simple functions and avoids the arcsine.

Two choices in that routine deserve attention. First, the pipe is never allowed to fill. DFULL for a pipe is 2.62 radians, which is a depth of 93 percent of the diameter — just about where the flow in a circular pipe is greatest, and comfortably away from the place where Manning's equation goes to pieces as the top of the pipe closes in. Second, when a gutter or pipe hits its full depth the excess is not lost; it is parked in QSUR, printed as a surcharge in cubic feet, and fed back as inflow on the next step (GUTT 162–164). That is a storage node at every manhole, done in three cards. The modern dynamic-wave engine does it with a pressurization slot and a full momentum equation; the 1971 engine did it with a bucket, and for a 5-minute step on a small system the bucket is not a bad answer.

The tree, upside down

The elements have to be solved upstream first, so each gutter knows its inflow before it is asked for its outflow. HYDRO does not ask you to order the cards. It finds the elements that discharge to the inlet, puts them at the far end of NGUT, then walks back up the tree prepending each element's feeders, and finally slides the whole list to the front (figure 5). Thirty cards, no recursion, no stack — just an array walked from the back. The same routine also invents a dummy element, NPG = 3, for any manhole number that subareas or gutters drain to but no gutter card describes; a dummy element passes its inflow straight through. That is how a subarea can drain to a manhole rather than a pipe.

gutter 1gutter 3sub 8 pipe 2pipe 4pipe 5 INLET NGUT order (HYDR 66–87) 1. inlet's feeders go to the end: NGUT(160)=5 2. walk back up, prepending: …,4,2,5 → …,3,1,4,2,5 3. shift to the front: NGUT = 3,1,4,2,5 Upstream first, so each gutter's QIN is already known when it is solved.
Figure 5. Sample deck 2 as HYDRO orders it. Pipe 5 feeds the inlet; subarea 8 drains to the inlet directly and never passes through a gutter.

The walk has a limit that the manual does not advertise. RHYDRO collects the elements that discharge to the inlet in two small arrays, NWTOI and NGTOI, and fills them with a loop that runs J = 1 to NIN, and NIN is 10 (RHYD 181). The eleventh subarea or gutter that drains straight to the inlet is reported as "LARGER THAN THE ALLOWED NO" — a message written for a different mistake — and the run stops. In 1971 this was a modelling rule you learned once: collect your laterals into a trunk before the inlet. The converters in this app learn it for you. When a SWMM 5 or SWMM 4 model has more than ten links reaching the outfall, they add pass-through collector elements, ten feeders each, and chain them, so the deck runs and each inlet keeps its own saved hydrograph. The Lancaster example, SWDAT1 from the SWMM 4 distribution, needs one such collector for its fifteen Transport inlets.

Tapes, and what the next block got

The printout is for the engineer. The results are on tape. At every step GUTTER writes the time and the inflow to each saved element to unit NOUT, after a three-record header (figure 6). The Transport Block read that tape as its inflow hydrographs; the quality routine SFQUAL read a second copy on a scratch unit. This app reads the same records back and draws them — the charts you see are not re-computed from the printout; they are the tape.

TITLE(40)NSTEP,NSAVE,NQUAL,DELT,TZERO,TAREAISAVE(1..NSAVE)TIME, OUTFLW(1..NSAVE) × NSTEP records (GUTT 195) Unit NOUT = JOUT(IOUTCT): the interface tape the Transport Block read. The chart on the Run tab is built from it.
Figure 6. The interface tape (RHYD 271–274, GUTT 195). Unformatted Fortran records: each is a length word, the data words, and the length again.

Dirt, by land use

The second half of the Runoff Block is SFQUAL, Metcalf & Eddy's surface quality model, and it is the part of SWMM 1 that had no precedent. The premise is blunt: what washes off a street is the dust and dirt that accumulated in the gutter since it was last cleaned, and how much accumulated depends on the land use and the length of curb. The Chicago APWA study gave the rates — 0.7 to 4.6 pounds per day per hundred feet of gutter for single-family through industrial land — and the BOD and coliform content of that dirt. Street sweeping takes a fixed fraction each pass (60 to 98 percent, by sweeping interval and number of passes), so the load at the start of the storm is a geometric series over the dry days. Catch basins add a second source: a tank of stale liquid of known BOD that the first runoff flushes out, with an exponential that saturates after about one and a half basin volumes have passed through.

dust and dirt: TOTDD = DRYDAY·DD or CLFREQ·DD·Σ(1−REFF)^k (SFQU 84, 93) washoff: POPSS = ASUB·(A·E + B·E^D)·C·REMDD/TOTDD, E = 100·r, D = 2.6 − 1.25·√r (SFQU 210–215) soluble BOD: P = PO·e^(−4.6·r·T), POP = PO − P (SFQU 204–209) catch basins: CBLBS = (1 − e^(−CBSUM/(1.5·CBVOL)))·POCB (SFQU 237–239)

Here r is the runoff rate in inches per hour over the area draining to the input, and the washoff fraction is a power law in it. Look at the exponent D before you trust a pollutograph: it is 1.0 above one inch per hour and climbs toward 2.6 as the flow dies away, so the solids removed per step can rise again on the recession, when the exponent outruns the falling flow. That is not a transcription error — the cards say it — it is what the 1971 authors fitted, and it is one reason later versions replaced this function with the exponential washoff SWMM uses today. SFQUAL reads the hydrographs back from the scratch tape GUTTER left, works per sewer input, writes a per-step table of flow, BOD and solids, and then overwrites the interface tape with NQUAL = 3 so the Transport Block received quality as well as flow (figure 7).

Figure 7. BOD and suspended solids per time step at the saved points of the deck on the Run tab, read from the rewritten interface tape.

Reading the printout

The report ends with four totals and a number worth trusting more than any single hydrograph: the error in continuity as a percentage of rainfall (HYDR 139). Rainfall in, minus infiltration, minus flow that reached the inlet, minus water still standing on the planes, should be zero. On sample deck 1 it is 0.14 percent; on deck 2, 0.9 percent. A 1971 engineer would have been pleased with either. The error has three sources — the midpoint depth in the planes, the averaged outflow in the gutters, and the fact that the surcharge bucket is not counted as storage — and it grows with the time step. Halve DELT and watch it fall; that is the oldest convergence test there is and it still works.

A model that keeps its mass balance in a visible number on the last page is a model that expects to be checked. Keep that habit.

What this rebuild changed, and what it did not

1971 listingFortran IVC, same nameswasm32, 0 imports 25 page images6 routines, card IDsCOMMON as one word array47 KB, runs in ~2 ms Check: native C build and wasm build give byte-identical printouts on both sample decks.
Figure 8. From the printed page to the browser. Each C line carries the card number it came from.

The Fortran was read from the page images of the listing — the OCR layer in the PDF turns WDEPTH into WOEPTH and 160 into 16O often enough to be useless as a source and good enough to be a scaffold. Each of the seven routines was typed back into fixed form with its identification field in columns 73–80, then translated to C one statement at a time. Blank COMMON is a single array of four-byte words, so the layout, the column-major arrays and even the one place the code deliberately clears past the end of HGRAPH behave exactly as they did on the 360. REAL is a 32-bit float; the 360 used hexadecimal floating point with a slightly different precision, and no one should expect the sixth digit to agree with a 1971 run. Blanks in numeric fields are ignored here, where the 360 read them as zeros; a card punched correctly reads the same either way, and a card typed carelessly now reads the way you meant it.

  • Included: RUNOFF, HYDRO, RHYDRO, WSHED, GUTTER, HCURVE — the whole quantity side, the card reader, the report, the interface tape.
  • Included: SFQUAL, the surface-quality model, with its scratch-tape read-back and the NQUAL = 3 interface tape. Not included: the Executive Block printer plots that HCURVE sets up. Transport, Storage and Receiving Water are separate volumes of work.
  • Imported: SWMM 5 .inp files and SWMM 4 .DAT files with a $RUNOFF block, including the SWDAT series that shipped with SWMM 4. Decks whose rain comes from a Rain Block file, or that only call EXTRAN, Storage or Stats, are shown but not run.
  • Verified: wasm and native builds produce byte-identical printouts; the engine is re-entrant; continuity closes within a percent on both sample decks. On the Lancaster deck the reported error is 29 percent, and that is water in transit: the SWMM 4 run ends at 60 minutes while the rain lasts to 65, and HYDR133–139 count rain, infiltration, inlet flow and subcatchment storage but not what is sitting in the gutters and pipes. Not verified: against an actual 1971 run, because none survives in this reconstruction.

Your run

Figure 9. Hydrographs at the saved elements of the deck currently loaded on the Run tab, read from the interface tape.

Change a width, halve the slope, move PCTZER to zero and run again. It takes two milliseconds. In 1971 it took a trip to the card punch, a place in the queue and a wait for the printer. The physics did not change in between; the patience required did.

What this is

The Runoff Block of the original Storm Water Management Model, Version 1, as published in Storm Water Management Model, Volume IV — Program Listing (EPA Water Quality Office, report 11024 DOC 10/71, October 1971) by Metcalf & Eddy, Inc., the University of Florida and Water Resources Engineers, Inc. Section 2 of that volume prints seven Fortran IV routines — RUNOFF, GUTTER, HCURVE, HYDRO, RHYDRO, WSHED and the surface-quality routine SFQUAL. All seven were transcribed from the page images, translated statement for statement into C, and compiled to WebAssembly. The engine reads the same 80-column card images and writes the same line-printer report.

What is and is not here

  • Included: the whole Runoff Block — hydrology and gutter/pipe routing (RUNO, HYDR, RHYD, WSHE, GUTT), the card reader, the printed report, the hydrograph scratch tape (unit 10) and interface tape (unit 8), and SFQUAL, the Metcalf & Eddy surface-quality model (dust and dirt by land use, street sweeping, catch basins, BOD, suspended solids, coliforms), which rewrites the interface tape with NQUAL = 3 as the Transport Block expected.
  • Not included: the Executive Block printer plots (GRAPH, CURVE, PLOT, PPLOT) that HCURVE drives — HCURVE itself is translated; its CURVE call is a no-op. The Transport, Storage and Receiving Water Blocks (pages 41–248) are not transcribed.
  • SWMM 5 import: the converter punches a SWMM 1 deck from a SWMM 5 .inp — subcatchments to subarea cards (Horton or approximated from Green-Ampt), conduits to gutter/pipe cards (circular, trapezoidal, rectangular, triangular; other shapes as circular), weirs/orifices/outlets/pumps as pass-through elements, gage series to the 10F5.0 histogram (averaged to coarser blocks when a run needs more than 160 values), SI models converted to US units, and default surface-quality cards. It lists every approximation it makes. SWMM 1 limits apply: 160 subareas, 160 links, 10 gages, one inlet, no storage, no flow splitting.
  • SWMM 4 import: a SWMM 4 .DAT with a $RUNOFF block is converted the same way — H1 subcatchments, G1 gutters and pipes (NPG 1/2/3), E1/E3 rain cards (TZRAIN becomes leading zero intervals), J1/L1 quality, Green-Ampt (INFILM = 1) mapped to Horton. Transport inlets become pass-through elements and are the saved points. Decks whose rain comes from a Rain Block interface file, or that have no $RUNOFF block (the EXTRAN, Storage and Stats examples), are shown for reference and not run. The SWDAT1–6 and EXAM1–4 decks from SWMMEnablement/legacy-swmm-ai are in the sample list.
  • Two 1971 traps both converters work around: RHYD 181–185 fill NGTOI/NWTOI with a DO J=1,NIN loop, so at most 10 elements may discharge to the inlet — the 11th prints "… IS LARGER THAN THE ALLOWED NO" and STOPs. The converters chain extra terminal elements through added pass-through collector elements. And DO 340 I=1,NW / DO 480 I=1,NG (RHYD 71, 144) read at most 160 cards and never see a terminator after the 160th, so a group of exactly 160 cards is punched without one.
  • Deliberate differences: REAL is IEEE single precision rather than IBM hexadecimal floating point; blanks in numeric card fields are ignored rather than read as zeros; DO loops are zero-trip; STOP after a data error returns to the host instead of ending the job. Everything else, including the overflow of the NRANVL=200 clearing loop past HGRAPH(160), behaves as the listing says.

AI use

This app was built with Claude, Anthropic's AI model, in a Claude session on 22 October 2026, under the direction of Robert (Bob) Dickinson, who supplied the scanned listing, set the goal (the SWMM 1 engine in Fortran, as a wasm engine, with an HTML app) and reviews the result. Responsibility for the work is his.

What Claude did. It read the 25 Runoff Block pages as images, using the PDF's OCR layer only as a scaffold, and typed all seven routines (1,311 cards) back into fixed-form Fortran with their card identification fields; translated them line for line into C with the blank COMMON kept as one word array; wrote the Fortran-IV formatted-I/O runtime (card reader, FORMAT interpreter, carriage control, unformatted tapes); compiled the engine to WebAssembly with wasi-sdk; wrote the two sample decks, the SWMM 5 .inp converter, this page, the Doc essay and the Word version of it, and this text.

How it was checked. Mechanically: the wasm printout is byte-identical to the native C build on both sample decks, the engine is re-entrant (two runs, identical output), continuity errors are 0.14 % and 0.91 %, and the hyetograph/hydrograph charts are read from the engine's own tape and COMMON rather than re-computed. By reading: every transcribed line was compared with the page image; the eleven lines that needed a judgement are listed on the Fortran tab. Not yet checked by anyone: no run of the original 1971 program exists to compare against, so there is no value-by-value score against a printed 1971 output; the printer plots have not been transcribed; no person other than Claude has yet proof-read the transcription, and the SFQUAL washoff numbers in particular have only been checked for plausibility, not against a published example.

Sources

  • Metcalf & Eddy, Inc., University of Florida, Water Resources Engineers, Inc. (1971). Storm Water Management Model, Volume IV — Program Listing. EPA 11024 DOC 10/71. Section 2, Runoff Block, pp. 13–40.
  • Same authors (1971). Volume I — Final Report (11024 DOC 07/71) and Volume III — User's Manual (11024 DOC 09/71), for the meaning of the card fields.
  • wasi-sdk 24 (clang 18) for the wasm32 build; no runtime imports are used.