GCC Code Coverage Report


Directory: src/solver/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 96.1% 367 / 0 / 382
Functions: 100.0% 15 / 0 / 15
Branches: 88.7% 220 / 0 / 248

stats.c
Line Branch Exec Source
1 //-----------------------------------------------------------------------------
2 // stats.c
3 //
4 // Project: EPA SWMM5
5 // Version: 5.2
6 // Date: 11/01/21 (Build 5.2.0)
7 // Author: L. Rossman
8 // R. Dickinson (CDM)
9 //
10 // Simulation statistics functions.
11 //
12 // Update History
13 // ==============
14 // Build 5.1.007:
15 // - Exfiltration losses added to storage node statistics.
16 // Build 5.1.008:
17 // - Support for updating groundwater statistics added.
18 // - Support for updating maximum reported nodal depths added.
19 // - OpenMP parallelization applied to updating node and link flow statistics.
20 // - Updating of time that conduit is upstrm/dnstrm full was modified.
21 // Build 5.1.011:
22 // - Surcharging is now evaluated only under dynamic wave flow routing and
23 // storage nodes cannot be classified as surcharged.
24 // Build 5.1.012:
25 // - Time step statistics now evaluated only in non-steady state periods.
26 // - Check for full conduit flow now accounts for number of barrels.
27 // Build 5.1.013:
28 // - Include omp.h protected against lack of compiler support for OpenMP.
29 // - Statistics on impervious and pervious runoff totals added.
30 // - Storage nodes with a non-zero surcharge depth (e.g. enclosed tanks)
31 // can now be classified as being surcharged.
32 // Build 5.1.015:
33 // - Fixes bug in summary statistics when Report Start date > Start Date.
34 // - Fixes failure to initialize all subcatchment groundwater statistics.
35 // - Support added for grouped freqency table of routing time steps.
36 // Build 5.2.0:
37 // - Support added for reporting most frequent non-converging nodes.
38 // - Support added for RptFlags.disabled option.
39 // - Fixed display of routing statistics report for RptFlags.flowStats = FALSE.
40 //-----------------------------------------------------------------------------
41 #define _CRT_SECURE_NO_DEPRECATE
42
43 #include <stdlib.h>
44 #include <string.h>
45 #include <math.h>
46 #include "headers.h"
47
48 //-----------------------------------------------------------------------------
49 // Shared variables
50 //-----------------------------------------------------------------------------
51 #define MAX_STATS 5
52 static TTimeStepStats TimeStepStats;
53 static TMaxStats MaxMassBalErrs[MAX_STATS];
54 static TMaxStats MaxCourantCrit[MAX_STATS];
55 static TMaxStats MaxFlowTurns[MAX_STATS];
56 static TMaxStats MaxNonConverged[MAX_STATS];
57 static double SysOutfallFlow;
58
59 //-----------------------------------------------------------------------------
60 // Exportable variables (shared with statsrpt.c)
61 //-----------------------------------------------------------------------------
62 TSubcatchStats* SubcatchStats;
63 TNodeStats* NodeStats;
64 TLinkStats* LinkStats;
65 TStorageStats* StorageStats;
66 TOutfallStats* OutfallStats;
67 TPumpStats* PumpStats;
68 double MaxOutfallFlow;
69 double MaxRunoffFlow;
70 double RoutingTimeSpan;
71
72 //-----------------------------------------------------------------------------
73 // Imported variables
74 //-----------------------------------------------------------------------------
75 extern double* NodeInflow; // defined in massbal.c
76 extern double* NodeOutflow; // defined in massbal.c
77
78 //-----------------------------------------------------------------------------
79 // External functions (declared in funcs.h)
80 //-----------------------------------------------------------------------------
81 // stats_open (called from swmm_start in swmm5.c)
82 // stats_close (called from swmm_end in swmm5.c)
83 // stats_report (called from swmm_end in swmm5.c)
84 // stats_updateSubcatchStats (called from subcatch_getRunoff)
85 // stats_updateGwaterStats (called from gwater_getGroundwater)
86 // stats_updateFlowStats (called from routing_execute)
87 // stats_updateTimeStepStats (called from routing_execute)
88 // stats_updateCriticalTimeCount (called from getVariableStep in dynwave.c)
89 // stats_updateMaxNodeDepth (called from output_saveNodeResults)
90 // stats_updateConvergenceStats (called from updateConvergenceStats in dynwave.c)
91
92 //-----------------------------------------------------------------------------
93 // Local functions
94 //-----------------------------------------------------------------------------
95 static void stats_updateNodeStats(int node, double tStep, DateTime aDate);
96 static void stats_updateLinkStats(int link, double tStep, DateTime aDate);
97 static void stats_findMaxStats(void);
98 static void stats_updateMaxStats(TMaxStats maxStats[], int i, int j, double x);
99
100 //=============================================================================
101
102 61 int stats_open()
103 //
104 // Input: none
105 // Output: returns an error code
106 // Purpose: opens the simulation statistics system.
107 //
108 {
109 int j, k;
110 double timeStepDelta;
111 double logMaxTimeStep;
112 double logMinTimeStep;
113
114 // --- set all pointers to NULL
115 61 NodeStats = NULL;
116 61 LinkStats = NULL;
117 61 StorageStats = NULL;
118 61 OutfallStats = NULL;
119 61 PumpStats = NULL;
120
121 // --- allocate memory for & initialize subcatchment statistics
122 61 SubcatchStats = NULL;
123
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 26 times.
61 if ( Nobjects[SUBCATCH] > 0 )
124 {
125 35 SubcatchStats = (TSubcatchStats *) calloc(Nobjects[SUBCATCH],
126 sizeof(TSubcatchStats));
127
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 if ( !SubcatchStats )
128 {
129 report_writeErrorMsg(ERR_MEMORY, "");
130 return ErrorCode;
131 }
132
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 35 times.
131 for (j=0; j<Nobjects[SUBCATCH]; j++)
133 {
134 96 SubcatchStats[j].precip = 0.0;
135 96 SubcatchStats[j].runon = 0.0;
136 96 SubcatchStats[j].evap = 0.0;
137 96 SubcatchStats[j].infil = 0.0;
138 96 SubcatchStats[j].runoff = 0.0;
139 96 SubcatchStats[j].maxFlow = 0.0;
140 96 SubcatchStats[j].impervRunoff = 0.0;
141 96 SubcatchStats[j].pervRunoff = 0.0;
142 }
143
144
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 35 times.
131 for (j=0; j<Nobjects[SUBCATCH]; j++)
145 {
146
2/2
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 10 times.
96 if ( Subcatch[j].groundwater == NULL ) continue;
147 10 Subcatch[j].groundwater->stats.avgUpperMoist = 0.0;
148 10 Subcatch[j].groundwater->stats.avgWaterTable = 0.0;
149 10 Subcatch[j].groundwater->stats.infil = 0.0;
150 10 Subcatch[j].groundwater->stats.latFlow = 0.0;
151 10 Subcatch[j].groundwater->stats.deepFlow = 0.0;
152 10 Subcatch[j].groundwater->stats.evap = 0.0;
153 10 Subcatch[j].groundwater->stats.maxFlow = 0.0;
154 10 Subcatch[j].groundwater->stats.finalUpperMoist = 0.0;
155 10 Subcatch[j].groundwater->stats.finalWaterTable = 0.0;
156 }
157 }
158
159 // --- allocate memory for node & link stats
160
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 10 times.
61 if ( Nobjects[LINK] > 0 )
161 {
162 51 NodeStats = (TNodeStats *) calloc(Nobjects[NODE], sizeof(TNodeStats));
163 51 LinkStats = (TLinkStats *) calloc(Nobjects[LINK], sizeof(TLinkStats));
164
2/4
✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 51 times.
51 if ( !NodeStats || !LinkStats )
165 {
166 report_writeErrorMsg(ERR_MEMORY, "");
167 return ErrorCode;
168 }
169 }
170
171 // --- initialize node stats
172
4/4
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 413 times.
✓ Branch 3 taken 51 times.
474 if ( NodeStats ) for ( j = 0; j < Nobjects[NODE]; j++ )
173 {
174 413 NodeStats[j].avgDepth = 0.0;
175 413 NodeStats[j].maxDepth = 0.0;
176 413 NodeStats[j].maxDepthDate = StartDateTime;
177 413 NodeStats[j].maxRptDepth = 0.0;
178 413 NodeStats[j].volFlooded = 0.0;
179 413 NodeStats[j].timeFlooded = 0.0;
180 413 NodeStats[j].timeSurcharged = 0.0;
181 413 NodeStats[j].timeCourantCritical = 0.0;
182 413 NodeStats[j].totLatFlow = 0.0;
183 413 NodeStats[j].maxLatFlow = 0.0;
184 413 NodeStats[j].maxInflow = 0.0;
185 413 NodeStats[j].maxOverflow = 0.0;
186 413 NodeStats[j].maxPondedVol = 0.0;
187 413 NodeStats[j].nonConvergedCount = 0;
188 413 NodeStats[j].maxInflowDate = StartDateTime;
189 413 NodeStats[j].maxOverflowDate = StartDateTime;
190 }
191
192 // --- initialize link stats
193
4/4
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 332 times.
✓ Branch 3 taken 51 times.
393 if ( LinkStats ) for ( j = 0; j < Nobjects[LINK]; j++ )
194 {
195 332 LinkStats[j].maxFlow = 0.0;
196 332 LinkStats[j].maxVeloc = 0.0;
197 332 LinkStats[j].maxDepth = 0.0;
198 332 LinkStats[j].maxStreetFilled = 0.0;
199 332 LinkStats[j].timeSurcharged = 0.0;
200 332 LinkStats[j].timeFullUpstream = 0.0;
201 332 LinkStats[j].timeFullDnstream = 0.0;
202 332 LinkStats[j].timeFullFlow = 0.0;
203 332 LinkStats[j].timeCapacityLimited = 0.0;
204 332 LinkStats[j].timeCourantCritical = 0.0;
205
2/2
✓ Branch 0 taken 2324 times.
✓ Branch 1 taken 332 times.
2656 for (k=0; k<MAX_FLOW_CLASSES; k++)
206 2324 LinkStats[j].timeInFlowClass[k] = 0.0;
207 332 LinkStats[j].flowTurns = 0;
208 332 LinkStats[j].flowTurnSign = 0;
209 }
210
211 // --- allocate memory for & initialize storage unit statistics
212
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 44 times.
61 if ( Nnodes[STORAGE] > 0 )
213 {
214 17 StorageStats = (TStorageStats *) calloc(Nnodes[STORAGE],
215 sizeof(TStorageStats));
216
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if ( !StorageStats )
217 {
218 report_writeErrorMsg(ERR_MEMORY, "");
219 return ErrorCode;
220 }
221
2/2
✓ Branch 0 taken 225 times.
✓ Branch 1 taken 17 times.
242 else for ( k = 0; k < Nobjects[NODE]; k++ )
222 {
223
2/2
✓ Branch 0 taken 185 times.
✓ Branch 1 taken 40 times.
225 if ( Node[k].type != STORAGE ) continue;
224 40 j = Node[k].subIndex;
225 40 StorageStats[j].initVol = Node[k].newVolume;
226 40 StorageStats[j].avgVol = 0.0;
227 40 StorageStats[j].maxVol = 0.0;
228 40 StorageStats[j].maxFlow = 0.0;
229 40 StorageStats[j].evapLosses = 0.0;
230 40 StorageStats[j].exfilLosses = 0.0;
231 40 StorageStats[j].maxVolDate = StartDateTime;
232 }
233 }
234
235 // --- allocate memory for & initialize outfall statistics
236
1/2
✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
61 if ( Nnodes[OUTFALL] > 0 )
237 {
238 61 OutfallStats = (TOutfallStats *) calloc(Nnodes[OUTFALL],
239 sizeof(TOutfallStats));
240
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
61 if ( !OutfallStats )
241 {
242 report_writeErrorMsg(ERR_MEMORY, "");
243 return ErrorCode;
244 }
245
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 61 times.
173 else for ( j = 0; j < Nnodes[OUTFALL]; j++ )
246 {
247 112 OutfallStats[j].avgFlow = 0.0;
248 112 OutfallStats[j].maxFlow = 0.0;
249 112 OutfallStats[j].totalPeriods = 0;
250
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 103 times.
112 if ( Nobjects[POLLUT] > 0 )
251 {
252 9 OutfallStats[j].totalLoad =
253 9 (double *) calloc(Nobjects[POLLUT], sizeof(double));
254
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if ( !OutfallStats[j].totalLoad )
255 {
256 report_writeErrorMsg(ERR_MEMORY, "");
257 return ErrorCode;
258 }
259
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 9 times.
34 for (k=0; k<Nobjects[POLLUT]; k++)
260 25 OutfallStats[j].totalLoad[k] = 0.0;
261 }
262 103 else OutfallStats[j].totalLoad = NULL;
263 }
264 }
265
266 // --- allocate memory & initialize pumping statistics
267
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 58 times.
61 if ( Nlinks[PUMP] > 0 )
268 {
269 3 PumpStats = (TPumpStats *) calloc(Nlinks[PUMP], sizeof(TPumpStats));
270
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if ( !PumpStats )
271 {
272 report_writeErrorMsg(ERR_MEMORY, "");
273 return ErrorCode;
274 }
275
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 3 times.
12 else for ( j = 0; j < Nlinks[PUMP]; j++ )
276 {
277 9 PumpStats[j].utilized = 0.0;
278 9 PumpStats[j].minFlow = 0.0;
279 9 PumpStats[j].avgFlow = 0.0;
280 9 PumpStats[j].maxFlow = 0.0;
281 9 PumpStats[j].volume = 0.0;
282 9 PumpStats[j].energy = 0.0;
283 9 PumpStats[j].startUps = 0;
284 9 PumpStats[j].offCurveLow = 0.0;
285 9 PumpStats[j].offCurveHigh = 0.0;
286 }
287 }
288
289 // --- initialize system stats
290 61 MaxRunoffFlow = 0.0;
291 61 MaxOutfallFlow = 0.0;
292 61 TimeStepStats.maxTimeStep = 0.0;
293 61 TimeStepStats.minTimeStep = RouteStep;
294 61 TimeStepStats.routingTime = 0.0;
295 61 TimeStepStats.trialsCount = 0.0;
296 61 TimeStepStats.steadyStateTime = 0.0;
297 61 TimeStepStats.timeStepCount = 0;
298
299 // --- divide range between min and max routing time steps into
300 // equal intervals using a logarithmic scale
301 61 logMaxTimeStep = log10(RouteStep);
302 61 logMinTimeStep = log10(MinRouteStep);
303 61 timeStepDelta = (logMaxTimeStep - logMinTimeStep) / (double)(TIMELEVELS-1);
304 61 TimeStepStats.timeStepIntervals[0] = RouteStep;
305
2/2
✓ Branch 0 taken 305 times.
✓ Branch 1 taken 61 times.
366 for (j = 1; j < TIMELEVELS; j++)
306 {
307 305 TimeStepStats.timeStepIntervals[j] =
308 305 pow(10., logMaxTimeStep - j * timeStepDelta);
309 305 TimeStepStats.timeStepCounts[j] = 0;
310 }
311 61 TimeStepStats.timeStepIntervals[TIMELEVELS - 1] = MinRouteStep;
312 61 RoutingTimeSpan = 0.0;
313 61 return 0;
314 }
315
316 //=============================================================================
317
318 61 void stats_close()
319 //
320 // Input: none
321 // Output:
322 // Purpose: closes the simulation statistics system.
323 //
324 {
325 int j;
326
327
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 26 times.
61 FREE(SubcatchStats);
328
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 10 times.
61 FREE(NodeStats);
329
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 10 times.
61 FREE(LinkStats);
330
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 44 times.
61 FREE(StorageStats);
331
1/2
✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
61 if ( OutfallStats )
332 {
333
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 61 times.
173 for ( j=0; j<Nnodes[OUTFALL]; j++ )
334
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 103 times.
112 FREE(OutfallStats[j].totalLoad);
335
1/2
✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
61 FREE(OutfallStats);
336 }
337
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 58 times.
61 FREE(PumpStats);
338 61 }
339
340 //=============================================================================
341
342 61 void stats_report()
343 //
344 // Input: none
345 // Output: none
346 // Purpose: reports simulation statistics.
347 //
348 {
349 // --- report flow routing accuracy statistics
350
3/4
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 51 times.
✗ Branch 3 not taken.
61 if ( Nobjects[LINK] > 0 && RouteModel != NO_ROUTING )
351 {
352 51 stats_findMaxStats();
353
2/4
✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 51 times.
✗ Branch 3 not taken.
51 if (!RptFlags.disabled && RptFlags.flowStats)
354 {
355 51 report_writeMaxStats(MaxMassBalErrs, MaxCourantCrit, MAX_STATS);
356 51 report_writeMaxFlowTurns(MaxFlowTurns, MAX_STATS);
357 51 report_writeNonconvergedStats(MaxNonConverged, MAX_STATS);
358 51 report_writeTimeStepStats(&TimeStepStats);
359 }
360 }
361
362 // --- report summary statistics
363
1/2
✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
61 if (!RptFlags.disabled)
364 61 statsrpt_writeReport();
365 61 }
366
367 //=============================================================================
368
369 118699 void stats_updateSubcatchStats(int j, double rainVol, double runonVol,
370 double evapVol, double infilVol,
371 double impervVol, double pervVol,
372 double runoffVol, double runoff)
373 //
374 // Input: j = subcatchment index
375 // rainVol = rainfall + snowfall volume (ft3)
376 // runonVol = runon volume from other subcatchments (ft3)
377 // evapVol = evaporation volume (ft3)
378 // infilVol = infiltration volume (ft3)
379 // impervVol = impervious runoff volume (ft3)
380 // pervVol = pervious runoff volume (ft3)
381 // runoffVol = runoff volume (ft3)
382 // runoff = runoff rate (cfs)
383 // Output: none
384 // Purpose: updates totals of runoff components for a specific subcatchment.
385 //
386 {
387 118699 SubcatchStats[j].precip += rainVol;
388 118699 SubcatchStats[j].runon += runonVol;
389 118699 SubcatchStats[j].evap += evapVol;
390 118699 SubcatchStats[j].infil += infilVol;
391 118699 SubcatchStats[j].runoff += runoffVol;
392
2/2
✓ Branch 0 taken 115484 times.
✓ Branch 1 taken 3215 times.
118699 SubcatchStats[j].maxFlow = MAX(SubcatchStats[j].maxFlow, runoff);
393 118699 SubcatchStats[j].impervRunoff += impervVol;
394 118699 SubcatchStats[j].pervRunoff += pervVol;
395 118699 }
396
397 //=============================================================================
398
399 26160 void stats_updateGwaterStats(int j, double infil, double evap, double latFlow,
400 double deepFlow, double theta, double waterTable,
401 double tStep)
402 {
403 26160 Subcatch[j].groundwater->stats.infil += infil * tStep;
404 26160 Subcatch[j].groundwater->stats.evap += evap * tStep;
405 26160 Subcatch[j].groundwater->stats.latFlow += latFlow * tStep;
406 26160 Subcatch[j].groundwater->stats.deepFlow += deepFlow * tStep;
407 26160 Subcatch[j].groundwater->stats.avgUpperMoist += theta * tStep;
408 26160 Subcatch[j].groundwater->stats.avgWaterTable += waterTable * tStep;
409 26160 Subcatch[j].groundwater->stats.finalUpperMoist = theta;
410 26160 Subcatch[j].groundwater->stats.finalWaterTable = waterTable;
411
2/2
✓ Branch 0 taken 860 times.
✓ Branch 1 taken 25300 times.
26160 if ( fabs(latFlow) > fabs(Subcatch[j].groundwater->stats.maxFlow) )
412 {
413 860 Subcatch[j].groundwater->stats.maxFlow = latFlow;
414 }
415 26160 }
416
417 //=============================================================================
418
419 25711 void stats_updateMaxRunoff()
420 //
421 // Input: none
422 // Output: updates global variable MaxRunoffFlow
423 // Purpose: updates value of maximum system runoff rate.
424 //
425 {
426 int j;
427 25711 double sysRunoff = 0.0;
428
429
2/2
✓ Branch 0 taken 118699 times.
✓ Branch 1 taken 25711 times.
144410 for (j=0; j<Nobjects[SUBCATCH]; j++) sysRunoff += Subcatch[j].newRunoff;
430
2/2
✓ Branch 0 taken 23944 times.
✓ Branch 1 taken 1767 times.
25711 MaxRunoffFlow = MAX(MaxRunoffFlow, sysRunoff);
431 25711 }
432
433 //=============================================================================
434
435 1584078 void stats_updateMaxNodeDepth(int j, double depth)
436 //
437 // Input: j = node index
438 // depth = water depth at node at current reporting time (ft)
439 // Output: none
440 // Purpose: updates a node's maximum depth recorded at reporting times.
441 //
442 {
443
2/2
✓ Branch 0 taken 1581366 times.
✓ Branch 1 taken 2712 times.
1584078 if ( NodeStats != NULL )
444
2/2
✓ Branch 0 taken 1542964 times.
✓ Branch 1 taken 38402 times.
1581366 NodeStats[j].maxRptDepth = MAX(NodeStats[j].maxRptDepth, depth);
445 1584078 }
446
447 //=============================================================================
448
449 1051534 void stats_updateFlowStats(double tStep, DateTime aDate)
450 //
451 // Input: tStep = routing time step (sec)
452 // aDate = current date/time
453 // Output: none
454 // Purpose: updates various flow routing statistics at current time period.
455 //
456 {
457 int j;
458
459 // --- update stats only after reporting period begins
460
2/2
✓ Branch 0 taken 2148 times.
✓ Branch 1 taken 1049386 times.
1051534 if ( aDate < ReportStart ) return;
461 1049386 SysOutfallFlow = 0.0;
462
463 // --- update node & link stats
464 //#pragma omp parallel num_threads(NumThreads)
465 {
466 // #pragma omp for
467
2/2
✓ Branch 0 taken 17756924 times.
✓ Branch 1 taken 1049386 times.
18806310 for ( j=0; j<Nobjects[NODE]; j++ )
468 17756924 stats_updateNodeStats(j, tStep, aDate);
469 // #pragma omp for
470
2/2
✓ Branch 0 taken 16737938 times.
✓ Branch 1 taken 1049386 times.
17787324 for ( j=0; j<Nobjects[LINK]; j++ )
471 16737938 stats_updateLinkStats(j, tStep, aDate);
472 }
473
474 // --- update count of time steps taken after reporting begins
475 1049386 ReportStepCount++;
476 1049386 RoutingTimeSpan += tStep;
477
478 // --- update max. system outfall flow
479
2/2
✓ Branch 0 taken 970564 times.
✓ Branch 1 taken 78822 times.
1049386 MaxOutfallFlow = MAX(MaxOutfallFlow, SysOutfallFlow);
480 }
481
482 //=============================================================================
483
484 1051534 void stats_updateTimeStepStats(double tStep, int trialsCount, int steadyState)
485 //
486 // Input: tStep = current flow routing time step (sec)
487 // trialsCount = number of trials used to solve routing
488 // steadyState = TRUE if steady flow conditions exist
489 // Output: none
490 // Purpose: updates flow routing time step statistics.
491 //
492 {
493 int j;
494
495 // --- update time step stats if not in steady state
496 1051534 TimeStepStats.steadyStateTime += steadyState * tStep;
497
1/2
✓ Branch 0 taken 1051534 times.
✗ Branch 1 not taken.
1051534 if (steadyState == FALSE)
498 {
499 // --- skip initial time step for min. value)
500
2/2
✓ Branch 0 taken 1051485 times.
✓ Branch 1 taken 49 times.
1051534 if (OldRoutingTime > 0)
501 {
502
2/2
✓ Branch 0 taken 1050902 times.
✓ Branch 1 taken 583 times.
1051485 TimeStepStats.minTimeStep = MIN(TimeStepStats.minTimeStep, tStep);
503
504 // --- locate interval that logged time step falls in
505 // and update its count
506
1/2
✓ Branch 0 taken 1052467 times.
✗ Branch 1 not taken.
1052467 for (j = 1; j < TIMELEVELS; j++)
507
2/2
✓ Branch 0 taken 1051485 times.
✓ Branch 1 taken 982 times.
1052467 if (tStep >= TimeStepStats.timeStepIntervals[j])
508 {
509 1051485 TimeStepStats.timeStepCounts[j]++;
510 1051485 break;
511 }
512 }
513
2/2
✓ Branch 0 taken 1051452 times.
✓ Branch 1 taken 82 times.
1051534 TimeStepStats.maxTimeStep = MAX(TimeStepStats.maxTimeStep, tStep);
514 1051534 TimeStepStats.routingTime += tStep;
515 1051534 TimeStepStats.timeStepCount++;
516 1051534 TimeStepStats.trialsCount += trialsCount;
517 }
518 1051534 }
519
520 //=============================================================================
521
522 250504 void stats_updateCriticalTimeCount(int node, int link)
523 //
524 // Input: node = node index
525 // link = link index
526 // Output: none
527 // Purpose: updates count of times a node or link was time step-critical.
528 //
529 {
530
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 250504 times.
250504 if ( node >= 0 ) NodeStats[node].timeCourantCritical += 1.0;
531
2/2
✓ Branch 0 taken 5179 times.
✓ Branch 1 taken 245325 times.
250504 else if ( link >= 0 ) LinkStats[link].timeCourantCritical += 1.0;
532 250504 }
533
534 //=============================================================================
535
536 970889 void stats_updateConvergenceStats(int node, int converged)
537 {
538
2/2
✓ Branch 0 taken 127488 times.
✓ Branch 1 taken 843401 times.
970889 if (converged == FALSE) NodeStats[node].nonConvergedCount++;
539 970889 }
540
541 //=============================================================================
542
543 17756924 void stats_updateNodeStats(int j, double tStep, DateTime aDate)
544 //
545 // Input: j = node index
546 // tStep = routing time step (sec)
547 // aDate = current date/time
548 // Output: none
549 // Purpose: updates flow statistics for a node.
550 //
551 {
552 int k, p;
553 17756924 double newVolume = Node[j].newVolume;
554 17756924 double newDepth = Node[j].newDepth;
555
4/4
✓ Branch 0 taken 735488 times.
✓ Branch 1 taken 17021436 times.
✓ Branch 2 taken 432230 times.
✓ Branch 3 taken 303258 times.
17756924 int canPond = (AllowPonding && Node[j].pondedArea > 0.0);
556
557 // --- update depth statistics
558 17756924 NodeStats[j].avgDepth += newDepth;
559
2/2
✓ Branch 0 taken 805025 times.
✓ Branch 1 taken 16951899 times.
17756924 if ( newDepth > NodeStats[j].maxDepth )
560 {
561 805025 NodeStats[j].maxDepth = newDepth;
562 805025 NodeStats[j].maxDepthDate = aDate;
563 }
564
565 // --- update flooding, ponding, and surcharge statistics
566
2/2
✓ Branch 0 taken 16438654 times.
✓ Branch 1 taken 1318270 times.
17756924 if ( Node[j].type != OUTFALL )
567 {
568
4/4
✓ Branch 0 taken 16350381 times.
✓ Branch 1 taken 88273 times.
✓ Branch 2 taken 41093 times.
✓ Branch 3 taken 16309288 times.
16438654 if ( newVolume > Node[j].fullVolume || Node[j].overflow > 0.0 )
569 {
570 129366 NodeStats[j].timeFlooded += tStep;
571 129366 NodeStats[j].volFlooded += Node[j].overflow * tStep;
572
2/2
✓ Branch 0 taken 88273 times.
✓ Branch 1 taken 41093 times.
217639 if ( canPond ) NodeStats[j].maxPondedVol =
573
2/2
✓ Branch 0 taken 61258 times.
✓ Branch 1 taken 27015 times.
88273 MAX(NodeStats[j].maxPondedVol,
574 (newVolume - Node[j].fullVolume));
575 }
576
577 // --- for dynamic wave routing, classify a node as
578 // surcharged if its water level exceeds its crown elev.
579
2/2
✓ Branch 0 taken 4444315 times.
✓ Branch 1 taken 11994339 times.
16438654 if (RouteModel == DW)
580 {
581
3/4
✓ Branch 0 taken 164361 times.
✓ Branch 1 taken 4279954 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 164361 times.
4444315 if ((Node[j].type != STORAGE || Node[j].surDepth > 0.0) &&
582
2/2
✓ Branch 0 taken 195741 times.
✓ Branch 1 taken 4084213 times.
4279954 newDepth + Node[j].invertElev + FUDGE >= Node[j].crownElev)
583 {
584 195741 NodeStats[j].timeSurcharged += tStep;
585 }
586 }
587 }
588
589 // --- update storage statistics
590
2/2
✓ Branch 0 taken 178401 times.
✓ Branch 1 taken 17578523 times.
17756924 if ( Node[j].type == STORAGE )
591 {
592 178401 k = Node[j].subIndex;
593 178401 StorageStats[k].avgVol += newVolume;
594 178401 StorageStats[k].evapLosses +=
595 178401 Storage[Node[j].subIndex].evapLoss;
596 178401 StorageStats[k].exfilLosses +=
597 178401 Storage[Node[j].subIndex].exfilLoss;
598
599
1/2
✓ Branch 0 taken 178401 times.
✗ Branch 1 not taken.
178401 newVolume = MIN(newVolume, Node[j].fullVolume);
600
2/2
✓ Branch 0 taken 36928 times.
✓ Branch 1 taken 141473 times.
178401 if ( newVolume > StorageStats[k].maxVol )
601 {
602 36928 StorageStats[k].maxVol = newVolume;
603 36928 StorageStats[k].maxVolDate = aDate;
604 }
605
2/2
✓ Branch 0 taken 146445 times.
✓ Branch 1 taken 31956 times.
178401 StorageStats[k].maxFlow = MAX(StorageStats[k].maxFlow, Node[j].outflow);
606 }
607
608 // --- update outfall statistics
609
2/2
✓ Branch 0 taken 1318270 times.
✓ Branch 1 taken 16438654 times.
17756924 if ( Node[j].type == OUTFALL )
610 {
611 1318270 k = Node[j].subIndex;
612
2/2
✓ Branch 0 taken 579935 times.
✓ Branch 1 taken 738335 times.
1318270 if ( Node[j].inflow >= MIN_RUNOFF_FLOW )
613 {
614 579935 OutfallStats[k].avgFlow += Node[j].inflow;
615
2/2
✓ Branch 0 taken 427979 times.
✓ Branch 1 taken 151956 times.
579935 OutfallStats[k].maxFlow = MAX(OutfallStats[k].maxFlow, Node[j].inflow);
616 579935 OutfallStats[k].totalPeriods++;
617 }
618
2/2
✓ Branch 0 taken 388691 times.
✓ Branch 1 taken 1318270 times.
1706961 for (p=0; p<Nobjects[POLLUT]; p++)
619 {
620 388691 OutfallStats[k].totalLoad[p] +=
621 388691 Node[j].inflow * Node[j].newQual[p] * tStep;
622 }
623 1318270 SysOutfallFlow += Node[j].inflow;
624 }
625
626 // --- update inflow statistics
627 17756924 NodeStats[j].totLatFlow +=
628 17756924 ((Node[j].oldLatFlow + Node[j].newLatFlow) * 0.5 * tStep );
629
2/2
✓ Branch 0 taken 203826 times.
✓ Branch 1 taken 17553098 times.
17756924 if ( fabs(Node[j].newLatFlow) > fabs(NodeStats[j].maxLatFlow) )
630 203826 NodeStats[j].maxLatFlow = Node[j].newLatFlow;
631
2/2
✓ Branch 0 taken 707718 times.
✓ Branch 1 taken 17049206 times.
17756924 if ( Node[j].inflow > NodeStats[j].maxInflow )
632 {
633 707718 NodeStats[j].maxInflow = Node[j].inflow;
634 707718 NodeStats[j].maxInflowDate = aDate;
635 }
636
637 // --- update overflow statistics
638
2/2
✓ Branch 0 taken 12317 times.
✓ Branch 1 taken 17744607 times.
17756924 if ( Node[j].overflow > NodeStats[j].maxOverflow )
639 {
640 12317 NodeStats[j].maxOverflow = Node[j].overflow;
641 12317 NodeStats[j].maxOverflowDate = aDate;
642 }
643 17756924 }
644
645 //=============================================================================
646
647 16737938 void stats_updateLinkStats(int j, double tStep, DateTime aDate)
648 //
649 // Input: j = link index
650 // tStep = routing time step (sec)
651 // aDate = current date/time
652 // Output: none
653 // Purpose: updates flow statistics for a link.
654 //
655 {
656 int k;
657 double q, v;
658 double dq;
659
660 // --- update max. flow
661 16737938 dq = Link[j].newFlow - Link[j].oldFlow;
662 16737938 q = fabs(Link[j].newFlow);
663
2/2
✓ Branch 0 taken 643341 times.
✓ Branch 1 taken 16094597 times.
16737938 if ( q > LinkStats[j].maxFlow )
664 {
665 643341 LinkStats[j].maxFlow = q;
666 643341 LinkStats[j].maxFlowDate = aDate;
667 }
668
669 // --- update max. velocity
670 16737938 v = link_getVelocity(j, q, Link[j].newDepth);
671
2/2
✓ Branch 0 taken 427683 times.
✓ Branch 1 taken 16310255 times.
16737938 if ( v > LinkStats[j].maxVeloc )
672 {
673 427683 LinkStats[j].maxVeloc = v;
674 }
675
676 // --- update max. depth
677
2/2
✓ Branch 0 taken 682014 times.
✓ Branch 1 taken 16055924 times.
16737938 if ( Link[j].newDepth > LinkStats[j].maxDepth )
678 {
679 682014 LinkStats[j].maxDepth = Link[j].newDepth;
680 }
681
682
2/2
✓ Branch 0 taken 29161 times.
✓ Branch 1 taken 16708777 times.
16737938 if ( Link[j].type == PUMP )
683 {
684
2/2
✓ Branch 0 taken 930 times.
✓ Branch 1 taken 28231 times.
29161 if ( q >= Link[j].qFull )
685 930 LinkStats[j].timeFullFlow += tStep;
686
2/2
✓ Branch 0 taken 18275 times.
✓ Branch 1 taken 10886 times.
29161 if ( q > MIN_RUNOFF_FLOW )
687 {
688 18275 k = Link[j].subIndex;
689
1/2
✓ Branch 0 taken 18275 times.
✗ Branch 1 not taken.
18275 PumpStats[k].minFlow = MIN(PumpStats[k].minFlow, q);
690 18275 PumpStats[k].maxFlow = LinkStats[j].maxFlow;
691 18275 PumpStats[k].avgFlow += q;
692 18275 PumpStats[k].volume += q*tStep;
693 18275 PumpStats[k].utilized += tStep;
694 18275 PumpStats[k].energy += link_getPower(j)*tStep/3600.0;
695
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18275 times.
18275 if ( Link[j].flowClass == DN_DRY )
696 PumpStats[k].offCurveLow += tStep;
697
2/2
✓ Branch 0 taken 11374 times.
✓ Branch 1 taken 6901 times.
18275 if ( Link[j].flowClass == UP_DRY )
698 11374 PumpStats[k].offCurveHigh += tStep;
699
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 18263 times.
18275 if ( Link[j].oldFlow < MIN_RUNOFF_FLOW )
700 12 PumpStats[k].startUps++;
701 18275 PumpStats[k].totalPeriods++;
702 18275 LinkStats[j].timeSurcharged += tStep;
703 18275 LinkStats[j].timeFullUpstream += tStep;
704 18275 LinkStats[j].timeFullDnstream += tStep;
705 }
706 }
707
2/2
✓ Branch 0 taken 16366843 times.
✓ Branch 1 taken 341934 times.
16708777 else if ( Link[j].type == CONDUIT )
708 {
709 // --- update time under normal flow & inlet control
710
2/2
✓ Branch 0 taken 2177749 times.
✓ Branch 1 taken 14189094 times.
16366843 if ( Link[j].normalFlow ) LinkStats[j].timeNormalFlow += tStep;
711
2/2
✓ Branch 0 taken 16941 times.
✓ Branch 1 taken 16349902 times.
16366843 if ( Link[j].inletControl ) LinkStats[j].timeInletControl += tStep;
712
713 // --- update flow classification distribution
714 16366843 k = Link[j].flowClass;
715
2/4
✓ Branch 0 taken 16366843 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16366843 times.
✗ Branch 3 not taken.
16366843 if ( k >= 0 && k < MAX_FLOW_CLASSES )
716 {
717 16366843 LinkStats[j].timeInFlowClass[k] += tStep;
718 }
719
720 // --- update time conduit is full
721 16366843 k = Link[j].subIndex;
722
2/2
✓ Branch 0 taken 193863 times.
✓ Branch 1 taken 16172980 times.
16366843 if ( q >= Link[j].qFull * (double)Conduit[k].barrels )
723 193863 LinkStats[j].timeFullFlow += tStep;
724
2/2
✓ Branch 0 taken 84705 times.
✓ Branch 1 taken 16282138 times.
16366843 if ( Conduit[k].capacityLimited )
725 84705 LinkStats[j].timeCapacityLimited += tStep;
726
727
4/4
✓ Branch 0 taken 197988 times.
✓ Branch 1 taken 141586 times.
✓ Branch 2 taken 273989 times.
✓ Branch 3 taken 15753280 times.
16366843 switch (Conduit[k].fullState)
728 {
729 197988 case ALL_FULL:
730 197988 LinkStats[j].timeSurcharged += tStep;
731 197988 LinkStats[j].timeFullUpstream += tStep;
732 197988 LinkStats[j].timeFullDnstream += tStep;
733 197988 break;
734 141586 case UP_FULL:
735 141586 LinkStats[j].timeFullUpstream += tStep;
736 141586 break;
737 273989 case DN_FULL:
738 273989 LinkStats[j].timeFullDnstream += tStep;
739 }
740
741 // --- update max. degree filled for streets
742
2/2
✓ Branch 0 taken 6328 times.
✓ Branch 1 taken 16360515 times.
16366843 if (Link[j].xsect.type == STREET_XSECT)
743 6328 LinkStats[j].maxStreetFilled =
744
2/2
✓ Branch 1 taken 1692 times.
✓ Branch 2 taken 4636 times.
6328 MAX(LinkStats[j].maxStreetFilled, street_getExtentFilled(j));
745 }
746
747 // --- update flow turn count
748 16737938 k = LinkStats[j].flowTurnSign;
749
2/2
✓ Branch 0 taken 2384742 times.
✓ Branch 1 taken 14353196 times.
16737938 LinkStats[j].flowTurnSign = SGN(dq);
750
4/4
✓ Branch 0 taken 1131097 times.
✓ Branch 1 taken 15606841 times.
✓ Branch 2 taken 18946 times.
✓ Branch 3 taken 1112151 times.
16737938 if ( fabs(dq) > 0.001 && k * LinkStats[j].flowTurnSign < 0 )
751 18946 LinkStats[j].flowTurns++;
752 16737938 }
753
754 //=============================================================================
755
756 51 void stats_findMaxStats()
757 //
758 // Input: none
759 // Output: none
760 // Purpose: finds nodes & links with highest mass balance errors
761 // & highest times Courant time-step critical.
762 //
763 {
764 int j;
765 double x, z;
766 double stepCount;
767
768 // --- initialize max. stats arrays
769
2/2
✓ Branch 0 taken 255 times.
✓ Branch 1 taken 51 times.
306 for (j=0; j<MAX_STATS; j++)
770 {
771 255 MaxMassBalErrs[j].objType = NODE;
772 255 MaxMassBalErrs[j].index = -1;
773 255 MaxMassBalErrs[j].value = -1.0;
774 255 MaxCourantCrit[j].index = -1;
775 255 MaxCourantCrit[j].value = -1.0;
776 255 MaxFlowTurns[j].index = -1;
777 255 MaxFlowTurns[j].value = -1.0;
778 255 MaxNonConverged[j].index = -1;
779 255 MaxNonConverged[j].value = 0.0;
780 }
781
782 // --- find links with most flow turns during reporting period
783
1/2
✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
51 if ( ReportStepCount > 2 )
784 {
785 51 stepCount = ReportStepCount;
786 51 z = 100.0 / (2./3. * (stepCount - 2.));
787
2/2
✓ Branch 0 taken 332 times.
✓ Branch 1 taken 51 times.
383 for (j=0; j<Nobjects[LINK]; j++)
788 {
789 332 x = LinkStats[j].flowTurns * z;
790 332 stats_updateMaxStats(MaxFlowTurns, LINK, j, x);
791 }
792 }
793
794 // --- find nodes with largest mass balance errors
795
2/2
✓ Branch 0 taken 413 times.
✓ Branch 1 taken 51 times.
464 for (j=0; j<Nobjects[NODE]; j++)
796 {
797 // --- skip terminal nodes and nodes with negligible inflow
798
2/2
✓ Branch 0 taken 218 times.
✓ Branch 1 taken 195 times.
413 if ( Node[j].degree <= 0 ) continue;
799
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 194 times.
195 if ( NodeInflow[j] <= 0.1 ) continue;
800
801 // --- evaluate mass balance error
802 // (Note: NodeInflow & NodeOutflow include any initial and final
803 // stored volumes, respectively).
804
1/2
✓ Branch 0 taken 194 times.
✗ Branch 1 not taken.
194 if ( NodeInflow[j] > 0.0 )
805 194 x = 1.0 - NodeOutflow[j] / NodeInflow[j];
806 else if ( NodeOutflow[j] > 0.0 ) x = -1.0;
807 else x = 0.0;
808 194 stats_updateMaxStats(MaxMassBalErrs, NODE, j, 100.0*x);
809 }
810
811 // --- following stats apply to all (startup + reporting) time periods
812 51 stepCount = TimeStepStats.timeStepCount;
813
814 // --- find nodes with highest nonconvergence frequency
815
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 13 times.
51 if ( RouteModel == DW )
816
2/2
✓ Branch 0 taken 328 times.
✓ Branch 1 taken 38 times.
366 for (j = 0; j < Nobjects[NODE]; j++)
817 328 stats_updateMaxStats(MaxNonConverged, NODE, j,
818 328 NodeStats[j].nonConvergedCount / stepCount);
819
820 // --- stop if not using a variable time step
821
4/4
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 31 times.
51 if ( RouteModel != DW || CourantFactor == 0.0 ) return;
822
823 // --- find nodes most frequently Courant critical
824
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31 times.
31 if ( stepCount == 0 ) return;
825
2/2
✓ Branch 0 taken 212 times.
✓ Branch 1 taken 31 times.
243 for (j=0; j<Nobjects[NODE]; j++)
826 {
827 212 x = NodeStats[j].timeCourantCritical / stepCount;
828 212 stats_updateMaxStats(MaxCourantCrit, NODE, j, 100.0*x);
829 }
830
831 // --- find links most frequently Courant critical
832
2/2
✓ Branch 0 taken 163 times.
✓ Branch 1 taken 31 times.
194 for (j=0; j<Nobjects[LINK]; j++)
833 {
834 163 x = LinkStats[j].timeCourantCritical / stepCount;
835 163 stats_updateMaxStats(MaxCourantCrit, LINK, j, 100.0*x);
836 }
837 }
838
839 //=============================================================================
840
841 1229 void stats_updateMaxStats(TMaxStats maxStats[], int i, int j, double x)
842 //
843 // Input: maxStats[] = array of critical statistics values
844 // i = object category (NODE or LINK)
845 // j = object index
846 // x = value of statistic for the object
847 // Output: none
848 // Purpose: updates the collection of most critical statistics
849 //
850 {
851 int k;
852 TMaxStats maxStats1, maxStats2;
853 1229 maxStats1.objType = i;
854 1229 maxStats1.index = j;
855 1229 maxStats1.value = x;
856
2/2
✓ Branch 0 taken 6145 times.
✓ Branch 1 taken 1229 times.
7374 for (k=0; k<MAX_STATS; k++)
857 {
858
2/2
✓ Branch 0 taken 348 times.
✓ Branch 1 taken 5797 times.
6145 if ( fabs(maxStats1.value) > fabs(maxStats[k].value) )
859 {
860 348 maxStats2 = maxStats[k];
861 348 maxStats[k] = maxStats1;
862 348 maxStats1 = maxStats2;
863 }
864 }
865 1229 }
866