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: 89.1% 221 / 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 58 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 58 NodeStats = NULL;
116 58 LinkStats = NULL;
117 58 StorageStats = NULL;
118 58 OutfallStats = NULL;
119 58 PumpStats = NULL;
120
121 // --- allocate memory for & initialize subcatchment statistics
122 58 SubcatchStats = NULL;
123
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 21 times.
58 if ( Nobjects[SUBCATCH] > 0 )
124 {
125 37 SubcatchStats = (TSubcatchStats *) calloc(Nobjects[SUBCATCH],
126 sizeof(TSubcatchStats));
127
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 if ( !SubcatchStats )
128 {
129 report_writeErrorMsg(ERR_MEMORY, "");
130 return ErrorCode;
131 }
132
2/2
✓ Branch 0 taken 2393 times.
✓ Branch 1 taken 37 times.
2430 for (j=0; j<Nobjects[SUBCATCH]; j++)
133 {
134 2393 SubcatchStats[j].precip = 0.0;
135 2393 SubcatchStats[j].runon = 0.0;
136 2393 SubcatchStats[j].evap = 0.0;
137 2393 SubcatchStats[j].infil = 0.0;
138 2393 SubcatchStats[j].runoff = 0.0;
139 2393 SubcatchStats[j].maxFlow = 0.0;
140 2393 SubcatchStats[j].impervRunoff = 0.0;
141 2393 SubcatchStats[j].pervRunoff = 0.0;
142 }
143
144
2/2
✓ Branch 0 taken 2393 times.
✓ Branch 1 taken 37 times.
2430 for (j=0; j<Nobjects[SUBCATCH]; j++)
145 {
146
2/2
✓ Branch 0 taken 152 times.
✓ Branch 1 taken 2241 times.
2393 if ( Subcatch[j].groundwater == NULL ) continue;
147 2241 Subcatch[j].groundwater->stats.avgUpperMoist = 0.0;
148 2241 Subcatch[j].groundwater->stats.avgWaterTable = 0.0;
149 2241 Subcatch[j].groundwater->stats.infil = 0.0;
150 2241 Subcatch[j].groundwater->stats.latFlow = 0.0;
151 2241 Subcatch[j].groundwater->stats.deepFlow = 0.0;
152 2241 Subcatch[j].groundwater->stats.evap = 0.0;
153 2241 Subcatch[j].groundwater->stats.maxFlow = 0.0;
154 2241 Subcatch[j].groundwater->stats.finalUpperMoist = 0.0;
155 2241 Subcatch[j].groundwater->stats.finalWaterTable = 0.0;
156 }
157 }
158
159 // --- allocate memory for node & link stats
160
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 10 times.
58 if ( Nobjects[LINK] > 0 )
161 {
162 48 NodeStats = (TNodeStats *) calloc(Nobjects[NODE], sizeof(TNodeStats));
163 48 LinkStats = (TLinkStats *) calloc(Nobjects[LINK], sizeof(TLinkStats));
164
2/4
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 48 times.
48 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 48 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 10173 times.
✓ Branch 3 taken 48 times.
10231 if ( NodeStats ) for ( j = 0; j < Nobjects[NODE]; j++ )
173 {
174 10173 NodeStats[j].avgDepth = 0.0;
175 10173 NodeStats[j].maxDepth = 0.0;
176 10173 NodeStats[j].maxDepthDate = StartDateTime;
177 10173 NodeStats[j].maxRptDepth = 0.0;
178 10173 NodeStats[j].volFlooded = 0.0;
179 10173 NodeStats[j].timeFlooded = 0.0;
180 10173 NodeStats[j].timeSurcharged = 0.0;
181 10173 NodeStats[j].timeCourantCritical = 0.0;
182 10173 NodeStats[j].totLatFlow = 0.0;
183 10173 NodeStats[j].maxLatFlow = 0.0;
184 10173 NodeStats[j].maxInflow = 0.0;
185 10173 NodeStats[j].maxOverflow = 0.0;
186 10173 NodeStats[j].maxPondedVol = 0.0;
187 10173 NodeStats[j].nonConvergedCount = 0;
188 10173 NodeStats[j].maxInflowDate = StartDateTime;
189 10173 NodeStats[j].maxOverflowDate = StartDateTime;
190 }
191
192 // --- initialize link stats
193
4/4
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 10508 times.
✓ Branch 3 taken 48 times.
10566 if ( LinkStats ) for ( j = 0; j < Nobjects[LINK]; j++ )
194 {
195 10508 LinkStats[j].maxFlow = 0.0;
196 10508 LinkStats[j].maxVeloc = 0.0;
197 10508 LinkStats[j].maxDepth = 0.0;
198 10508 LinkStats[j].maxStreetFilled = 0.0;
199 10508 LinkStats[j].timeSurcharged = 0.0;
200 10508 LinkStats[j].timeFullUpstream = 0.0;
201 10508 LinkStats[j].timeFullDnstream = 0.0;
202 10508 LinkStats[j].timeFullFlow = 0.0;
203 10508 LinkStats[j].timeCapacityLimited = 0.0;
204 10508 LinkStats[j].timeCourantCritical = 0.0;
205
2/2
✓ Branch 0 taken 73556 times.
✓ Branch 1 taken 10508 times.
84064 for (k=0; k<MAX_FLOW_CLASSES; k++)
206 73556 LinkStats[j].timeInFlowClass[k] = 0.0;
207 10508 LinkStats[j].flowTurns = 0;
208 10508 LinkStats[j].flowTurnSign = 0;
209 }
210
211 // --- allocate memory for & initialize storage unit statistics
212
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 39 times.
58 if ( Nnodes[STORAGE] > 0 )
213 {
214 19 StorageStats = (TStorageStats *) calloc(Nnodes[STORAGE],
215 sizeof(TStorageStats));
216
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
19 if ( !StorageStats )
217 {
218 report_writeErrorMsg(ERR_MEMORY, "");
219 return ErrorCode;
220 }
221
2/2
✓ Branch 0 taken 6555 times.
✓ Branch 1 taken 19 times.
6574 else for ( k = 0; k < Nobjects[NODE]; k++ )
222 {
223
2/2
✓ Branch 0 taken 6438 times.
✓ Branch 1 taken 117 times.
6555 if ( Node[k].type != STORAGE ) continue;
224 117 j = Node[k].subIndex;
225 117 StorageStats[j].initVol = Node[k].newVolume;
226 117 StorageStats[j].avgVol = 0.0;
227 117 StorageStats[j].maxVol = 0.0;
228 117 StorageStats[j].maxFlow = 0.0;
229 117 StorageStats[j].evapLosses = 0.0;
230 117 StorageStats[j].exfilLosses = 0.0;
231 117 StorageStats[j].maxVolDate = StartDateTime;
232 }
233 }
234
235 // --- allocate memory for & initialize outfall statistics
236
1/2
✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
58 if ( Nnodes[OUTFALL] > 0 )
237 {
238 58 OutfallStats = (TOutfallStats *) calloc(Nnodes[OUTFALL],
239 sizeof(TOutfallStats));
240
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 if ( !OutfallStats )
241 {
242 report_writeErrorMsg(ERR_MEMORY, "");
243 return ErrorCode;
244 }
245
2/2
✓ Branch 0 taken 348 times.
✓ Branch 1 taken 58 times.
406 else for ( j = 0; j < Nnodes[OUTFALL]; j++ )
246 {
247 348 OutfallStats[j].avgFlow = 0.0;
248 348 OutfallStats[j].maxFlow = 0.0;
249 348 OutfallStats[j].totalPeriods = 0;
250
2/2
✓ Branch 0 taken 260 times.
✓ Branch 1 taken 88 times.
348 if ( Nobjects[POLLUT] > 0 )
251 {
252 260 OutfallStats[j].totalLoad =
253 260 (double *) calloc(Nobjects[POLLUT], sizeof(double));
254
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 260 times.
260 if ( !OutfallStats[j].totalLoad )
255 {
256 report_writeErrorMsg(ERR_MEMORY, "");
257 return ErrorCode;
258 }
259
2/2
✓ Branch 0 taken 1027 times.
✓ Branch 1 taken 260 times.
1287 for (k=0; k<Nobjects[POLLUT]; k++)
260 1027 OutfallStats[j].totalLoad[k] = 0.0;
261 }
262 88 else OutfallStats[j].totalLoad = NULL;
263 }
264 }
265
266 // --- allocate memory & initialize pumping statistics
267
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 46 times.
58 if ( Nlinks[PUMP] > 0 )
268 {
269 12 PumpStats = (TPumpStats *) calloc(Nlinks[PUMP], sizeof(TPumpStats));
270
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if ( !PumpStats )
271 {
272 report_writeErrorMsg(ERR_MEMORY, "");
273 return ErrorCode;
274 }
275
2/2
✓ Branch 0 taken 106 times.
✓ Branch 1 taken 12 times.
118 else for ( j = 0; j < Nlinks[PUMP]; j++ )
276 {
277 106 PumpStats[j].utilized = 0.0;
278 106 PumpStats[j].minFlow = 0.0;
279 106 PumpStats[j].avgFlow = 0.0;
280 106 PumpStats[j].maxFlow = 0.0;
281 106 PumpStats[j].volume = 0.0;
282 106 PumpStats[j].energy = 0.0;
283 106 PumpStats[j].startUps = 0;
284 106 PumpStats[j].offCurveLow = 0.0;
285 106 PumpStats[j].offCurveHigh = 0.0;
286 }
287 }
288
289 // --- initialize system stats
290 58 MaxRunoffFlow = 0.0;
291 58 MaxOutfallFlow = 0.0;
292 58 TimeStepStats.maxTimeStep = 0.0;
293 58 TimeStepStats.minTimeStep = RouteStep;
294 58 TimeStepStats.routingTime = 0.0;
295 58 TimeStepStats.trialsCount = 0.0;
296 58 TimeStepStats.steadyStateTime = 0.0;
297 58 TimeStepStats.timeStepCount = 0;
298
299 // --- divide range between min and max routing time steps into
300 // equal intervals using a logarithmic scale
301 58 logMaxTimeStep = log10(RouteStep);
302 58 logMinTimeStep = log10(MinRouteStep);
303 58 timeStepDelta = (logMaxTimeStep - logMinTimeStep) / (double)(TIMELEVELS-1);
304 58 TimeStepStats.timeStepIntervals[0] = RouteStep;
305
2/2
✓ Branch 0 taken 290 times.
✓ Branch 1 taken 58 times.
348 for (j = 1; j < TIMELEVELS; j++)
306 {
307 290 TimeStepStats.timeStepIntervals[j] =
308 290 pow(10., logMaxTimeStep - j * timeStepDelta);
309 290 TimeStepStats.timeStepCounts[j] = 0;
310 }
311 58 TimeStepStats.timeStepIntervals[TIMELEVELS - 1] = MinRouteStep;
312 58 RoutingTimeSpan = 0.0;
313 58 return 0;
314 }
315
316 //=============================================================================
317
318 58 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 37 times.
✓ Branch 1 taken 21 times.
58 FREE(SubcatchStats);
328
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 10 times.
58 FREE(NodeStats);
329
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 10 times.
58 FREE(LinkStats);
330
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 39 times.
58 FREE(StorageStats);
331
1/2
✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
58 if ( OutfallStats )
332 {
333
2/2
✓ Branch 0 taken 348 times.
✓ Branch 1 taken 58 times.
406 for ( j=0; j<Nnodes[OUTFALL]; j++ )
334
2/2
✓ Branch 0 taken 260 times.
✓ Branch 1 taken 88 times.
348 FREE(OutfallStats[j].totalLoad);
335
1/2
✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
58 FREE(OutfallStats);
336 }
337
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 46 times.
58 FREE(PumpStats);
338 58 }
339
340 //=============================================================================
341
342 58 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 48 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 48 times.
✗ Branch 3 not taken.
58 if ( Nobjects[LINK] > 0 && RouteModel != NO_ROUTING )
351 {
352 48 stats_findMaxStats();
353
2/4
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
✗ Branch 3 not taken.
48 if (!RptFlags.disabled && RptFlags.flowStats)
354 {
355 48 report_writeMaxStats(MaxMassBalErrs, MaxCourantCrit, MAX_STATS);
356 48 report_writeMaxFlowTurns(MaxFlowTurns, MAX_STATS);
357 48 report_writeNonconvergedStats(MaxNonConverged, MAX_STATS);
358 48 report_writeTimeStepStats(&TimeStepStats);
359 }
360 }
361
362 // --- report summary statistics
363
1/2
✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
58 if (!RptFlags.disabled)
364 58 statsrpt_writeReport();
365 58 }
366
367 //=============================================================================
368
369 3229694 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 3229694 SubcatchStats[j].precip += rainVol;
388 3229694 SubcatchStats[j].runon += runonVol;
389 3229694 SubcatchStats[j].evap += evapVol;
390 3229694 SubcatchStats[j].infil += infilVol;
391 3229694 SubcatchStats[j].runoff += runoffVol;
392
2/2
✓ Branch 0 taken 3179641 times.
✓ Branch 1 taken 50053 times.
3229694 SubcatchStats[j].maxFlow = MAX(SubcatchStats[j].maxFlow, runoff);
393 3229694 SubcatchStats[j].impervRunoff += impervVol;
394 3229694 SubcatchStats[j].pervRunoff += pervVol;
395 3229694 }
396
397 //=============================================================================
398
399 3033546 void stats_updateGwaterStats(int j, double infil, double evap, double latFlow,
400 double deepFlow, double theta, double waterTable,
401 double tStep)
402 {
403 3033546 Subcatch[j].groundwater->stats.infil += infil * tStep;
404 3033546 Subcatch[j].groundwater->stats.evap += evap * tStep;
405 3033546 Subcatch[j].groundwater->stats.latFlow += latFlow * tStep;
406 3033546 Subcatch[j].groundwater->stats.deepFlow += deepFlow * tStep;
407 3033546 Subcatch[j].groundwater->stats.avgUpperMoist += theta * tStep;
408 3033546 Subcatch[j].groundwater->stats.avgWaterTable += waterTable * tStep;
409 3033546 Subcatch[j].groundwater->stats.finalUpperMoist = theta;
410 3033546 Subcatch[j].groundwater->stats.finalWaterTable = waterTable;
411
2/2
✓ Branch 0 taken 114227 times.
✓ Branch 1 taken 2919319 times.
3033546 if ( fabs(latFlow) > fabs(Subcatch[j].groundwater->stats.maxFlow) )
412 {
413 114227 Subcatch[j].groundwater->stats.maxFlow = latFlow;
414 }
415 3033546 }
416
417 //=============================================================================
418
419 33090 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 33090 double sysRunoff = 0.0;
428
429
2/2
✓ Branch 0 taken 3229694 times.
✓ Branch 1 taken 33090 times.
3262784 for (j=0; j<Nobjects[SUBCATCH]; j++) sysRunoff += Subcatch[j].newRunoff;
430
2/2
✓ Branch 0 taken 31744 times.
✓ Branch 1 taken 1346 times.
33090 MaxRunoffFlow = MAX(MaxRunoffFlow, sysRunoff);
431 33090 }
432
433 //=============================================================================
434
435 1930386 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 1927674 times.
✓ Branch 1 taken 2712 times.
1930386 if ( NodeStats != NULL )
444
2/2
✓ Branch 0 taken 1818867 times.
✓ Branch 1 taken 108807 times.
1927674 NodeStats[j].maxRptDepth = MAX(NodeStats[j].maxRptDepth, depth);
445 1930386 }
446
447 //=============================================================================
448
449 988013 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
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 988013 times.
988013 if ( aDate < ReportStart ) return;
461 988013 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 37851987 times.
✓ Branch 1 taken 988013 times.
38840000 for ( j=0; j<Nobjects[NODE]; j++ )
468 37851987 stats_updateNodeStats(j, tStep, aDate);
469 // #pragma omp for
470
2/2
✓ Branch 0 taken 37208897 times.
✓ Branch 1 taken 988013 times.
38196910 for ( j=0; j<Nobjects[LINK]; j++ )
471 37208897 stats_updateLinkStats(j, tStep, aDate);
472 }
473
474 // --- update count of time steps taken after reporting begins
475 988013 ReportStepCount++;
476 988013 RoutingTimeSpan += tStep;
477
478 // --- update max. system outfall flow
479
2/2
✓ Branch 0 taken 921386 times.
✓ Branch 1 taken 66627 times.
988013 MaxOutfallFlow = MAX(MaxOutfallFlow, SysOutfallFlow);
480 }
481
482 //=============================================================================
483
484 988013 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 988013 TimeStepStats.steadyStateTime += steadyState * tStep;
497
1/2
✓ Branch 0 taken 988013 times.
✗ Branch 1 not taken.
988013 if (steadyState == FALSE)
498 {
499 // --- skip initial time step for min. value)
500
2/2
✓ Branch 0 taken 987974 times.
✓ Branch 1 taken 39 times.
988013 if (OldRoutingTime > 0)
501 {
502
2/2
✓ Branch 0 taken 987739 times.
✓ Branch 1 taken 235 times.
987974 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 991301 times.
✗ Branch 1 not taken.
991301 for (j = 1; j < TIMELEVELS; j++)
507
2/2
✓ Branch 0 taken 987974 times.
✓ Branch 1 taken 3327 times.
991301 if (tStep >= TimeStepStats.timeStepIntervals[j])
508 {
509 987974 TimeStepStats.timeStepCounts[j]++;
510 987974 break;
511 }
512 }
513
2/2
✓ Branch 0 taken 987948 times.
✓ Branch 1 taken 65 times.
988013 TimeStepStats.maxTimeStep = MAX(TimeStepStats.maxTimeStep, tStep);
514 988013 TimeStepStats.routingTime += tStep;
515 988013 TimeStepStats.timeStepCount++;
516 988013 TimeStepStats.trialsCount += trialsCount;
517 }
518 988013 }
519
520 //=============================================================================
521
522 189152 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 189152 times.
189152 if ( node >= 0 ) NodeStats[node].timeCourantCritical += 1.0;
531
2/2
✓ Branch 0 taken 20361 times.
✓ Branch 1 taken 168791 times.
189152 else if ( link >= 0 ) LinkStats[link].timeCourantCritical += 1.0;
532 189152 }
533
534 //=============================================================================
535
536 1824857 void stats_updateConvergenceStats(int node, int converged)
537 {
538
2/2
✓ Branch 0 taken 127716 times.
✓ Branch 1 taken 1697141 times.
1824857 if (converged == FALSE) NodeStats[node].nonConvergedCount++;
539 1824857 }
540
541 //=============================================================================
542
543 37851987 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 37851987 double newVolume = Node[j].newVolume;
554 37851987 double newDepth = Node[j].newDepth;
555
4/4
✓ Branch 0 taken 1078120 times.
✓ Branch 1 taken 36773867 times.
✓ Branch 2 taken 749574 times.
✓ Branch 3 taken 328546 times.
37851987 int canPond = (AllowPonding && Node[j].pondedArea > 0.0);
556
557 // --- update depth statistics
558 37851987 NodeStats[j].avgDepth += newDepth;
559
2/2
✓ Branch 0 taken 6591284 times.
✓ Branch 1 taken 31260703 times.
37851987 if ( newDepth > NodeStats[j].maxDepth )
560 {
561 6591284 NodeStats[j].maxDepth = newDepth;
562 6591284 NodeStats[j].maxDepthDate = aDate;
563 }
564
565 // --- update flooding, ponding, and surcharge statistics
566
2/2
✓ Branch 0 taken 36585373 times.
✓ Branch 1 taken 1266614 times.
37851987 if ( Node[j].type != OUTFALL )
567 {
568
4/4
✓ Branch 0 taken 36497100 times.
✓ Branch 1 taken 88273 times.
✓ Branch 2 taken 37764 times.
✓ Branch 3 taken 36459336 times.
36585373 if ( newVolume > Node[j].fullVolume || Node[j].overflow > 0.0 )
569 {
570 126037 NodeStats[j].timeFlooded += tStep;
571 126037 NodeStats[j].volFlooded += Node[j].overflow * tStep;
572
2/2
✓ Branch 0 taken 88273 times.
✓ Branch 1 taken 37764 times.
214310 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 24591034 times.
✓ Branch 1 taken 11994339 times.
36585373 if (RouteModel == DW)
580 {
581
3/4
✓ Branch 0 taken 129090 times.
✓ Branch 1 taken 24461944 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 129090 times.
24591034 if ((Node[j].type != STORAGE || Node[j].surDepth > 0.0) &&
582
2/2
✓ Branch 0 taken 595484 times.
✓ Branch 1 taken 23866460 times.
24461944 newDepth + Node[j].invertElev + FUDGE >= Node[j].crownElev)
583 {
584 595484 NodeStats[j].timeSurcharged += tStep;
585 }
586 }
587 }
588
589 // --- update storage statistics
590
2/2
✓ Branch 0 taken 143130 times.
✓ Branch 1 taken 37708857 times.
37851987 if ( Node[j].type == STORAGE )
591 {
592 143130 k = Node[j].subIndex;
593 143130 StorageStats[k].avgVol += newVolume;
594 143130 StorageStats[k].evapLosses +=
595 143130 Storage[Node[j].subIndex].evapLoss;
596 143130 StorageStats[k].exfilLosses +=
597 143130 Storage[Node[j].subIndex].exfilLoss;
598
599
1/2
✓ Branch 0 taken 143130 times.
✗ Branch 1 not taken.
143130 newVolume = MIN(newVolume, Node[j].fullVolume);
600
2/2
✓ Branch 0 taken 35858 times.
✓ Branch 1 taken 107272 times.
143130 if ( newVolume > StorageStats[k].maxVol )
601 {
602 35858 StorageStats[k].maxVol = newVolume;
603 35858 StorageStats[k].maxVolDate = aDate;
604 }
605
2/2
✓ Branch 0 taken 114851 times.
✓ Branch 1 taken 28279 times.
143130 StorageStats[k].maxFlow = MAX(StorageStats[k].maxFlow, Node[j].outflow);
606 }
607
608 // --- update outfall statistics
609
2/2
✓ Branch 0 taken 1266614 times.
✓ Branch 1 taken 36585373 times.
37851987 if ( Node[j].type == OUTFALL )
610 {
611 1266614 k = Node[j].subIndex;
612
2/2
✓ Branch 0 taken 548361 times.
✓ Branch 1 taken 718253 times.
1266614 if ( Node[j].inflow >= MIN_RUNOFF_FLOW )
613 {
614 548361 OutfallStats[k].avgFlow += Node[j].inflow;
615
2/2
✓ Branch 0 taken 406281 times.
✓ Branch 1 taken 142080 times.
548361 OutfallStats[k].maxFlow = MAX(OutfallStats[k].maxFlow, Node[j].inflow);
616 548361 OutfallStats[k].totalPeriods++;
617 }
618
2/2
✓ Branch 0 taken 436529 times.
✓ Branch 1 taken 1266614 times.
1703143 for (p=0; p<Nobjects[POLLUT]; p++)
619 {
620 436529 OutfallStats[k].totalLoad[p] +=
621 436529 Node[j].inflow * Node[j].newQual[p] * tStep;
622 }
623 1266614 SysOutfallFlow += Node[j].inflow;
624 }
625
626 // --- update inflow statistics
627 37851987 NodeStats[j].totLatFlow +=
628 37851987 ((Node[j].oldLatFlow + Node[j].newLatFlow) * 0.5 * tStep );
629
2/2
✓ Branch 0 taken 286715 times.
✓ Branch 1 taken 37565272 times.
37851987 if ( fabs(Node[j].newLatFlow) > fabs(NodeStats[j].maxLatFlow) )
630 286715 NodeStats[j].maxLatFlow = Node[j].newLatFlow;
631
2/2
✓ Branch 0 taken 5834738 times.
✓ Branch 1 taken 32017249 times.
37851987 if ( Node[j].inflow > NodeStats[j].maxInflow )
632 {
633 5834738 NodeStats[j].maxInflow = Node[j].inflow;
634 5834738 NodeStats[j].maxInflowDate = aDate;
635 }
636
637 // --- update overflow statistics
638
2/2
✓ Branch 0 taken 11718 times.
✓ Branch 1 taken 37840269 times.
37851987 if ( Node[j].overflow > NodeStats[j].maxOverflow )
639 {
640 11718 NodeStats[j].maxOverflow = Node[j].overflow;
641 11718 NodeStats[j].maxOverflowDate = aDate;
642 }
643 37851987 }
644
645 //=============================================================================
646
647 37208897 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 37208897 dq = Link[j].newFlow - Link[j].oldFlow;
662 37208897 q = fabs(Link[j].newFlow);
663
2/2
✓ Branch 0 taken 6043513 times.
✓ Branch 1 taken 31165384 times.
37208897 if ( q > LinkStats[j].maxFlow )
664 {
665 6043513 LinkStats[j].maxFlow = q;
666 6043513 LinkStats[j].maxFlowDate = aDate;
667 }
668
669 // --- update max. velocity
670 37208897 v = link_getVelocity(j, q, Link[j].newDepth);
671
2/2
✓ Branch 0 taken 4558286 times.
✓ Branch 1 taken 32650611 times.
37208897 if ( v > LinkStats[j].maxVeloc )
672 {
673 4558286 LinkStats[j].maxVeloc = v;
674 }
675
676 // --- update max. depth
677
2/2
✓ Branch 0 taken 6937265 times.
✓ Branch 1 taken 30271632 times.
37208897 if ( Link[j].newDepth > LinkStats[j].maxDepth )
678 {
679 6937265 LinkStats[j].maxDepth = Link[j].newDepth;
680 }
681
682
2/2
✓ Branch 0 taken 84753 times.
✓ Branch 1 taken 37124144 times.
37208897 if ( Link[j].type == PUMP )
683 {
684
2/2
✓ Branch 0 taken 54040 times.
✓ Branch 1 taken 30713 times.
84753 if ( q >= Link[j].qFull )
685 54040 LinkStats[j].timeFullFlow += tStep;
686
2/2
✓ Branch 0 taken 70325 times.
✓ Branch 1 taken 14428 times.
84753 if ( q > MIN_RUNOFF_FLOW )
687 {
688 70325 k = Link[j].subIndex;
689
1/2
✓ Branch 0 taken 70325 times.
✗ Branch 1 not taken.
70325 PumpStats[k].minFlow = MIN(PumpStats[k].minFlow, q);
690 70325 PumpStats[k].maxFlow = LinkStats[j].maxFlow;
691 70325 PumpStats[k].avgFlow += q;
692 70325 PumpStats[k].volume += q*tStep;
693 70325 PumpStats[k].utilized += tStep;
694 70325 PumpStats[k].energy += link_getPower(j)*tStep/3600.0;
695
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70325 times.
70325 if ( Link[j].flowClass == DN_DRY )
696 PumpStats[k].offCurveLow += tStep;
697
2/2
✓ Branch 0 taken 11374 times.
✓ Branch 1 taken 58951 times.
70325 if ( Link[j].flowClass == UP_DRY )
698 11374 PumpStats[k].offCurveHigh += tStep;
699
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 70299 times.
70325 if ( Link[j].oldFlow < MIN_RUNOFF_FLOW )
700 26 PumpStats[k].startUps++;
701 70325 PumpStats[k].totalPeriods++;
702 70325 LinkStats[j].timeSurcharged += tStep;
703 70325 LinkStats[j].timeFullUpstream += tStep;
704 70325 LinkStats[j].timeFullDnstream += tStep;
705 }
706 }
707
2/2
✓ Branch 0 taken 36789022 times.
✓ Branch 1 taken 335122 times.
37124144 else if ( Link[j].type == CONDUIT )
708 {
709 // --- update time under normal flow & inlet control
710
2/2
✓ Branch 0 taken 11125323 times.
✓ Branch 1 taken 25663699 times.
36789022 if ( Link[j].normalFlow ) LinkStats[j].timeNormalFlow += tStep;
711
2/2
✓ Branch 0 taken 16941 times.
✓ Branch 1 taken 36772081 times.
36789022 if ( Link[j].inletControl ) LinkStats[j].timeInletControl += tStep;
712
713 // --- update flow classification distribution
714 36789022 k = Link[j].flowClass;
715
2/4
✓ Branch 0 taken 36789022 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36789022 times.
✗ Branch 3 not taken.
36789022 if ( k >= 0 && k < MAX_FLOW_CLASSES )
716 {
717 36789022 LinkStats[j].timeInFlowClass[k] += tStep;
718 }
719
720 // --- update time conduit is full
721 36789022 k = Link[j].subIndex;
722
2/2
✓ Branch 0 taken 233377 times.
✓ Branch 1 taken 36555645 times.
36789022 if ( q >= Link[j].qFull * (double)Conduit[k].barrels )
723 233377 LinkStats[j].timeFullFlow += tStep;
724
2/2
✓ Branch 0 taken 76504 times.
✓ Branch 1 taken 36712518 times.
36789022 if ( Conduit[k].capacityLimited )
725 76504 LinkStats[j].timeCapacityLimited += tStep;
726
727
4/4
✓ Branch 0 taken 345988 times.
✓ Branch 1 taken 119649 times.
✓ Branch 2 taken 864493 times.
✓ Branch 3 taken 35458892 times.
36789022 switch (Conduit[k].fullState)
728 {
729 345988 case ALL_FULL:
730 345988 LinkStats[j].timeSurcharged += tStep;
731 345988 LinkStats[j].timeFullUpstream += tStep;
732 345988 LinkStats[j].timeFullDnstream += tStep;
733 345988 break;
734 119649 case UP_FULL:
735 119649 LinkStats[j].timeFullUpstream += tStep;
736 119649 break;
737 864493 case DN_FULL:
738 864493 LinkStats[j].timeFullDnstream += tStep;
739 }
740
741 // --- update max. degree filled for streets
742
2/2
✓ Branch 0 taken 6328 times.
✓ Branch 1 taken 36782694 times.
36789022 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 37208897 k = LinkStats[j].flowTurnSign;
749
2/2
✓ Branch 0 taken 12628995 times.
✓ Branch 1 taken 24579902 times.
37208897 LinkStats[j].flowTurnSign = SGN(dq);
750
4/4
✓ Branch 0 taken 3241688 times.
✓ Branch 1 taken 33967209 times.
✓ Branch 2 taken 85125 times.
✓ Branch 3 taken 3156563 times.
37208897 if ( fabs(dq) > 0.001 && k * LinkStats[j].flowTurnSign < 0 )
751 85125 LinkStats[j].flowTurns++;
752 37208897 }
753
754 //=============================================================================
755
756 48 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 240 times.
✓ Branch 1 taken 48 times.
288 for (j=0; j<MAX_STATS; j++)
770 {
771 240 MaxMassBalErrs[j].objType = NODE;
772 240 MaxMassBalErrs[j].index = -1;
773 240 MaxMassBalErrs[j].value = -1.0;
774 240 MaxCourantCrit[j].index = -1;
775 240 MaxCourantCrit[j].value = -1.0;
776 240 MaxFlowTurns[j].index = -1;
777 240 MaxFlowTurns[j].value = -1.0;
778 240 MaxNonConverged[j].index = -1;
779 240 MaxNonConverged[j].value = 0.0;
780 }
781
782 // --- find links with most flow turns during reporting period
783
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 6 times.
48 if ( ReportStepCount > 2 )
784 {
785 42 stepCount = ReportStepCount;
786 42 z = 100.0 / (2./3. * (stepCount - 2.));
787
2/2
✓ Branch 0 taken 4706 times.
✓ Branch 1 taken 42 times.
4748 for (j=0; j<Nobjects[LINK]; j++)
788 {
789 4706 x = LinkStats[j].flowTurns * z;
790 4706 stats_updateMaxStats(MaxFlowTurns, LINK, j, x);
791 }
792 }
793
794 // --- find nodes with largest mass balance errors
795
2/2
✓ Branch 0 taken 10173 times.
✓ Branch 1 taken 48 times.
10221 for (j=0; j<Nobjects[NODE]; j++)
796 {
797 // --- skip terminal nodes and nodes with negligible inflow
798
2/2
✓ Branch 0 taken 1734 times.
✓ Branch 1 taken 8439 times.
10173 if ( Node[j].degree <= 0 ) continue;
799
2/2
✓ Branch 0 taken 4624 times.
✓ Branch 1 taken 3815 times.
8439 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 3815 times.
✗ Branch 1 not taken.
3815 if ( NodeInflow[j] > 0.0 )
805 3815 x = 1.0 - NodeOutflow[j] / NodeInflow[j];
806 else if ( NodeOutflow[j] > 0.0 ) x = -1.0;
807 else x = 0.0;
808 3815 stats_updateMaxStats(MaxMassBalErrs, NODE, j, 100.0*x);
809 }
810
811 // --- following stats apply to all (startup + reporting) time periods
812 48 stepCount = TimeStepStats.timeStepCount;
813
814 // --- find nodes with highest nonconvergence frequency
815
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 13 times.
48 if ( RouteModel == DW )
816
2/2
✓ Branch 0 taken 10088 times.
✓ Branch 1 taken 35 times.
10123 for (j = 0; j < Nobjects[NODE]; j++)
817 10088 stats_updateMaxStats(MaxNonConverged, NODE, j,
818 10088 NodeStats[j].nonConvergedCount / stepCount);
819
820 // --- stop if not using a variable time step
821
4/4
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 30 times.
48 if ( RouteModel != DW || CourantFactor == 0.0 ) return;
822
823 // --- find nodes most frequently Courant critical
824
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 24 times.
30 if ( stepCount == 0 ) return;
825
2/2
✓ Branch 0 taken 4548 times.
✓ Branch 1 taken 24 times.
4572 for (j=0; j<Nobjects[NODE]; j++)
826 {
827 4548 x = NodeStats[j].timeCourantCritical / stepCount;
828 4548 stats_updateMaxStats(MaxCourantCrit, NODE, j, 100.0*x);
829 }
830
831 // --- find links most frequently Courant critical
832
2/2
✓ Branch 0 taken 4608 times.
✓ Branch 1 taken 24 times.
4632 for (j=0; j<Nobjects[LINK]; j++)
833 {
834 4608 x = LinkStats[j].timeCourantCritical / stepCount;
835 4608 stats_updateMaxStats(MaxCourantCrit, LINK, j, 100.0*x);
836 }
837 }
838
839 //=============================================================================
840
841 27765 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 27765 maxStats1.objType = i;
854 27765 maxStats1.index = j;
855 27765 maxStats1.value = x;
856
2/2
✓ Branch 0 taken 138825 times.
✓ Branch 1 taken 27765 times.
166590 for (k=0; k<MAX_STATS; k++)
857 {
858
2/2
✓ Branch 0 taken 836 times.
✓ Branch 1 taken 137989 times.
138825 if ( fabs(maxStats1.value) > fabs(maxStats[k].value) )
859 {
860 836 maxStats2 = maxStats[k];
861 836 maxStats[k] = maxStats1;
862 836 maxStats1 = maxStats2;
863 }
864 }
865 27765 }
866