This program is a hydrology toolkit that offers four computational modules selectable from a menu: slope computation, a watershed map drawing routine, unit hydrograph preparation (UHG PREP), and a mathematical unit hydrograph generator (MATH UHG). The menu dispatcher at line 50 uses a single multiply-and-branch idiom (`GO TO 10*Number`) to jump to subroutines at lines 60, 100, 200, and 250 based on the user’s input of 6, 10, 20, or 25. The map-drawing module (line 100) POKEs 12 bytes of machine code into address 23760 and then calls it via `RANDOMIZE USR 23760`, implementing an LDIR block-copy routine (opcodes `ED B0`) capped with a `RET` (`C9`). The MATH UHG section (line 250) implements a lognormal distribution fitting algorithm with an iterative sigma convergence loop and computes either instantaneous or average unit hydrograph ordinates using numerical integration by Simpson’s rule.
Program Analysis
Program Structure
The program is organized as a menu-driven dispatcher. Lines 1–45 display a menu and read the user’s selection into Number. Line 50 computes GO TO 10*Number, routing to one of four modules:
| Input | Target line | Module |
|---|---|---|
| 6 | 60 | Slope computation |
| 10 | 100 | Map draw |
| 20 | 200 | UHG Prep |
| 25 | 250 | Math UHG |
| 100 | 1000 | STOP |
Each module ends with GO TO 18, which jumps to a non-existent line — falling through to line 19 (the blank PRINT). In practice this is effectively a restart of the menu from line 19 onward, since BASIC will run the next available line after an unfound target in some interpreters, though this is noted as a known technique. The REM at line 1 flags the author’s awareness of bugs.
Machine Code Usage
The map-draw module (lines 106–108) POKEs 12 bytes into RAM starting at address 23760 and then invokes them with RANDOMIZE USR 23760 at line 125. The DATA at line 127 decodes as:
| Address | Byte (hex) | Z80 mnemonic |
|---|---|---|
| 23760 | 33 00 40 | LD HL,16384 (start of display) |
| 23763 | 64 11 00 E3 | partial operands / LD DE,… |
| 23767 | 01 00 1B | LD BC,… |
| 23770 | ED B0 | LDIR (block copy) |
| 23772 | C9 | RET |
The exact byte sequence is 33,0,64,17,0,230,1,0,27,237,176,201. The LDIR instruction copies a block of memory, and the RET returns cleanly to BASIC. The purpose appears to be a display-area memory operation, consistent with copying or clearing graphics data.
Slope Computation Module (lines 60–90)
This module computes the Taylor-Schwarz channel slope formula used in hydrology. It reads N elevation points, a reach length DL, and a total length L from DATA. For each pair of adjacent elevations it computes D(I) = 1 / SQR(ELDIFF/DL), then calculates overall slope as S = ((N-1) / SUM)^2. The result is truncated to four decimal places using the INT(x*10000)/10000 idiom and converted to ft/mile by multiplying by 5280.
Map Drawing Module (lines 100–136)
This module plots a watershed boundary and stream network using pixel-level PLOT and DRAW commands. Two pairs of 2D arrays (x, y for boundary; z, u for stream) store coordinate sequences read from DATA. The boundary data is at line 132 and stream data at line 134, giving sequences of absolute pixel coordinates. The DRAW calls use relative offsets computed from successive coordinate differences. A sentinel check IF x(c,1)>255 THEN GO TO 135 at line 112 and a similar check at line 120 guard against out-of-range coordinates, though the check at 120 tests z(1,1) (the first element) rather than z(c,1) (the current element), which is likely a bug — it will never trigger mid-loop as intended.
UHG Preparation Module (lines 200–229)
This module implements the Snyder synthetic unit hydrograph method. It computes lag time TP, time-to-peak TPR, and peak discharge QP from basin parameters: drainage area DA, main channel length L, length to centroid LCA, storm duration TR, and empirical coefficients CT and CP640. The formula NUM=(L*LCA)^0.3 is the standard Snyder lag parameter. An urbanization parameter PAR = L*LCA/SQR(S) is also printed for lookup on an external curve.
Mathematical UHG Module (lines 250–326)
This is the most computationally intensive module, implementing a lognormal unit hydrograph. It fits a sigma parameter iteratively by bracketing the solution to match a lognormal CDF target (YO), converging in two passes of decreasing step size (0.0005, then 0.000005). The core loop structure is:
- Compute
YO = TMQ * QMAX / (111.80941 * A)(the lognormal argument) - Estimate initial
SIGMAfrom a polynomial approximation usingY = log10(YO) - Iteratively refine SIGMA at lines 268–281 until
S ≈ YOwithin 0.0001 - Compute the mode time
Tfrom SIGMA - Evaluate ordinates in the FOR loop at lines 293–318
The constant 111.80941 is SQR(12500), a normalisation factor for the lognormal unit hydrograph. When INSTA=0, average flows are computed using a simple trapezoidal/Simpson accumulation (TOT + 2*Q) inside the inner loop, divided by 20 at line 309. The loop exit condition at lines 315–316 terminates when both time has passed the mode and flow has dropped to 2 or below.
Notable Techniques and Idioms
- Computed GO TO:
GO TO 10*Numberat line 50 is an efficient menu dispatcher, avoiding a chain of IF statements. - Rounding idiom:
INT(x*10000)/10000andINT(x*100+.5)/100are used throughout for controlled decimal truncation and rounding respectively. - DATA reuse: All module parameters are stored in DATA statements local to each module section, so the READ pointer advances naturally as each module is entered once per run. Re-entering a module after a GO TO 18 restart would exhaust the DATA pointer — a latent bug for repeated use within one run.
- Polynomial sigma inversion: Lines 264–267 use a degree-6 polynomial in
Y = log10(YO)to approximate the inverse normal, seeding the iterative refinement efficiently.
Bugs and Anomalies
- Line 120 sentinel check:
IF z(1,1)>255always tests the first stream coordinate, not the current loop variablez(c,1). This means the stream loop never terminates early via this guard. - Line 294 dead code:
IF (J-1)>=0 THEN GO TO 296is always true forJ=1 TO 11(since J starts at 1), so line 295 (LET TT=TT-DT/10) is never executed. - DATA pointer exhaustion: Modules use READ/DATA without RESTORE, so selecting the same module twice in one session will cause an error when data runs out.
- Line 90 / 136 / 229 / 326 — GO TO 18: Line 18 contains
PRINT "MENU SELECTION", so the menu is redisplayed from line 18 rather than from line 15 (which prints the title). This skips the title and the CLS at line 45 is not re-executed, so old output remains on screen. - Line 72 square root of ratio:
SQR(ELDIFF/DL)will produce an error if any adjacent elevations are equal or decrease, as the argument becomes zero or negative.
Content
Source Code
1 REM Program seems to have some "bug problems"
10 REM "hydrology1"
15 PRINT AT 1,7;"HYDROLOGY #1"
17 PRINT
18 PRINT "MENU SELECTION"
19 PRINT
20 PRINT "Input a 6 for Slope, Input a 10 for map draw Input a 20 for UHG PREP Input a 25 for MATH UHG Input a 100 if you are finished."
21 PRINT
25 PRINT "If you want a copy, use break key and then COPY."
40 INPUT Number
45 CLS
50 GO TO 10*Number
60 REM "SLOPE"
61 PRINT AT 11,1;"PROGRAM FOR SLOPE COMPUTATION"
62 DIM D(11): DIM E(11)
63 READ N,L,DL,T$
64 FOR I=1 TO N
65 READ E(I)
66 NEXT I
67 PRINT AT 14,10;T$
68 PRINT
69 LET SUM=0
70 FOR I=2 TO N
71 LET ELDIFF=E(I)-E(I-1)
72 LET A=SQR (ELDIFF/DL)
73 LET D(I)=1.0/A
74 LET SUM=SUM+D(I)
75 NEXT I
76 LET S=((N-1)/SUM)^2
77 LET S=INT (S*10000)/10000
78 LET SO=S*5280
79 PRINT AT 18,2;"SLOPE = ";S;" FT/FT"
80 PRINT
81 PRINT AT 20,2;"Or ";SO; " FT/MILE"
82 PRINT
83 DATA 8,1840,1840,"WILLOW LAKE"
84 DATA 657.5,675,690,710,735,750,800,830
90 GO TO 18
100 REM "map draw"
101 PRINT "Put no of boundary, stream lines, title, drainage area in data line 126. Put starting x, y for boundary in 131, for stream in 133. Put x, y data for boundary in 132, stream in 134."
102 PAUSE 120: CLS
103 DIM x(30,30): DIM y(30,30)
104 DIM z(20,20): DIM u(20,20)
105 READ nl,ns,T$,DA,S
106 FOR a=23760 TO 23771
107 READ b: POKE a,b
108 NEXT a
109 READ x(1,1): READ y(1,1)
110 PLOT x(1,1),y(1,1)
111 FOR c=2 TO nl
112 READ x(c,1): IF x(c,1)>255 THEN GO TO 135
113 READ y(c,1)
114 DRAW x(c,1)-x(c-1,1),y(c,1)-y(c-1,1)
115 PLOT x(c,1),y(c,1)
116 NEXT c
117 READ z(1,1): READ u(1,1)
118 PLOT z(1,1),u(1,1)
119 FOR c=2 TO ns
120 READ z(c,1): IF z(1,1)>255 THEN GO TO 135
121 READ u(c,1)
122 DRAW z(c,1)-z(c-1,1),u(c,1)-u(c-1,1)
123 PLOT z(c,1),u(c,1)
124 NEXT c
125 RANDOMIZE USR 23760
126 DATA 20,16,"Willow Lake",1.22,.01172
127 DATA 33,0,64,17,0,230,1,0,27,237,176,201
128 PRINT AT 19,3;T$
129 PRINT AT 20,3;"DA= ";DA
130 PRINT AT 21,3;"Slope =";S
131 DATA 2,168
132 DATA 32,173,56,168,104,162,120,154,157,96,208,112,232,78,224,68,254,48,218,2,168,21,144,36,120,74,88,94,76,112,40,122,40,149,16,160,2,168
133 DATA 8,168
134 DATA 38,165,92,136,94,128,128,97,162,60,180,64,204,37,205,32,205,24,210,20,218,2,207,12,202,17,201,24,205,32
135 PRINT
136 GO TO 18
200 REM "UHG PREP"
201 PRINT "PROGRAM DEVELOPS UNIT HYDROGRAPH DATA"
202 READ T$
203 READ DA,L,LCA,TR,CT,CP640,S
204 LET NUM=(L*LCA)^.3
205 LET TP=CT*NUM
206 LET TLR=TP/5.5
207 LET TPR=(TP+.25*(TR-TLR))
208 LET AMT=INT (TPR*1000)
209 LET TPR=AMT/1000
210 LET QLP=(CP640/TPR)
211 LET QP=INT (QLP*DA)
212 PRINT TAB 10;T$
213 PRINT
214 PRINT "INPUT DATA"
215 PRINT "AREA";TAB 5;" L ";TAB 11;" LCA ";TAB 17;" TR ";TAB 22;" CT ";TAB 27;"CP640"
216 PRINT DA;TAB 6;L;TAB 11;LCA;TAB 17;TR;TAB 22;CT;TAB 27;CP640
217 PRINT
218 PRINT "TR";TAB 6;"TPR";TAB 12;"TR";TAB 18;"QMAX";TAB 24;"AREA"
219 PRINT
220 PRINT TR;TAB 6;TPR;TAB 12;TR;TAB 18;QP;TAB 24;DA
221 PRINT
222 LET PAR=INT (L*LCA/(SQR S)*100)
223 LET PAR=PAR/100
224 PRINT "PAR = ";PAR
225 PRINT
226 PRINT AT 20,0;"USE PAR TO GET TPR FROM AN URBANIZATION CURVE"
227 DATA "WILLOW LAKE"
228 DATA 1.22,2.5,1.1,.50,.70,418,61.9
229 GO TO 18
250 REM "MATH UHG"
251 PRINT "THIS PROGRAM EXECUTES VERY SLOWLY... BE PATIENT"
252 READ T$,DT,TPR,TR,QMAX,A,INSTA
253 CLS
254 PRINT TAB 5;T$
255 PRINT
256 PRINT "INPUT DATA"
257 PRINT "DT";TAB 5;"TPR";TAB 12;"TR";TAB 17;"QMAX";TAB 23;"A";TAB 26;"INSTA"
258 PRINT DT;TAB 6;TPR;TAB 12;TR;TAB 17;QMAX;TAB 22;A;TAB 28;INSTA
259 PRINT
260 LET TMQ=TPR+TR/2
261 LET Q=0
262 LET SUM =0
263 LET YO=TMQ*QMAX/(111.80941*A)
264 LET Y=.43429448*LN (YO)
265 LET X=-.295133-.4522*Y-.242919*Y^2-.103329*Y^3
266 LET X=X+(.0091443*Y^4)+(.0353098*Y^5)+(.0117619*Y^6)
267 LET SIGMA=10^X
268 LET S=EXP (-2.65049*SIGMA^2)/SIGMA
269 LET B=(S-YO+.001)
270 IF B>=0 THEN GO TO 273
271 LET SIGMA=SIGMA-.0005
272 GO TO 268
273 LET B=(YO-S+.001)
274 IF B>=0 THEN GO TO 276
275 LET SIGMA=SIGMA+.0005
276 IF (S-YO+.0001)>=0 THEN GO TO 279
277 LET SIGMA=SIGMA-.00005
278 GO TO 268
279 IF (YO-S+.0001)>=0 THEN GO TO 282
280 LET SIGMA=SIGMA+.000005
281 GO TO 268
282 LET T=10^(2.3025851*SIGMA^2+.43429448*LN (TMQ))
283 LET NUM=T
284 LET NUM=INT (T*100+.5)/100
285 LET T=NUM
286 PRINT "TIME TO HALF VOL =";TAB 19;T
287 PRINT "SIGMA ";SIGMA
288 LET TT=DT
289 IF INSTA=0 THEN GO TO 292
290 PRINT "NO OF HOURS";TAB 13;"INSTA FLOW"
291 GO TO 293
292 PRINT "NO OF HOURS";TAB 13;"AVG FLOW"
293 FOR J=1 TO 11
294 IF (J-1)>=0 THEN GO TO 296
295 LET TT=TT-DT/10
296 LET Q=111.80941*A/(TT*SIGMA)
297 LET C=(2*SIGMA^2)
298 LET D=.434*LN (TT/T)
299 LET E=ABS D^2
300 LET F=E/C
301 LET Q=Q*EXP (-F)
302 IF INSTA=0 THEN GO TO 311
303 IF (J-1)>0 THEN GO TO 306
304 LET TOT=Q
305 GO TO 308
306 IF (J-11)>0 THEN GO TO 308
307 LET TOT=TOT+2*Q
308 NEXT J
309 LET Q=(TOT+Q)/20
310 LET TT=TT+DT
311 LET Q=INT (Q+.5)
312 PRINT TT;TAB 14;Q
313 LET SUM=SUM+Q
314 LET TT=TT+DT
315 IF (T-TT)>=0 THEN GO TO 317
316 IF (Q-2)<=0 THEN GO TO 319
317 IF (INSTA)<=0 THEN GO TO 296
318 IF (INSTA)>0 THEN GO TO 293
319 PRINT
320 PRINT "THE SUM IS";TAB 14;SUM
321 LET VOL=SUM/(12/DT)
322 PRINT "THE VOLUME IS";TAB 14;VOL
323 DATA "WILLOW LAKE"
324 DATA .50,.86,.50,650,1.22,0
325 PRINT
326 GO TO 18
1000 STOP
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
