GCC Code Coverage Report


Directory: src/solver/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 87.7% 300 / 0 / 342
Functions: 95.7% 22 / 0 / 23
Branches: 79.4% 208 / 0 / 262

routing.c
Line Branch Exec Source
1 //-----------------------------------------------------------------------------
2 // routing.c
3 //
4 // Project: EPA SWMM5
5 // Version: 5.2
6 // Date: 11/01/21 (Build 5.2.0)
7 // Author: L. Rossman
8 // M. Tryby (EPA)
9 //
10 // Conveyance system routing functions.
11 //
12 // Update History
13 // ==============
14 // Build 5.1.007:
15 // - Nodal evap/seepage losses computed using conditions at start of time step.
16 // - DWF pollutant concentrations ignored if DWF is negative.
17 // - Separate mass balance accounting made for storage evap. & seepage.
18 // - Nodal mass balance accounting for negative lateral inflows corrected.
19 // Build 5.1.008:
20 // - Initialization of flow and quality routing systems moved here from swmm5.c.
21 // - Lateral inflows now evaluated at start (not end) of time step.
22 // - Flows from LID drains included in lateral inflows.
23 // - Conduit evap/seepage losses multiplied by number of barrels before
24 // being added into mass balances.
25 // Build 5.1.010:
26 // - Time when a link's setting is changed is recorded.
27 // Build 5.1.011:
28 // - Support added for limiting flow routing to specific events.
29 // Build 5.1.012:
30 // - routing_execute() was re-written so that Routing Events and
31 // Skip Steady Flow options work together correctly.
32 // Build 5.1.013:
33 // - Support added for evaluating controls rules at RuleStep time interval.
34 // - Back flow through Outfall nodes now treated as External Inflows for
35 // mass balance purposes.
36 // - Global infiltration factor for storage seepage set in routing_execute.
37 // Build 5.2.0:
38 // - Support added for street flow capture and sewer backflow thru inlets.
39 // - Shell sort replaces insertion sort for sorting Event array.
40 //-----------------------------------------------------------------------------
41 #define _CRT_SECURE_NO_DEPRECATE
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <math.h>
47 #include "headers.h"
48 #include "lid.h"
49 //-----------------------------------------------------------------------------
50 // Shared variables
51 //-----------------------------------------------------------------------------
52 static int* SortedLinks;
53 static int NextEvent;
54 static int BetweenEvents;
55 static double NewRuleTime;
56
57 //-----------------------------------------------------------------------------
58 // External functions (declared in funcs.h)
59 //-----------------------------------------------------------------------------
60 // routing_open (called by swmm_start in swmm5.c)
61 // routing_getRoutingStep (called by swmm_step in swmm5.c)
62 // routing_execute (called by swmm_step in swmm5.c)
63 // routing_close (called by swmm_end in swmm5.c)
64
65 //-----------------------------------------------------------------------------
66 // Function declarations
67 //-----------------------------------------------------------------------------
68 static int evaluateControlRules(DateTime currentDate, double routingStep);
69 static void sortEvents(void);
70 static int isBetweenEvents(DateTime currentDate);
71 static int isInSteadyState(int actionCount, double stepFlowError);
72 static int inflowHasChanged(void);
73
74 static void initSystemInflows();
75 static void addSystemInflows(DateTime currentDate, double routingStep);
76 static void addExternalInflows(DateTime currentDate);
77 static void addDryWeatherInflows(DateTime currentDate);
78 static void addWetWeatherInflows(double routingTime);
79 static void addGroundwaterInflows(double routingTime);
80 static void addRdiiInflows(DateTime currentDate);
81 static void addIfaceInflows(DateTime currentDate);
82 static void addLidDrainInflows(double routingTime);
83
84 static int routeFlow(int routingModel, double routingStep);
85 static void removeSystemOutflows(double routingStep);
86 static void removeStorageLosses(double tStep);
87 static void removeConduitLosses(void);
88 static void removeOutflows(double tStep);
89
90
91 //=============================================================================
92
93 61 int routing_open()
94 //
95 // Input: none
96 // Output: returns an error code
97 // Purpose: initializes the routing analyzer.
98 //
99 {
100 // --- open treatment system
101
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 61 times.
61 if ( !treatmnt_open() ) return ErrorCode;
102
103 // --- topologically sort the links
104 61 SortedLinks = NULL;
105
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 10 times.
61 if ( Nobjects[LINK] > 0 )
106 {
107 51 SortedLinks = (int *) calloc(Nobjects[LINK], sizeof(int));
108
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 51 times.
51 if ( !SortedLinks )
109 {
110 report_writeErrorMsg(ERR_MEMORY, "");
111 return ErrorCode;
112 }
113 51 toposort_sortLinks(SortedLinks);
114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 51 times.
51 if ( ErrorCode ) return ErrorCode;
115 }
116
117 // --- open any routing interface files
118 61 iface_openRoutingFiles();
119
120 // --- initialize flow and quality routing systems
121 61 flowrout_init(RouteModel);
122
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 1 time.
61 if ( Fhotstart1.mode == NO_FILE ) qualrout_init();
123
124 // --- initialize routing events
125
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 59 times.
61 if ( NumEvents > 0 ) sortEvents();
126 61 NextEvent = 0;
127 61 BetweenEvents = (NumEvents > 0);
128 61 NewRuleTime = 0.0;
129 61 return ErrorCode;
130 }
131
132 //=============================================================================
133
134 61 void routing_close(int routingModel)
135 //
136 // Input: routingModel = routing method code
137 // Output: none
138 // Purpose: closes down the routing analyzer.
139 //
140 {
141 // --- close any routing interface files
142 61 iface_closeRoutingFiles();
143
144 // --- free allocated memory
145 61 flowrout_close(routingModel);
146 61 treatmnt_close();
147
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 10 times.
61 FREE(SortedLinks);
148 61 }
149
150 //=============================================================================
151
152 1110502 double routing_getRoutingStep(int routingModel, double fixedStep)
153 //
154 // Input: routingModel = routing method code
155 // fixedStep = user-supplied time step (sec)
156 // Output: returns a routing time step (sec)
157 // Purpose: determines time step used for flow routing at current time period.
158 //
159 {
160 double date1, date2, nextTime;
161 1110502 double routingStep = 0.0, nextRuleTime, nextRoutingTime;
162
163
2/2
✓ Branch 0 taken 42480 times.
✓ Branch 1 taken 1068022 times.
1110502 if ( Nobjects[LINK] == 0 ) return fixedStep;
164
165 // --- find largest step possible if between routing events
166
4/4
✓ Branch 0 taken 189288 times.
✓ Branch 1 taken 878734 times.
✓ Branch 2 taken 16488 times.
✓ Branch 3 taken 172800 times.
1068022 if ( NumEvents > 0 && BetweenEvents )
167 {
168
2/2
✓ Branch 0 taken 15744 times.
✓ Branch 1 taken 744 times.
16488 nextTime = MIN(NewRunoffTime, ReportTime);
169 16488 date1 = getDateTime(NewRoutingTime);
170 16488 date2 = getDateTime(nextTime);
171
4/4
✓ Branch 0 taken 8880 times.
✓ Branch 1 taken 7608 times.
✓ Branch 2 taken 8346 times.
✓ Branch 3 taken 534 times.
16488 if ( date2 > date1 && date2 < Event[NextEvent].start )
172 {
173 8346 routingStep = (nextTime - NewRoutingTime) / 1000.0;
174 }
175 else
176 {
177 8142 date1 = getDateTime(NewRoutingTime + 1000.0 * fixedStep);
178
2/2
✓ Branch 0 taken 8130 times.
✓ Branch 1 taken 12 times.
8142 if ( date1 < Event[NextEvent].start ) return fixedStep;
179 }
180 }
181
182 // --- otherwise use a regular flow-routing based time step
183
2/2
✓ Branch 0 taken 1051546 times.
✓ Branch 1 taken 8346 times.
1059892 if (routingStep == 0.0)
184 {
185 1051546 routingStep = flowrout_getRoutingStep(routingModel, fixedStep);
186 }
187
188 // --- determine if control rule time interval reached
189
2/2
✓ Branch 0 taken 1921 times.
✓ Branch 1 taken 1057971 times.
1059892 if (RuleStep > 0)
190 {
191 1921 nextRuleTime = NewRuleTime + 1000. * RuleStep;
192 1921 nextRoutingTime = NewRoutingTime + 1000. * routingStep;
193
2/2
✓ Branch 0 taken 480 times.
✓ Branch 1 taken 1441 times.
1921 if (nextRoutingTime >= nextRuleTime)
194 {
195 480 routingStep = (nextRuleTime - NewRoutingTime) / 1000.0;
196 }
197 }
198 1059892 return routingStep;
199 }
200
201 //=============================================================================
202
203 1110502 void routing_execute(int routingModel, double routingStep)
204 //
205 // Input: routingModel = routing method code
206 // routingStep = routing time step (sec)
207 // Output: none
208 // Purpose: executes the routing process at the current time period.
209 //
210 {
211 1110502 int trialsCount = 1; // trials required to solve flow routing
212 1110502 int actionCount = 0; // number of control actions taken
213 1110502 int inSteadyState = TRUE; // system is in steady state
214 DateTime currentDate; // date at start of routing step
215 double stepFlowError; // 1 - (system outflow) / (system inflow)
216
217
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1110502 times.
1110502 if ( ErrorCode ) return;
218
219 // --- update mass balance totals over previous half time step
220 1110502 massbal_updateRoutingTotals(routingStep/2.);
221
222 // --- take any applicable control rule actions
223 1110502 currentDate = getDateTime(NewRoutingTime);
224 1110502 actionCount = evaluateControlRules(currentDate, routingStep);
225
226 // --- initialize mass balance and system inflow variables
227 1110502 stepFlowError = massbal_getStepFlowError();
228 1110502 massbal_initTimeStepTotals();
229 1110502 initSystemInflows();
230
231 // --- check that current date falls within a user-speficied event period
232 1110502 BetweenEvents = isBetweenEvents(currentDate);
233
2/2
✓ Branch 0 taken 1094014 times.
✓ Branch 1 taken 16488 times.
1110502 if (BetweenEvents == FALSE)
234 {
235 // --- apply current inflows to conveyance system
236 1094014 addSystemInflows(currentDate, routingStep);
237 1094014 inlet_findCapturedFlows(routingStep);
238
239 // --- route flows if system is not in steady state
240 1094014 inSteadyState = isInSteadyState(actionCount, stepFlowError);
241
1/2
✓ Branch 0 taken 1094014 times.
✗ Branch 1 not taken.
1094014 if (inSteadyState == FALSE)
242 1094014 trialsCount = routeFlow(routingModel, routingStep);
243
244 // --- route water quality constituents
245
4/4
✓ Branch 0 taken 203668 times.
✓ Branch 1 taken 890346 times.
✓ Branch 2 taken 201513 times.
✓ Branch 3 taken 2155 times.
1094014 if (Nobjects[POLLUT] > 0 && !IgnoreQuality)
246 {
247 201513 inlet_adjustQualInflows();
248 201513 qualrout_execute(routingStep);
249 }
250
251 // --- update mass balance totals for flows leaving the system
252 1094014 removeSystemOutflows(routingStep);
253 1094014 inlet_adjustQualOutflows();
254
255 // --- update time step & flow routing statistics
256
2/2
✓ Branch 0 taken 1051534 times.
✓ Branch 1 taken 42480 times.
1094014 if (Nobjects[LINK] > 0)
257 {
258 1051534 stats_updateFlowStats(routingStep, getDateTime(NewRoutingTime));
259 1051534 stats_updateTimeStepStats(routingStep, trialsCount, inSteadyState);
260 }
261 }
262
263 // --- update mass balance totals over the current half time step
264 1110502 massbal_updateRoutingTotals(routingStep / 2.);
265 }
266
267 //=============================================================================
268
269 1110502 int evaluateControlRules(DateTime currentDate, double routingStep)
270 {
271 int j;
272 1110502 int actionCount = 0;
273
274 // --- find new link target settings that are not related to
275 // --- control rules (e.g., pump on/off depth limits)
276
2/2
✓ Branch 1 taken 16958726 times.
✓ Branch 2 taken 1110502 times.
18069228 for (j=0; j<Nobjects[LINK]; j++) link_setTargetSetting(j);
277
278 // --- evaluate control rules if next evaluation time reached
279
4/4
✓ Branch 0 taken 1921 times.
✓ Branch 1 taken 1108581 times.
✓ Branch 2 taken 480 times.
✓ Branch 3 taken 1441 times.
1110502 if (RuleStep == 0 || fabs(NewRoutingTime - NewRuleTime) < 1.0)
280 {
281 1109061 controls_evaluate(currentDate, currentDate - StartDateTime,
282 routingStep / SECperDAY);
283 }
284
285 // --- change each link's actual setting if it differs from its target
286
2/2
✓ Branch 0 taken 16958726 times.
✓ Branch 1 taken 1110502 times.
18069228 for (j=0; j<Nobjects[LINK]; j++)
287 {
288
2/2
✓ Branch 0 taken 1014 times.
✓ Branch 1 taken 16957712 times.
16958726 if ( Link[j].targetSetting != Link[j].setting )
289 {
290 // --- update time when link was switched between open & closed
291
2/2
✓ Branch 0 taken 473 times.
✓ Branch 1 taken 541 times.
1014 if ( Link[j].targetSetting * Link[j].setting == 0.0 )
292 473 Link[j].timeLastSet = currentDate;
293
294 // --- implement the change in the link's setting
295 1014 link_setSetting(j, routingStep);
296 1014 actionCount++;
297 }
298 }
299
300 // --- update value of elapsed routing time (in milliseconds)
301 1110502 OldRoutingTime = NewRoutingTime;
302 1110502 NewRoutingTime = NewRoutingTime + 1000.0 * routingStep;
303
304 // --- see if control rule evaluation time should be advanced
305
2/2
✓ Branch 0 taken 478 times.
✓ Branch 1 taken 1110024 times.
1110502 if (fabs(NewRoutingTime - (NewRuleTime + 1000.0*RuleStep)) < 1)
306 478 NewRuleTime += 1000.0 * RuleStep;
307 1110502 return actionCount;
308 }
309
310 //=============================================================================
311
312 1110502 void initSystemInflows()
313 {
314 int j;
315
316 // --- replace old water quality state with new state
317
2/2
✓ Branch 0 taken 220156 times.
✓ Branch 1 taken 890346 times.
1110502 if ( Nobjects[POLLUT] > 0 )
318 {
319
2/2
✓ Branch 1 taken 2757661 times.
✓ Branch 2 taken 220156 times.
2977817 for (j=0; j<Nobjects[NODE]; j++) node_setOldQualState(j);
320
2/2
✓ Branch 1 taken 2575662 times.
✓ Branch 2 taken 220156 times.
2795818 for (j=0; j<Nobjects[LINK]; j++) link_setOldQualState(j);
321 }
322
323 // --- set infiltration factor for storage unit seepage
324 // (-1 argument indicates global factor is used)
325 1110502 infil_setInfilFactor(-1);
326
327 // --- initialize lateral inflows at nodes
328
2/2
✓ Branch 0 taken 18038828 times.
✓ Branch 1 taken 1110502 times.
19149330 for (j = 0; j < Nobjects[NODE]; j++)
329 {
330 18038828 Node[j].oldLatFlow = Node[j].newLatFlow;
331 18038828 Node[j].newLatFlow = 0.0;
332 }
333 1110502 }
334
335 //=============================================================================
336
337 1110502 int isBetweenEvents(DateTime currentDate)
338 {
339 // --- if no events defined then result is always false
340
2/2
✓ Branch 0 taken 921214 times.
✓ Branch 1 taken 189288 times.
1110502 if ( NumEvents == 0 ) return FALSE;
341
342 // --- currrent event period has ended so result is true
343
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 189282 times.
189288 if ( currentDate > Event[NextEvent].end )
344 {
345 6 NextEvent++;
346 6 return TRUE;
347 }
348
349 // --- we've entered the next event period so result is false
350
2/2
✓ Branch 0 taken 172800 times.
✓ Branch 1 taken 16482 times.
189282 else if ( currentDate >= Event[NextEvent].start )
351 {
352 172800 return FALSE;
353 }
354 16482 return TRUE;
355 }
356
357 //=============================================================================
358
359 1094014 void addSystemInflows(DateTime currentDate, double routingStep)
360 {
361 int j;
362
363 // --- find evap. & seepage losses from storage nodes
364
2/2
✓ Branch 0 taken 17807996 times.
✓ Branch 1 taken 1094014 times.
18902010 for (j = 0; j < Nobjects[NODE]; j++)
365 17807996 Node[j].losses = node_getLosses(j, routingStep);
366
367 // --- add lateral inflows at nodes
368 1094014 addExternalInflows(currentDate);
369 1094014 addDryWeatherInflows(currentDate);
370 1094014 addWetWeatherInflows(OldRoutingTime);
371 1094014 addGroundwaterInflows(OldRoutingTime);
372 1094014 addLidDrainInflows(OldRoutingTime);
373 1094014 addRdiiInflows(currentDate);
374 1094014 addIfaceInflows(currentDate);
375
376 // --- initialize node inflow for quality routing
377
2/2
✓ Branch 0 taken 17807996 times.
✓ Branch 1 taken 1094014 times.
18902010 for (j = 0; j < Nobjects[NODE]; j++)
378
2/2
✓ Branch 0 taken 15589862 times.
✓ Branch 1 taken 2218134 times.
17807996 Node[j].qualInflow = MAX(0.0, Node[j].newLatFlow);
379 1094014 }
380
381 //=============================================================================
382
383 1094014 int isInSteadyState(int actionCount, double stepFlowError)
384 {
385 // --- check if can skip steady state periods based on flows
386
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1094014 times.
1094014 if ( SkipSteadyState )
387 {
388 if ( OldRoutingTime == 0.0
389 || actionCount > 0
390 || fabs(stepFlowError) > SysFlowTol
391 || inflowHasChanged() ) return FALSE;
392 else return TRUE;
393 }
394 1094014 return FALSE;
395 }
396
397 //=============================================================================
398
399 1094014 int routeFlow(int routingModel, double routingStep)
400 {
401 int j;
402 1094014 int stepCount = 1;
403
404 // --- replace old hydraulic state values with current ones
405
2/2
✓ Branch 1 taken 16744382 times.
✓ Branch 2 taken 1094014 times.
17838396 for (j = 0; j < Nobjects[LINK]; j++) link_setOldHydState(j);
406
2/2
✓ Branch 1 taken 17807996 times.
✓ Branch 2 taken 1094014 times.
18902010 for (j = 0; j < Nobjects[NODE]; j++) node_setOldHydState(j);
407
408 // --- initialize node inflows to lateral flows, outflows to evap +
409 // seepage losses, & overflows to excess stored volume
410
2/2
✓ Branch 0 taken 17807996 times.
✓ Branch 1 taken 1094014 times.
18902010 for (j = 0; j < Nobjects[NODE]; j++)
411 17807996 node_initFlows(j, routingStep);
412
413 // --- route flow through the drainage network
414
2/2
✓ Branch 0 taken 1051534 times.
✓ Branch 1 taken 42480 times.
1094014 if ( Nobjects[LINK] > 0 )
415 {
416 1051534 stepCount = flowrout_execute(SortedLinks, routingModel, routingStep);
417 }
418
419 // --- save overflows at inlet capture nodes as inlet backflow
420 1094014 return stepCount;
421 }
422
423 //=============================================================================
424
425 1094014 void removeSystemOutflows(double routingStep)
426 {
427 // --- remove evaporation, infiltration & outflows from system
428 1094014 removeStorageLosses(routingStep);
429 1094014 removeConduitLosses();
430 1094014 removeOutflows(routingStep);
431 1094014 }
432
433 //=============================================================================
434
435 1094014 void addExternalInflows(DateTime currentDate)
436 //
437 // Input: currentDate = current date/time
438 // Output: none
439 // Purpose: adds direct external inflows to nodes at current date.
440 //
441 {
442 int j, p;
443 double q, w;
444 TExtInflow* inflow;
445
446 // --- for each node with a defined external inflow
447
2/2
✓ Branch 0 taken 17807996 times.
✓ Branch 1 taken 1094014 times.
18902010 for (j = 0; j < Nobjects[NODE]; j++)
448 {
449 // --- get flow inflow
450 17807996 q = Node[j].apiExtInflow;
451 17807996 inflow = Node[j].extInflow;
452
2/2
✓ Branch 0 taken 1170085 times.
✓ Branch 1 taken 16655912 times.
17825997 while ( inflow )
453 {
454
2/2
✓ Branch 0 taken 1152084 times.
✓ Branch 1 taken 18001 times.
1170085 if ( inflow->type == FLOW_INFLOW )
455 {
456 1152084 q += inflow_getExtInflow(inflow, currentDate);
457 1152084 break;
458 }
459 18001 else inflow = inflow->next;
460 }
461
2/2
✓ Branch 0 taken 17396413 times.
✓ Branch 1 taken 411583 times.
17807996 if ( fabs(q) < FLOW_TOL ) q = 0.0;
462
463 // --- add flow inflow to node's lateral inflow
464 17807996 Node[j].newLatFlow += q;
465
1/2
✓ Branch 0 taken 17807996 times.
✗ Branch 1 not taken.
17807996 if (q >= 0.0)
466 17807996 massbal_addInflowFlow(EXTERNAL_INFLOW, q);
467 else
468 {
469 massbal_addOutflowFlow(-q, FALSE);
470 continue;
471 }
472
473 // --- add on any inflow (i.e., reverse flow) through an outfall
474
3/4
✓ Branch 0 taken 1365046 times.
✓ Branch 1 taken 16442950 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1365046 times.
17807996 if ( Node[j].type == OUTFALL && Node[j].oldNetInflow < 0.0 )
475 {
476 q = q - Node[j].oldNetInflow;
477 }
478
479 // --- get pollutant mass inflows
480 17807996 inflow = Node[j].extInflow;
481
2/2
✓ Branch 0 taken 1170085 times.
✓ Branch 1 taken 17807996 times.
18978081 while ( inflow )
482 {
483
2/2
✓ Branch 0 taken 18001 times.
✓ Branch 1 taken 1152084 times.
1170085 if ( inflow->type != FLOW_INFLOW )
484 {
485 18001 p = inflow->param;
486 18001 w = inflow_getExtInflow(inflow, currentDate);
487
1/2
✓ Branch 0 taken 18001 times.
✗ Branch 1 not taken.
18001 if ( inflow->type == CONCEN_INFLOW ) w *= q;
488 18001 Node[j].newQual[p] += w;
489 18001 massbal_addInflowQual(EXTERNAL_INFLOW, p, w);
490 }
491 1170085 inflow = inflow->next;
492 }
493 }
494 1094014 }
495
496 //=============================================================================
497
498 1094014 void addDryWeatherInflows(DateTime currentDate)
499 //
500 // Input: currentDate = current date/time
501 // Output: none
502 // Purpose: adds dry weather inflows to nodes at current date.
503 //
504 {
505 int j, p;
506 int month, day, hour;
507 double q, w;
508 TDwfInflow* inflow;
509
510 // --- get month (zero-based), day-of-week (zero-based),
511 // & hour-of-day for routing date/time
512 1094014 month = datetime_monthOfYear(currentDate) - 1;
513 1094014 day = datetime_dayOfWeek(currentDate) - 1;
514 1094014 hour = datetime_hourOfDay(currentDate);
515
516 // --- for each node with a defined dry weather inflow
517
2/2
✓ Branch 0 taken 17807996 times.
✓ Branch 1 taken 1094014 times.
18902010 for (j = 0; j < Nobjects[NODE]; j++)
518 {
519 17807996 inflow = Node[j].dwfInflow;
520
2/2
✓ Branch 0 taken 17742447 times.
✓ Branch 1 taken 65549 times.
17807996 if ( !inflow ) continue;
521
522 // --- get flow inflow (i.e., the inflow whose param code is -1)
523 65549 q = 0.0;
524
1/2
✓ Branch 0 taken 65549 times.
✗ Branch 1 not taken.
65549 while ( inflow )
525 {
526
1/2
✓ Branch 0 taken 65549 times.
✗ Branch 1 not taken.
65549 if ( inflow->param < 0 )
527 {
528 65549 q = inflow_getDwfInflow(inflow, month, day, hour);
529 65549 break;
530 }
531 inflow = inflow->next;
532 }
533
2/2
✓ Branch 0 taken 12287 times.
✓ Branch 1 taken 53262 times.
65549 if ( fabs(q) < FLOW_TOL ) q = 0.0;
534
535 // --- add flow inflow to node's lateral inflow
536 65549 Node[j].newLatFlow += q;
537 65549 massbal_addInflowFlow(DRY_WEATHER_INFLOW, q);
538
539 // --- stop if inflow is non-positive
540
2/2
✓ Branch 0 taken 12287 times.
✓ Branch 1 taken 53262 times.
65549 if ( q <= 0.0 ) continue;
541
542 // --- add default DWF pollutant inflows
543
2/2
✓ Branch 0 taken 51720 times.
✓ Branch 1 taken 53262 times.
104982 for ( p = 0; p < Nobjects[POLLUT]; p++)
544 {
545
1/2
✓ Branch 0 taken 51720 times.
✗ Branch 1 not taken.
51720 if ( Pollut[p].dwfConcen > 0.0 )
546 {
547 51720 w = q * Pollut[p].dwfConcen;
548 51720 Node[j].newQual[p] += w;
549 51720 massbal_addInflowQual(DRY_WEATHER_INFLOW, p, w);
550 }
551 }
552
553 // --- get pollutant mass inflows
554 53262 inflow = Node[j].dwfInflow;
555
2/2
✓ Branch 0 taken 53262 times.
✓ Branch 1 taken 53262 times.
106524 while ( inflow )
556 {
557
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53262 times.
53262 if ( inflow->param >= 0 )
558 {
559 p = inflow->param;
560 w = q * inflow_getDwfInflow(inflow, month, day, hour);
561 Node[j].newQual[p] += w;
562 massbal_addInflowQual(DRY_WEATHER_INFLOW, p, w);
563
564 // --- subtract off any default inflow
565 if ( Pollut[p].dwfConcen > 0.0 )
566 {
567 w = q * Pollut[p].dwfConcen;
568 Node[j].newQual[p] -= w;
569 massbal_addInflowQual(DRY_WEATHER_INFLOW, p, -w);
570 }
571 }
572 53262 inflow = inflow->next;
573 }
574 }
575 1094014 }
576
577 //=============================================================================
578
579 1094014 void addWetWeatherInflows(double routingTime)
580 //
581 // Input: routingTime = elasped time (millisec)
582 // Output: none
583 // Purpose: adds runoff inflows to nodes at current elapsed time.
584 //
585 {
586 int i, j, p;
587 double q, w;
588 double f;
589
590 // --- find where current routing time lies between latest runoff times
591
2/2
✓ Branch 0 taken 706286 times.
✓ Branch 1 taken 387728 times.
1094014 if ( Nobjects[SUBCATCH] == 0 ) return;
592 387728 f = (routingTime - OldRunoffTime) / (NewRunoffTime - OldRunoffTime);
593
2/2
✓ Branch 0 taken 9349 times.
✓ Branch 1 taken 378379 times.
387728 if ( f < 0.0 ) f = 0.0;
594
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 387728 times.
387728 if ( f > 1.0 ) f = 1.0;
595
596 // for each subcatchment outlet node,
597 // add interpolated runoff flow & pollutant load to node's inflow
598
2/2
✓ Branch 0 taken 1971199 times.
✓ Branch 1 taken 387728 times.
2358927 for (i = 0; i < Nobjects[SUBCATCH]; i++)
599 {
600 1971199 j = Subcatch[i].outNode;
601
2/2
✓ Branch 0 taken 1962559 times.
✓ Branch 1 taken 8640 times.
1971199 if ( j >= 0)
602 {
603 // add runoff flow to lateral inflow
604 1962559 q = subcatch_getWtdOutflow(i, f); // current runoff flow
605 1962559 Node[j].newLatFlow += q;
606 1962559 massbal_addInflowFlow(WET_WEATHER_INFLOW, q);
607
608 // add pollutant load
609
2/2
✓ Branch 0 taken 2843080 times.
✓ Branch 1 taken 1962559 times.
4805639 for (p = 0; p < Nobjects[POLLUT]; p++)
610 {
611 2843080 w = surfqual_getWtdWashoff(i, p, f);
612 2843080 Node[j].newQual[p] += w;
613 2843080 massbal_addInflowQual(WET_WEATHER_INFLOW, p, w);
614 }
615 }
616 }
617 }
618
619 //=============================================================================
620
621 1094014 void addGroundwaterInflows(double routingTime)
622 //
623 // Input: routingTime = elasped time (millisec)
624 // Output: none
625 // Purpose: adds groundwater inflows to nodes at current elapsed time.
626 //
627 {
628 int i, j, p;
629 double q, w;
630 double f;
631 TGroundwater* gw;
632
633 // --- find where current routing time lies between latest runoff times
634
2/2
✓ Branch 0 taken 706286 times.
✓ Branch 1 taken 387728 times.
1094014 if ( Nobjects[SUBCATCH] == 0 ) return;
635 387728 f = (routingTime - OldRunoffTime) / (NewRunoffTime - OldRunoffTime);
636
2/2
✓ Branch 0 taken 9349 times.
✓ Branch 1 taken 378379 times.
387728 if ( f < 0.0 ) f = 0.0;
637
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 387728 times.
387728 if ( f > 1.0 ) f = 1.0;
638
639 // --- for each subcatchment
640
2/2
✓ Branch 0 taken 1971199 times.
✓ Branch 1 taken 387728 times.
2358927 for (i = 0; i < Nobjects[SUBCATCH]; i++)
641 {
642 // --- see if subcatch contains groundwater
643 1971199 gw = Subcatch[i].groundwater;
644
2/2
✓ Branch 0 taken 53458 times.
✓ Branch 1 taken 1917741 times.
1971199 if ( gw )
645 {
646 // --- identify node receiving groundwater flow
647 53458 j = gw->node;
648
1/2
✓ Branch 0 taken 53458 times.
✗ Branch 1 not taken.
53458 if ( j >= 0 )
649 {
650 // add groundwater flow to lateral inflow
651 53458 q = ( (1.0 - f)*(gw->oldFlow) + f*(gw->newFlow) )
652 53458 * Subcatch[i].area;
653
2/2
✓ Branch 0 taken 12371 times.
✓ Branch 1 taken 41087 times.
53458 if ( fabs(q) < FLOW_TOL ) continue;
654 41087 Node[j].newLatFlow += q;
655 41087 massbal_addInflowFlow(GROUNDWATER_INFLOW, q);
656
657 // add pollutant load (for positive inflow)
658
2/2
✓ Branch 0 taken 7138 times.
✓ Branch 1 taken 33949 times.
41087 if ( q > 0.0 )
659 {
660
2/2
✓ Branch 0 taken 25848 times.
✓ Branch 1 taken 7138 times.
32986 for (p = 0; p < Nobjects[POLLUT]; p++)
661 {
662 25848 w = q * Pollut[p].gwConcen;
663 25848 Node[j].newQual[p] += w;
664 25848 massbal_addInflowQual(GROUNDWATER_INFLOW, p, w);
665 }
666 }
667 }
668 }
669 }
670 }
671
672 //=============================================================================
673
674 1094014 void addLidDrainInflows(double routingTime)
675 //
676 // Input: routingTime = elasped time (millisec)
677 // Output: none
678 // Purpose: adds inflows to nodes receiving LID drain flow.
679 //
680 {
681 int j;
682 double f;
683
684 // for each subcatchment
685
2/2
✓ Branch 0 taken 706286 times.
✓ Branch 1 taken 387728 times.
1094014 if ( Nobjects[SUBCATCH] == 0 ) return;
686 387728 f = (routingTime - OldRunoffTime) / (NewRunoffTime - OldRunoffTime);
687
2/2
✓ Branch 0 taken 9349 times.
✓ Branch 1 taken 378379 times.
387728 if ( f < 0.0 ) f = 0.0;
688
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 387728 times.
387728 if ( f > 1.0 ) f = 1.0;
689
2/2
✓ Branch 0 taken 1971199 times.
✓ Branch 1 taken 387728 times.
2358927 for (j = 0; j < Nobjects[SUBCATCH]; j++)
690 {
691
3/4
✓ Branch 0 taken 1971199 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 52551 times.
✓ Branch 3 taken 1918648 times.
1971199 if ( Subcatch[j].area > 0.0 && Subcatch[j].lidArea > 0.0 )
692 52551 lid_addDrainInflow(j, f);
693 }
694 }
695
696 //=============================================================================
697
698 1094014 void addRdiiInflows(DateTime currentDate)
699 //
700 // Input: currentDate = current date/time
701 // Output: none
702 // Purpose: adds RDII inflows to nodes at current date.
703 //
704 {
705 int i, j, p;
706 double q, w;
707 int numRdiiNodes;
708
709 // --- see if any nodes have RDII at current date
710 1094014 numRdiiNodes = rdii_getNumRdiiFlows(currentDate);
711
712 // --- add RDII flow to each node's lateral inflow
713
2/2
✓ Branch 0 taken 4915 times.
✓ Branch 1 taken 1094014 times.
1098929 for (i=0; i<numRdiiNodes; i++)
714 {
715 4915 rdii_getRdiiFlow(i, &j, &q);
716
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4915 times.
4915 if ( j < 0 ) continue;
717
2/2
✓ Branch 0 taken 121 times.
✓ Branch 1 taken 4794 times.
4915 if ( fabs(q) < FLOW_TOL ) continue;
718 4794 Node[j].newLatFlow += q;
719 4794 massbal_addInflowFlow(RDII_INFLOW, q);
720
721 // add pollutant load (for positive inflow)
722
1/2
✓ Branch 0 taken 4794 times.
✗ Branch 1 not taken.
4794 if ( q > 0.0 )
723 {
724
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4794 times.
4794 for (p = 0; p < Nobjects[POLLUT]; p++)
725 {
726 w = q * Pollut[p].rdiiConcen;
727 Node[j].newQual[p] += w;
728 massbal_addInflowQual(RDII_INFLOW, p, w);
729 }
730 }
731 }
732 1094014 }
733
734 //=============================================================================
735
736 1094014 void addIfaceInflows(DateTime currentDate)
737 //
738 // Input: currentDate = current date/time
739 // Output: none
740 // Purpose: adds inflows from routing interface file to nodes at current date.
741 //
742 {
743 int i, j, p;
744 double q, w;
745 int numIfaceNodes;
746
747 // --- see if any nodes have interface inflows at current date
748
2/2
✓ Branch 0 taken 1089693 times.
✓ Branch 1 taken 4321 times.
1094014 if ( Finflows.mode != USE_FILE ) return;
749 4321 numIfaceNodes = iface_getNumIfaceNodes(currentDate);
750
751 // --- add interface flow to each node's lateral inflow
752
2/2
✓ Branch 0 taken 4321 times.
✓ Branch 1 taken 4321 times.
8642 for (i=0; i<numIfaceNodes; i++)
753 {
754 4321 j = iface_getIfaceNode(i);
755
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4321 times.
4321 if ( j < 0 ) continue;
756 4321 q = iface_getIfaceFlow(i);
757
2/2
✓ Branch 0 taken 845 times.
✓ Branch 1 taken 3476 times.
4321 if ( fabs(q) < FLOW_TOL ) continue;
758 3476 Node[j].newLatFlow += q;
759 3476 massbal_addInflowFlow(EXTERNAL_INFLOW, q);
760
761 // add pollutant load (for positive inflow)
762
1/2
✓ Branch 0 taken 3476 times.
✗ Branch 1 not taken.
3476 if ( q > 0.0 )
763 {
764
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3476 times.
3476 for (p = 0; p < Nobjects[POLLUT]; p++)
765 {
766 w = q * iface_getIfaceQual(i, p);
767 Node[j].newQual[p] += w;
768 massbal_addInflowQual(EXTERNAL_INFLOW, p, w);
769 }
770 }
771 }
772 }
773
774 //=============================================================================
775
776 int inflowHasChanged()
777 //
778 // Input: none
779 // Output: returns TRUE if external inflows or outfall flows have changed
780 // from the previous time step
781 // Purpose: checks if the hydraulic state of the system has changed from
782 // the previous time step.
783 //
784 {
785 int j;
786 double diff, qOld, qNew;
787
788 // --- check if external inflows or outfall flows have changed
789 for (j = 0; j < Nobjects[NODE]; j++)
790 {
791 qOld = Node[j].oldLatFlow;
792 qNew = Node[j].newLatFlow;
793 if ( fabs(qOld) > TINY ) diff = (qNew / qOld) - 1.0;
794 else if ( fabs(qNew) > TINY ) diff = 1.0;
795 else diff = 0.0;
796 if ( fabs(diff) > LatFlowTol ) return TRUE;
797 if ( Node[j].type == OUTFALL || Node[j].degree == 0 )
798 {
799 qOld = Node[j].oldFlowInflow;
800 qNew = Node[j].inflow;
801 if ( fabs(qOld) > TINY ) diff = (qNew / qOld) - 1.0;
802 else if ( fabs(qNew) > TINY ) diff = 1.0;
803 else diff = 0.0;
804 if ( fabs(diff) > LatFlowTol ) return TRUE;
805 }
806 }
807 return FALSE;
808 }
809
810 //=============================================================================
811
812 1094014 void removeStorageLosses(double tStep)
813 //
814 // Input: tStep = routing time step (sec)
815 // Output: none
816 // Purpose: adds flow rate lost from all storage nodes due to evaporation
817 // & seepage in current time step to overall mass balance totals.
818 //
819 {
820 int i;
821 1094014 double evapLoss = 0.0,
822 1094014 exfilLoss = 0.0;
823
824 // --- check each storage node
825
2/2
✓ Branch 0 taken 17807996 times.
✓ Branch 1 taken 1094014 times.
18902010 for ( i = 0; i < Nobjects[NODE]; i++ )
826 {
827
2/2
✓ Branch 0 taken 180549 times.
✓ Branch 1 taken 17627447 times.
17807996 if (Node[i].type == STORAGE)
828 {
829 // --- update total system storage losses
830 180549 evapLoss += Storage[Node[i].subIndex].evapLoss;
831 180549 exfilLoss += Storage[Node[i].subIndex].exfilLoss;
832 }
833 }
834
835 // --- add loss rates (ft3/sec) to time step's mass balance
836 1094014 massbal_addNodeLosses(evapLoss/tStep, exfilLoss/tStep);
837 1094014 }
838
839 //=============================================================================
840
841 1094014 void removeConduitLosses()
842 //
843 // Input: none
844 // Output: none
845 // Purpose: adds flow rate lost from all conduits due to evaporation
846 // & seepage over current time step to overall mass balance.
847 //
848 {
849 int i, k;
850 double barrels,
851 1094014 evapLoss = 0.0,
852 1094014 seepLoss = 0.0;
853
854
2/2
✓ Branch 0 taken 16744382 times.
✓ Branch 1 taken 1094014 times.
17838396 for ( i = 0; i < Nobjects[LINK]; i++ )
855 {
856
2/2
✓ Branch 0 taken 16368991 times.
✓ Branch 1 taken 375391 times.
16744382 if (Link[i].type == CONDUIT)
857 {
858 // --- retrieve number of barrels
859 16368991 k = Link[i].subIndex;
860 16368991 barrels = Conduit[k].barrels;
861
862 // --- update total conduit losses
863 16368991 evapLoss += Conduit[k].evapLossRate * barrels;
864 16368991 seepLoss += Conduit[k].seepLossRate * barrels;
865 }
866 }
867 1094014 massbal_addLinkLosses(evapLoss, seepLoss);
868 1094014 }
869
870 //=============================================================================
871
872 1094014 void removeOutflows(double tStep)
873 //
874 // Input: none
875 // Output: none
876 // Purpose: finds flows that leave the system and adds these to mass
877 // balance totals.
878 //
879 {
880 int i, p, k;
881 int isFlooded;
882 double q, w, v;
883
884
2/2
✓ Branch 0 taken 17807996 times.
✓ Branch 1 taken 1094014 times.
18902010 for ( i = 0; i < Nobjects[NODE]; i++ )
885 {
886 // --- accumulate inflow volume & pollut. load at outfalls
887
4/4
✓ Branch 0 taken 1365046 times.
✓ Branch 1 taken 16442950 times.
✓ Branch 2 taken 690725 times.
✓ Branch 3 taken 674321 times.
17807996 if ( Node[i].type == OUTFALL && Node[i].inflow > 0.0 )
888 {
889 690725 k = Node[i].subIndex;
890
2/2
✓ Branch 0 taken 1405 times.
✓ Branch 1 taken 689320 times.
690725 if ( Outfall[k].routeTo >= 0 )
891 {
892 1405 v = Node[i].inflow * tStep;
893 1405 Outfall[k].vRouted += v;
894
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1405 times.
1405 for (p = 0; p < Nobjects[POLLUT]; p++)
895 Outfall[k].wRouted[p] += Node[i].newQual[p] * v;
896 }
897 }
898
899 // --- update mass balance with flow and mass leaving the system
900 // through outfalls and flooded interior nodes
901 17807996 q = node_getSystemOutflow(i, &isFlooded);
902
2/2
✓ Branch 0 taken 731818 times.
✓ Branch 1 taken 17076178 times.
17807996 if ( q > 0.0 )
903 {
904 731818 massbal_addOutflowFlow(q, isFlooded);
905
2/2
✓ Branch 0 taken 393293 times.
✓ Branch 1 taken 731818 times.
1125111 for ( p = 0; p < Nobjects[POLLUT]; p++ )
906 {
907 393293 w = q * Node[i].newQual[p];
908 393293 massbal_addOutflowQual(p, w, isFlooded);
909 }
910 }
911 17076178 else massbal_addInflowFlow(EXTERNAL_INFLOW, -q);
912
913 // --- update mass balance with mass leaving system through negative
914 // lateral inflows (lateral flow was previously accounted for)
915 17807996 q = Node[i].newLatFlow;
916
2/2
✓ Branch 0 taken 20452 times.
✓ Branch 1 taken 17787544 times.
17807996 if ( q < 0.0 )
917 {
918
2/2
✓ Branch 0 taken 1851 times.
✓ Branch 1 taken 20452 times.
22303 for ( p = 0; p < Nobjects[POLLUT]; p++ )
919 {
920 1851 w = -q * Node[i].newQual[p];
921 1851 massbal_addOutflowQual(p, w, FALSE);
922 }
923 }
924 }
925 1094014 }
926
927 //=============================================================================
928
929 2 void sortEvents()
930 //
931 // Input: none
932 // Output: none
933 // Purpose: sorts the entries of the Event array in chronological order.
934 //
935 {
936 int i, j, gap;
937 TEvent temp;
938
939 // Apply shell sort to event list
940
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 for (gap = NumEvents/2; gap >= 1; gap /= 2)
941 {
942
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (i = gap; i < NumEvents; i += gap)
943 {
944 4 temp = Event[i];
945 4 j = i - gap;
946
4/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 2 times.
7 while (j >= 0 && Event[j].start > temp.start)
947 {
948 3 Event[j+gap] = Event[j];
949 3 j -= gap;
950 }
951
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 time.
4 if (j != i-gap) Event[j+gap] = temp;
952 }
953 }
954
955 // Adjust for overlapping events
956
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (i = 0; i < NumEvents-1; i++)
957 {
958
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if ( Event[i].end > Event[i+1].start ) Event[i].end = Event[i+1].start;
959 }
960 2 }
961
962 //=============================================================================
963