GCC Code Coverage Report


Directory: src/solver/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 89.3% 635 / 0 / 711
Functions: 97.3% 36 / 0 / 37
Branches: 70.4% 338 / 0 / 480

lid.c
Line Branch Exec Source
1 //-----------------------------------------------------------------------------
2 // lid.c
3 //
4 // Project: EPA SWMM5
5 // Version: 5.2
6 // Date: 07/13/23 (Build 5.2.4)
7 // Author: L. Rossman
8 //
9 // This module handles all data processing involving LID (Low Impact
10 // Development) practices used to treat runoff for individual subcatchments
11 // within a project. The actual computation of LID performance is made by
12 // functions within the lidproc.c module. See LidTypes below for the types
13 // of LIDs that can be modeled.
14 //
15 // An LID process is described by the TLidProc data structure and consists of
16 // size-independent design data for the different vertical layers that make
17 // up a specific type of LID. The collection of these LID process designs is
18 // stored in the LidProcs array.
19 //
20 // When a member of LidProcs is to be deployed in a particular subcatchment,
21 // its sizing and treatment data are stored in a TLidUnit data structure.
22 // The collection of all TLidUnits deployed in a subcatchment is held in a
23 // TLidGroup list data structure. The LidGroups array contains a TLidGroup
24 // list for each subcatchment in the project.
25 //
26 // During a runoff time step, each subcatchment calls the lid_getRunoff()
27 // function to compute flux rates and a water balance through each layer
28 // of each LID unit in the subcatchment. The resulting outflows (runoff,
29 // drain flow, evaporation and infiltration) are added to those computed
30 // for the non-LID portion of the subcatchment.
31 //
32 // An option exists for the detailed time series of flux rates and storage
33 // levels for a specific LID unit to be written to a text file named by the
34 // user for viewing outside of the SWMM program.
35 //
36 // Update History
37 // ==============
38 // Build 5.1.008:
39 // - More input error reporting added.
40 // - Rooftop Disconnection added to the types of LIDs.
41 // - LID drain flows are now tracked separately.
42 // - LID drain flows can now be routed to separate outlets.
43 // - Check added to insure LID flows not returned to nonexistent pervious area.
44 // Build 5.1.009:
45 // - Fixed bug where LID's could return outflow to non-LID area when LIDs
46 // make up entire subcatchment.
47 // Build 5.1.010:
48 // - Support for new Modified Green Ampt infiltration model added.
49 // - Imported variable HasWetLids now properly initialized.
50 // - Initial state of reporting (lidUnit->rptFile->wasDry) changed to
51 // prevent duplicate printing of first line of detailed report file.
52 // Build 5.1.011:
53 // - The top of the storage layer is no longer used as a limit for an
54 // underdrain offset thus allowing upturned drains to be modeled.
55 // - Column headings for the detailed LID report file were modified.
56 // Build 5.1.012:
57 // - Redefined initialization of wasDry for LID reporting.
58 // Build 5.1.013:
59 // - Support added for LID units treating pervious area runoff.
60 // - Support added for open/closed head levels and multiplier v. head
61 // control curve for underdrain flow.
62 // - Support added for unclogging permeable pavement at fixed intervals.
63 // - Support added for pollutant removal in underdrain flow.
64 // Build 5.1.014:
65 // - Fixed bug in creating LidProcs when there are no subcatchments.
66 // - Fixed bug in adding underdrain pollutant loads to mass balances.
67 // Build 5.1.015:
68 // - Support added for mutiple infiltration methods within a project.
69 // Build 5.2.0:
70 // - Covered property added to RAIN_BARREL parameters
71 // Build 5.2.3
72 // - Fixed double counting of initial water volume in green roof drain mat.
73 // Build 5.2.4
74 // - Fixed test for invalid data in readDrainData function.
75 //-----------------------------------------------------------------------------
76 #define _CRT_SECURE_NO_DEPRECATE
77
78 #include <math.h>
79 #include "headers.h"
80 #include "lid.h"
81
82 #define ERR_PAVE_LAYER " - check pavement layer parameters"
83 #define ERR_SOIL_LAYER " - check soil layer parameters"
84 #define ERR_STOR_LAYER " - check storage layer parameters"
85 #define ERR_SWALE_SURF " - check swale surface parameters"
86 #define ERR_GREEN_AMPT " - check subcatchment Green-Ampt parameters"
87 #define ERR_DRAIN_OFFSET " - drain offset exceeds storage height"
88 #define ERR_DRAIN_HEADS " - invalid drain open/closed heads"
89 #define ERR_SWALE_WIDTH " - invalid swale width"
90
91 //-----------------------------------------------------------------------------
92 // Enumerations
93 //-----------------------------------------------------------------------------
94 enum LidLayerTypes {
95 SURF, // surface layer
96 SOIL, // soil layer
97 STOR, // storage layer
98 PAVE, // pavement layer
99 DRAINMAT, // drainage mat layer
100 DRAIN, // underdrain system
101 REMOVALS}; // pollutant removals
102
103 //// Note: DRAINMAT must be placed before DRAIN so the two keywords can
104 /// be distinguished from one another when parsing a line of input.
105
106 char* LidLayerWords[] =
107 {"SURFACE", "SOIL", "STORAGE", "PAVEMENT", "DRAINMAT", "DRAIN",
108 "REMOVALS", NULL};
109
110 char* LidTypeWords[] =
111 {"BC", //bio-retention cell
112 "RG", //rain garden
113 "GR", //green roof
114 "IT", //infiltration trench
115 "PP", //porous pavement
116 "RB", //rain barrel
117 "VS", //vegetative swale
118 "RD", //rooftop disconnection
119 NULL};
120
121 //-----------------------------------------------------------------------------
122 // Data Structures
123 //-----------------------------------------------------------------------------
124
125 // LID List - list of LID units contained in an LID group
126 struct LidList
127 {
128 TLidUnit* lidUnit; // ptr. to a LID unit
129 struct LidList* nextLidUnit;
130 };
131 typedef struct LidList TLidList;
132
133 // LID Group - collection of LID units applied to a specific subcatchment
134 struct LidGroup
135 {
136 double pervArea; // amount of pervious area in group (ft2)
137 double flowToPerv; // total flow sent to pervious area (cfs)
138 double oldDrainFlow; // total drain flow in previous period (cfs)
139 double newDrainFlow; // total drain flow in current period (cfs)
140 TLidList* lidList; // list of LID units in the group
141 };
142 typedef struct LidGroup* TLidGroup;
143
144
145 //-----------------------------------------------------------------------------
146 // Shared Variables
147 //-----------------------------------------------------------------------------
148 static TLidProc* LidProcs; // array of LID processes
149 static int LidCount; // number of LID processes
150 static TLidGroup* LidGroups; // array of LID process groups
151 static int GroupCount; // number of LID groups (subcatchments)
152
153 static double EvapRate; // evaporation rate (ft/s)
154 static double NativeInfil; // native soil infil. rate (ft/s)
155 static double MaxNativeInfil; // native soil infil. rate limit (ft/s)
156
157 //-----------------------------------------------------------------------------
158 // Imported Variables (from SUBCATCH.C)
159 //-----------------------------------------------------------------------------
160 // Volumes (ft3) for a subcatchment over a time step
161 extern double Vevap; // evaporation
162 extern double Vpevap; // pervious area evaporation
163 extern double Vinfil; // non-LID infiltration
164 extern double VlidInfil; // infiltration from LID units
165 extern double VlidIn; // impervious area flow to LID units
166 extern double VlidOut; // surface outflow from LID units
167 extern double VlidDrain; // drain outflow from LID units
168 extern double VlidReturn; // LID outflow returned to pervious area
169 extern char HasWetLids; // TRUE if any LIDs are wet
170 // (from RUNOFF.C)
171
172 //-----------------------------------------------------------------------------
173 // External Functions (prototyped in lid.h)
174 //-----------------------------------------------------------------------------
175 // lid_create called by createObjects in project.c
176 // lid_delete called by deleteObjects in project.c
177 // lid_validate called by project_validate
178 // lid_initState called by project_init
179
180 // lid_readProcParams called by parseLine in input.c
181 // lid_readGroupParams called by parseLine in input.c
182
183 // lid_setOldGroupState called by subcatch_setOldState
184 // lid_setReturnQual called by findLidLoads in surfqual.c
185 // lid_getReturnQual called by subcatch_getRunon
186
187 // lid_getPervArea called by subcatch_getFracPerv
188 // lid_getFlowToPerv called by subcatch_getRunon
189 // lid_getSurfaceDepth called by subcatch_getDepth
190 // lid_getDepthOnPavement called by sweptSurfacesDry in subcatch.c
191 // lid_getStoredVolume called by subcatch_getStorage
192 // lid_getRunon called by subcatch_getRunon
193 // lid_getRunoff called by subcatch_getRunoff
194
195 // lid_addDrainRunon called by subcatch_getRunon
196 // lid_addDrainLoads called by surfqual_getWashoff
197 // lid_addDrainInflow called by addLidDrainInflows in routing.c
198
199 // lid_writeSummary called by inputrpt_writeInput
200 // lid_writeWaterBalance called by statsrpt_writeReport
201
202
203 //-----------------------------------------------------------------------------
204 // Local Functions
205 //-----------------------------------------------------------------------------
206 static void freeLidGroup(int j);
207 static int readSurfaceData(int j, char* tok[], int ntoks);
208 static int readPavementData(int j, char* tok[], int ntoks);
209 static int readSoilData(int j, char* tok[], int ntoks);
210 static int readStorageData(int j, char* tok[], int ntoks);
211 static int readDrainData(int j, char* tok[], int ntoks);
212 static int readDrainMatData(int j, char* toks[], int ntoks);
213 static int readRemovalsData(int j, char* toks[], int ntoks);
214
215 static int addLidUnit(int j, int k, int n, double x[], char* fname,
216 int drainSubcatch, int drainNode);
217 static int createLidRptFile(TLidUnit* lidUnit, char* fname);
218 static void initLidRptFile(char* title, char* lidID, char* subcatchID,
219 TLidUnit* lidUnit);
220 static void validateLidProc(int j);
221 static void validateLidGroup(int j);
222
223 static int isLidPervious(int k);
224 static double getImpervAreaRunoff(int j);
225 static double getPervAreaRunoff(int j);
226 static double getSurfaceDepth(int subcatch);
227 static double getRainInflow(int j, TLidUnit* lidUnit);
228 static void findNativeInfil(int j, double tStep);
229
230
231 static void evalLidUnit(int j, TLidUnit* lidUnit, double lidArea,
232 double lidInflow, double tStep, double *qRunoff,
233 double *qDrain, double *qReturn);
234
235 //=============================================================================
236
237 58 void lid_create(int lidCount, int subcatchCount)
238 //
239 // Purpose: creates an array of LID objects.
240 // Input: n = number of LID processes
241 // Output: none
242 //
243 {
244 int j;
245
246 //... assign NULL values to LID arrays
247 58 LidProcs = NULL;
248 58 LidGroups = NULL;
249 58 LidCount = lidCount;
250
251 //... create LID groups
252 58 GroupCount = subcatchCount;
253
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 21 times.
58 if ( GroupCount > 0 )
254 {
255 37 LidGroups = (TLidGroup *) calloc(GroupCount, sizeof(TLidGroup));
256
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 if ( LidGroups == NULL )
257 {
258 ErrorCode = ERR_MEMORY;
259 return;
260 }
261 }
262
263 //... initialize LID groups
264
2/2
✓ Branch 0 taken 2393 times.
✓ Branch 1 taken 58 times.
2451 for (j = 0; j < GroupCount; j++) LidGroups[j] = NULL;
265
266 //... create LID objects
267
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 13 times.
58 if ( LidCount == 0 ) return;
268 13 LidProcs = (TLidProc *) calloc(LidCount, sizeof(TLidProc));
269
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if ( LidProcs == NULL )
270 {
271 ErrorCode = ERR_MEMORY;
272 return;
273 }
274
275 //... initialize LID objects
276
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 13 times.
33 for (j = 0; j < LidCount; j++)
277 {
278 20 LidProcs[j].lidType = -1;
279 20 LidProcs[j].surface.thickness = 0.0;
280 20 LidProcs[j].surface.voidFrac = 1.0;
281 20 LidProcs[j].surface.roughness = 0.0;
282 20 LidProcs[j].surface.surfSlope = 0.0;
283 20 LidProcs[j].pavement.thickness = 0.0;
284 20 LidProcs[j].soil.thickness = 0.0;
285 20 LidProcs[j].storage.thickness = 0.0;
286 20 LidProcs[j].storage.kSat = 0.0;
287 20 LidProcs[j].drain.coeff = 0.0;
288 20 LidProcs[j].drain.offset = 0.0;
289 20 LidProcs[j].drainMat.thickness = 0.0;
290 20 LidProcs[j].drainMat.roughness = 0.0;
291 20 LidProcs[j].drainRmvl = NULL;
292 20 LidProcs[j].drainRmvl = (double *)
293 20 calloc(Nobjects[POLLUT], sizeof(double));
294
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (LidProcs[j].drainRmvl == NULL)
295 {
296 ErrorCode = ERR_MEMORY;
297 return;
298 }
299 }
300 }
301
302 //=============================================================================
303
304 58 void lid_delete()
305 //
306 // Purpose: deletes all LID objects
307 // Input: none
308 // Output: none
309 //
310 {
311 int j;
312
2/2
✓ Branch 1 taken 2393 times.
✓ Branch 2 taken 58 times.
2451 for (j = 0; j < GroupCount; j++) freeLidGroup(j);
313
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 21 times.
58 FREE(LidGroups);
314
3/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 58 times.
78 for (j = 0; j < LidCount; j++) FREE(LidProcs[j].drainRmvl);
315
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 45 times.
58 FREE(LidProcs);
316 58 GroupCount = 0;
317 58 LidCount = 0;
318 58 }
319
320 //=============================================================================
321
322 2393 void freeLidGroup(int j)
323 //
324 // Purpose: frees all LID units associated with a subcatchment.
325 // Input: j = group (or subcatchment) index
326 // Output: none
327 //
328 {
329 2393 TLidGroup lidGroup = LidGroups[j];
330 TLidList* lidList;
331 TLidUnit* lidUnit;
332 TLidList* nextLidUnit;
333
334
2/2
✓ Branch 0 taken 2382 times.
✓ Branch 1 taken 11 times.
2393 if ( lidGroup == NULL ) return;
335 11 lidList = lidGroup->lidList;
336
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 11 times.
29 while (lidList)
337 {
338 18 lidUnit = lidList->lidUnit;
339
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 15 times.
18 if ( lidUnit->rptFile )
340 {
341
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if ( lidUnit->rptFile->file ) fclose(lidUnit->rptFile->file);
342 3 free(lidUnit->rptFile);
343 }
344 18 nextLidUnit = lidList->nextLidUnit;
345 18 free(lidUnit);
346 18 free(lidList);
347 18 lidList = nextLidUnit;
348 }
349 11 free(lidGroup);
350 11 LidGroups[j] = NULL;
351 }
352
353 //=============================================================================
354
355 73 int lid_readProcParams(char* toks[], int ntoks)
356 //
357 // Purpose: reads LID process information from line of input data file
358 // Input: toks = array of string tokens
359 // ntoks = number of tokens
360 // Output: returns error code
361 //
362 // Format for first line that defines a LID process is:
363 // LID_ID LID_Type
364 //
365 // Followed by some combination of lines below depending on LID_Type:
366 // LID_ID SURFACE <parameters>
367 // LID_ID PAVEMENT <parameters>
368 // LID_ID SOIL <parameters>
369 // LID_ID STORAGE <parameters>
370 // LID_ID DRAIN <parameters>
371 // LID_ID DRAINMAT <parameters>
372 // LID_ID REMOVALS <parameters>
373 //
374 {
375 int j, m;
376
377 // --- check for minimum number of tokens
378
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 73 times.
73 if ( ntoks < 2 ) return error_setInpError(ERR_ITEMS, "");
379
380 // --- check that LID exists in database
381 73 j = project_findObject(LID, toks[0]);
382
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 73 times.
73 if ( j < 0 ) return error_setInpError(ERR_NAME, toks[0]);
383
384 // --- assign ID if not done yet
385
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 53 times.
73 if ( LidProcs[j].ID == NULL )
386 20 LidProcs[j].ID = project_findID(LID, toks[0]);
387
388 // --- check if second token is the type of LID
389 73 m = findmatch(toks[1], LidTypeWords);
390
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 53 times.
73 if ( m >= 0 )
391 {
392 20 LidProcs[j].lidType = m;
393 20 return 0;
394 }
395
396 // --- check if second token is name of LID layer
397 53 else m = findmatch(toks[1], LidLayerWords);
398
399 // --- read input parameters for the identified layer
400
7/8
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 1 time.
✗ Branch 7 not taken.
53 switch (m)
401 {
402 16 case SURF: return readSurfaceData(j, toks, ntoks);
403 8 case SOIL: return readSoilData(j, toks, ntoks);
404 12 case STOR: return readStorageData(j, toks, ntoks);
405 2 case PAVE: return readPavementData(j, toks, ntoks);
406 12 case DRAIN: return readDrainData(j, toks, ntoks);
407 2 case DRAINMAT: return readDrainMatData(j, toks, ntoks);
408 1 case REMOVALS: return readRemovalsData(j, toks, ntoks);
409 }
410 return error_setInpError(ERR_KEYWORD, toks[1]);
411 }
412
413 //=============================================================================
414
415 18 int lid_readGroupParams(char* toks[], int ntoks)
416 //
417 // Purpose: reads input data for a LID unit placed in a subcatchment.
418 // Input: toks = array of string tokens
419 // ntoks = number of tokens
420 // Output: returns error code
421 //
422 // Format of input data line is:
423 // Subcatch_ID LID_ID Number Area Width InitSat FromImp ToPerv
424 // (RptFile DrainTo FromPerv)
425 // where:
426 // Subcatch_ID = name of subcatchment
427 // LID_ID = name of LID process
428 // Number (n) = number of replicate units
429 // Area (x[0]) = area of each unit
430 // Width (x[1]) = outflow width of each unit
431 // InitSat (x[2]) = % that LID is initially saturated
432 // FromImp (x[3]) = % of impervious runoff sent to LID
433 // ToPerv (x[4]) = 1 if outflow goes to pervious sub-area; 0 if not
434 // RptFile = name of detailed results file (optional)
435 // DrainTo = name of subcatch/node for drain flow (optional)
436 // FromPerv (x[5]) = % of pervious runoff sent to LID
437 //
438 {
439 int i, j, k, n;
440 double x[6];
441 18 char* fname = NULL;
442 18 int drainSubcatch = -1, drainNode = -1;
443
444 //... check for valid number of input tokens
445
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if ( ntoks < 8 ) return error_setInpError(ERR_ITEMS, "");
446
447 //... find subcatchment
448 18 j = project_findObject(SUBCATCH, toks[0]);
449
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if ( j < 0 ) return error_setInpError(ERR_NAME, toks[0]);
450
451 //... find LID process in list of LID processes
452 18 k = project_findObject(LID, toks[1]);
453
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if ( k < 0 ) return error_setInpError(ERR_NAME, toks[1]);
454
455 //... get number of replicates
456 18 n = atoi(toks[2]);
457
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if ( n < 0 ) return error_setInpError(ERR_NUMBER, toks[2]);
458
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if ( n == 0 ) return 0;
459
460 //... convert next 4 tokens to doubles
461
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 18 times.
108 for (i = 3; i <= 7; i++)
462 {
463
2/4
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 90 times.
90 if ( ! getDouble(toks[i], &x[i-3]) || x[i-3] < 0.0 )
464 return error_setInpError(ERR_NUMBER, toks[i]);
465 }
466
467 //... check for valid percentages on tokens 5 & 6 (x[2] & x[3])
468
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 36 times.
✓ Branch 3 taken 18 times.
54 for (i = 2; i <= 3; i++) if ( x[i] > 100.0 )
469 return error_setInpError(ERR_NUMBER, toks[i+3]);
470
471 //... read optional report file name
472
4/4
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 13 times.
18 if ( ntoks >= 9 && strcmp(toks[8], "*") != 0 ) fname = toks[8];
473
474 //... read optional underdrain outlet
475
4/4
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 13 times.
18 if ( ntoks >= 10 && strcmp(toks[9], "*") != 0 )
476 {
477 1 drainSubcatch = project_findObject(SUBCATCH, toks[9]);
478
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if ( drainSubcatch < 0 )
479 {
480 1 drainNode = project_findObject(NODE, toks[9]);
481
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if ( drainNode < 0 ) return error_setInpError(ERR_NAME, toks[9]);
482 }
483 }
484
485 //... read percent of pervious area treated by LID unit
486 18 x[5] = 0.0;
487
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 4 times.
18 if (ntoks >= 11)
488 {
489
3/6
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 14 times.
14 if (!getDouble(toks[10], &x[5]) || x[5] < 0.0 || x[5] > 100.0)
490 return error_setInpError(ERR_NUMBER, toks[10]);
491 }
492
493 //... create a new LID unit and add it to the subcatchment's LID group
494 18 return addLidUnit(j, k, n, x, fname, drainSubcatch, drainNode);
495 }
496
497 //=============================================================================
498
499 18 int addLidUnit(int j, int k, int n, double x[], char* fname,
500 int drainSubcatch, int drainNode)
501 //
502 // Purpose: adds an LID unit to a subcatchment's LID group.
503 // Input: j = subcatchment index
504 // k = LID control index
505 // n = number of replicate units
506 // x = LID unit's parameters
507 // fname = name of detailed performance report file
508 // drainSubcatch = index of subcatchment receiving underdrain flow
509 // drainNode = index of node receiving underdrain flow
510 // Output: returns an error code
511 //
512 {
513 TLidUnit* lidUnit;
514 TLidList* lidList;
515 TLidGroup lidGroup;
516
517 //... create a LID group (pointer to an LidGroup struct)
518 // if one doesn't already exist
519 18 lidGroup = LidGroups[j];
520
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 7 times.
18 if ( !lidGroup )
521 {
522 11 lidGroup = (struct LidGroup *) malloc(sizeof(struct LidGroup));
523
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if ( !lidGroup ) return error_setInpError(ERR_MEMORY, "");
524 11 lidGroup->lidList = NULL;
525 11 LidGroups[j] = lidGroup;
526 }
527
528 //... create a new LID unit to add to the group
529 18 lidUnit = (TLidUnit *) malloc(sizeof(TLidUnit));
530
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if ( !lidUnit ) return error_setInpError(ERR_MEMORY, "");
531 18 lidUnit->rptFile = NULL;
532
533 //... add the LID unit to the group
534 18 lidList = (TLidList *) malloc(sizeof(TLidList));
535
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if ( !lidList )
536 {
537 free(lidUnit);
538 return error_setInpError(ERR_MEMORY, "");
539 }
540 18 lidList->lidUnit = lidUnit;
541 18 lidList->nextLidUnit = lidGroup->lidList;
542 18 lidGroup->lidList = lidList;
543
544 //... assign parameter values to LID unit
545 18 lidUnit->lidIndex = k;
546 18 lidUnit->number = n;
547 18 lidUnit->area = x[0] / SQR(UCF(LENGTH));
548 18 lidUnit->fullWidth = x[1] / UCF(LENGTH);
549 18 lidUnit->initSat = x[2] / 100.0;
550 18 lidUnit->fromImperv = x[3] / 100.0;
551 18 lidUnit->toPerv = (x[4] > 0.0);
552 18 lidUnit->fromPerv = x[5] / 100.0;
553 18 lidUnit->drainSubcatch = drainSubcatch;
554 18 lidUnit->drainNode = drainNode;
555
556 //... open report file if it was supplied
557
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 15 times.
18 if ( fname != NULL )
558 {
559
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if ( !createLidRptFile(lidUnit, fname) )
560 return error_setInpError(ERR_RPT_FILE, fname);
561 }
562 18 return 0;
563 }
564
565 //=============================================================================
566
567 3 int createLidRptFile(TLidUnit* lidUnit, char* fname)
568 {
569 TLidRptFile* rptFile;
570
571 3 rptFile = (TLidRptFile *) malloc(sizeof(TLidRptFile));
572
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if ( rptFile == NULL ) return 0;
573 3 lidUnit->rptFile = rptFile;
574 3 rptFile->file = fopen(fname, "wt");
575
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if ( rptFile->file == NULL ) return 0;
576 3 return 1;
577 }
578
579 //=============================================================================
580
581 16 int readSurfaceData(int j, char* toks[], int ntoks)
582 //
583 // Purpose: reads surface layer data for a LID process from line of input
584 // data file
585 // Input: j = LID process index
586 // toks = array of string tokens
587 // ntoks = number of tokens
588 // Output: returns error code
589 //
590 // Format of data is:
591 // LID_ID SURFACE StorageHt VegVolFrac Roughness SurfSlope SideSlope
592 //
593 {
594 int i;
595 double x[5];
596
597
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if ( ntoks < 7 ) return error_setInpError(ERR_ITEMS, "");
598
2/2
✓ Branch 0 taken 80 times.
✓ Branch 1 taken 16 times.
96 for (i = 2; i < 7; i++)
599 {
600
2/4
✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 80 times.
80 if ( ! getDouble(toks[i], &x[i-2]) || x[i-2] < 0.0 )
601 return error_setInpError(ERR_NUMBER, toks[i]);
602 }
603
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if ( x[1] >= 1.0 ) return error_setInpError(ERR_NUMBER, toks[3]);
604
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if ( x[0] == 0.0 ) x[1] = 0.0;
605
606 16 LidProcs[j].surface.thickness = x[0] / UCF(RAINDEPTH);
607 16 LidProcs[j].surface.voidFrac = 1.0 - x[1];
608 16 LidProcs[j].surface.roughness = x[2];
609 16 LidProcs[j].surface.surfSlope = x[3] / 100.0;
610 16 LidProcs[j].surface.sideSlope = x[4];
611 16 return 0;
612 }
613
614 //=============================================================================
615
616 2 int readPavementData(int j, char* toks[], int ntoks)
617 //
618 // Purpose: reads pavement layer data for a LID process from line of input
619 // data file
620 // Input: j = LID process index
621 // toks = array of string tokens
622 // ntoks = number of tokens
623 // Output: returns error code
624 //
625 // Format of data is:
626 // LID_ID PAVEMENT Thickness VoidRatio FracImperv Permeability ClogFactor
627 // (RegenDays RegenDegree)
628 //
629 {
630 int i;
631 double x[7];
632
633
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if ( ntoks < 7 ) return error_setInpError(ERR_ITEMS, "");
634
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 2 times.
12 for (i = 2; i < 7; i++)
635 {
636
2/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
10 if ( ! getDouble(toks[i], &x[i-2]) || x[i-2] < 0.0 )
637 return error_setInpError(ERR_NUMBER, toks[i]);
638 }
639
640 // ... read optional clogging regeneration properties
641 2 x[5] = 0.0;
642
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 if (ntoks > 7)
643 {
644
2/4
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
1 if (!getDouble(toks[7], &x[5]) || x[5] < 0.0)
645 return error_setInpError(ERR_NUMBER, toks[7]);
646 }
647 2 x[6] = 0.0;
648
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 if (ntoks > 8)
649 {
650
3/6
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
1 if (!getDouble(toks[8], &x[6]) || x[6] < 0.0 || x[6] > 1.0)
651 return error_setInpError(ERR_NUMBER, toks[8]);
652 }
653
654 //... convert void ratio to void fraction
655 2 x[1] = x[1]/(x[1] + 1.0);
656
657 2 LidProcs[j].pavement.thickness = x[0] / UCF(RAINDEPTH);
658 2 LidProcs[j].pavement.voidFrac = x[1];
659 2 LidProcs[j].pavement.impervFrac = x[2];
660 2 LidProcs[j].pavement.kSat = x[3] / UCF(RAINFALL);
661 2 LidProcs[j].pavement.clogFactor = x[4];
662 2 LidProcs[j].pavement.regenDays = x[5];
663 2 LidProcs[j].pavement.regenDegree = x[6];
664 2 return 0;
665 }
666
667 //=============================================================================
668
669 8 int readSoilData(int j, char* toks[], int ntoks)
670 //
671 // Purpose: reads soil layer data for a LID process from line of input
672 // data file
673 // Input: j = LID process index
674 // toks = array of string tokens
675 // ntoks = number of tokens
676 // Output: returns error code
677 //
678 // Format of data is:
679 // LID_ID SOIL Thickness Porosity FieldCap WiltPt Ksat Kslope Suction
680 //
681 {
682 int i;
683 double x[7];
684
685
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if ( ntoks < 9 ) return error_setInpError(ERR_ITEMS, "");
686
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 8 times.
64 for (i = 2; i < 9; i++)
687 {
688
2/4
✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 56 times.
56 if ( ! getDouble(toks[i], &x[i-2]) || x[i-2] < 0.0 )
689 return error_setInpError(ERR_NUMBER, toks[i]);
690 }
691 8 LidProcs[j].soil.thickness = x[0] / UCF(RAINDEPTH);
692 8 LidProcs[j].soil.porosity = x[1];
693 8 LidProcs[j].soil.fieldCap = x[2];
694 8 LidProcs[j].soil.wiltPoint = x[3];
695 8 LidProcs[j].soil.kSat = x[4] / UCF(RAINFALL);
696 8 LidProcs[j].soil.kSlope = x[5];
697 8 LidProcs[j].soil.suction = x[6] / UCF(RAINDEPTH);
698 8 return 0;
699 }
700
701 //=============================================================================
702
703 12 int readStorageData(int j, char* toks[], int ntoks)
704 //
705 // Purpose: reads drainage layer data for a LID process from line of input
706 // data file
707 // Input: j = LID process index
708 // toks = array of string tokens
709 // ntoks = number of tokens
710 // Output: returns error code
711 //
712 // Format of data is:
713 // LID_ID STORAGE Thickness VoidRatio Ksat ClogFactor (YES/NO)
714 //
715 {
716 int i;
717 12 int covered = FALSE;
718 double x[6];
719
720 //... read numerical parameters
721
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if ( ntoks < 6 ) return error_setInpError(ERR_ITEMS, "");
722
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 12 times.
60 for (i = 2; i < 6; i++)
723 {
724
2/4
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 48 times.
48 if ( ! getDouble(toks[i], &x[i-2]) || x[i-2] < 0.0 )
725 return error_setInpError(ERR_NUMBER, toks[i]);
726 }
727
728 //... check if rain barrel is covered
729
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (ntoks > 6)
730 {
731 if (match(toks[6], w_YES))
732 covered = TRUE;
733 }
734
735 //... convert void ratio to void fraction
736 12 x[1] = x[1]/(x[1] + 1.0);
737
738 //... save parameters to LID storage layer structure
739 12 LidProcs[j].storage.thickness = x[0] / UCF(RAINDEPTH);
740 12 LidProcs[j].storage.voidFrac = x[1];
741 12 LidProcs[j].storage.kSat = x[2] / UCF(RAINFALL);
742 12 LidProcs[j].storage.clogFactor = x[3];
743 12 LidProcs[j].storage.covered = covered;
744 12 return 0;
745 }
746
747 //=============================================================================
748
749 12 int readDrainData(int j, char* toks[], int ntoks)
750 //
751 // Purpose: reads underdrain data for a LID process from line of input
752 // data file
753 // Input: j = LID process index
754 // toks = array of string tokens
755 // ntoks = number of tokens
756 // Output: returns error code
757 //
758 // Format of data is:
759 // LID_ID DRAIN coeff expon offset delay hOpen hClose curve
760 //
761 {
762 int i;
763 double x[6];
764
765 //... read numerical parameters
766
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if ( ntoks < 6 ) return error_setInpError(ERR_ITEMS, "");
767
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 12 times.
84 for (i = 0; i < 6; i++) x[i] = 0.0;
768
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 12 times.
84 for (i = 2; i < 8; i++)
769 {
770
4/6
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 6 times.
✓ Branch 3 taken 66 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 66 times.
72 if ( (ntoks > i) && (! getDouble(toks[i], &x[i-2]) || x[i-2] < 0.0) )
771 return error_setInpError(ERR_NUMBER, toks[i]);
772 }
773
774 12 i = -1;
775
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if ( ntoks >= 9 )
776 {
777 i = project_findObject(CURVE, toks[8]);
778 if (i < 0) return error_setInpError(ERR_NAME, toks[8]);
779 }
780
781 //... save parameters to LID drain layer structure
782 12 LidProcs[j].drain.coeff = x[0];
783 12 LidProcs[j].drain.expon = x[1];
784 12 LidProcs[j].drain.offset = x[2] / UCF(RAINDEPTH);
785 12 LidProcs[j].drain.delay = x[3] * 3600.0;
786 12 LidProcs[j].drain.hOpen = x[4] / UCF(RAINDEPTH);
787 12 LidProcs[j].drain.hClose = x[5] / UCF(RAINDEPTH);
788 12 LidProcs[j].drain.qCurve = i;
789 12 return 0;
790 }
791
792 //=============================================================================
793
794 2 int readDrainMatData(int j, char* toks[], int ntoks)
795 //
796 // Purpose: reads drainage mat data for a LID process from line of input
797 // data file
798 // Input: j = LID process index
799 // toks = array of string tokens
800 // ntoks = number of tokens
801 // Output: returns error code
802 //
803 // Format of data is:
804 // LID_ID DRAINMAT thickness voidRatio roughness
805 //
806 {
807 int i;
808 double x[3];
809
810 //... read numerical parameters
811
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if ( ntoks < 5 ) return error_setInpError(ERR_ITEMS, "");
812
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if ( LidProcs[j].lidType != GREEN_ROOF ) return 0;
813
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 for (i = 2; i < 5; i++)
814 {
815
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
6 if ( ! getDouble(toks[i], &x[i-2]) || x[i-2] < 0.0 )
816 return error_setInpError(ERR_NUMBER, toks[i]);
817 }
818
819 //... save parameters to LID drain layer structure
820 2 LidProcs[j].drainMat.thickness = x[0] / UCF(RAINDEPTH);;
821 2 LidProcs[j].drainMat.voidFrac = x[1];
822 2 LidProcs[j].drainMat.roughness = x[2];
823 2 return 0;
824 }
825
826 //=============================================================================
827
828 1 int readRemovalsData(int j, char* toks[], int ntoks)
829 //
830 // Purpose: reads pollutant removal data for a LID process from line of input
831 // data file
832 // Input: j = LID process index
833 // toks = array of string tokens
834 // ntoks = number of tokens
835 // Output: returns error code
836 //
837 // Format of data is:
838 // LID_ID REMOVALS pollut1 %removal1 pollut2 %removal2 ...
839 //
840 {
841 1 int i = 2;
842 int p;
843 double rmvl;
844
845 //... start with 3rd token
846
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (ntoks < 4) return error_setInpError(ERR_ITEMS, "");
847
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 while (ntoks > i)
848 {
849 //... find pollutant index from its name
850 1 p = project_findObject(POLLUT, toks[i]);
851
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (p < 0) return error_setInpError(ERR_NAME, toks[i]);
852
853 //... check that a next token exists
854 1 i++;
855
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (ntoks == i) return error_setInpError(ERR_ITEMS, "");
856
857 //... get the % removal value from the next token
858
3/6
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
1 if (!getDouble(toks[i], &rmvl) || rmvl < 0.0 || rmvl > 100.0)
859 return error_setInpError(ERR_NUMBER, toks[i]);
860
861 //... save the pollutant removal for the LID process as a fraction
862 1 LidProcs[j].drainRmvl[p] = rmvl / 100.0;
863 1 i++;
864 }
865 1 return 0;
866 }
867 //=============================================================================
868
869 11 void lid_writeSummary()
870 //
871 // Purpose: writes summary of LID processes used to report file.
872 // Input: none
873 // Output: none
874 //
875 {
876 int j, k;
877 double pctArea;
878 TLidUnit* lidUnit;
879 TLidList* lidList;
880 TLidGroup lidGroup;
881
882 11 fprintf(Frpt.file, "\n");
883 11 fprintf(Frpt.file, "\n");
884 11 fprintf(Frpt.file, "\n *******************");
885 11 fprintf(Frpt.file, "\n LID Control Summary");
886 11 fprintf(Frpt.file, "\n *******************");
887
888
889 11 fprintf(Frpt.file,
890 "\n No. of Unit Unit %% Area %% Imperv %% Perv"); //(5.1.013)
891 11 fprintf(Frpt.file, //
892 "\n Subcatchment LID Control Units Area Width Covered Treated Treated"); //
893 11 fprintf(Frpt.file, //
894 "\n ---------------------------------------------------------------------------------------------------"); //
895
896
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 11 times.
47 for (j = 0; j < GroupCount; j++)
897 {
898 36 lidGroup = LidGroups[j];
899
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 11 times.
36 if ( lidGroup == NULL ) continue;
900 11 lidList = lidGroup->lidList;
901
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 11 times.
29 while ( lidList )
902 {
903 18 lidUnit = lidList->lidUnit;
904 18 k = lidUnit->lidIndex;
905 18 pctArea = lidUnit->area * lidUnit->number / Subcatch[j].area * 100.0;
906 18 fprintf(Frpt.file, "\n %-16s %-16s", Subcatch[j].ID, LidProcs[k].ID);
907 54 fprintf(Frpt.file, "%6d %10.2f %10.2f %10.2f %10.2f %10.2f",
908 18 lidUnit->number, lidUnit->area * SQR(UCF(LENGTH)),
909 18 lidUnit->fullWidth * UCF(LENGTH), pctArea,
910 18 lidUnit->fromImperv*100.0, lidUnit->fromPerv*100.0);
911 18 lidList = lidList->nextLidUnit;
912 }
913 }
914 11 }
915
916 //=============================================================================
917
918 58 void lid_validate()
919 //
920 // Purpose: validates LID process and group parameters.
921 // Input: none
922 // Output: none
923 //
924 {
925 int j;
926
2/2
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 58 times.
78 for (j = 0; j < LidCount; j++) validateLidProc(j);
927
2/2
✓ Branch 1 taken 2393 times.
✓ Branch 2 taken 58 times.
2451 for (j = 0; j < GroupCount; j++) validateLidGroup(j);
928 58 }
929
930 //=============================================================================
931
932 20 void validateLidProc(int j)
933 //
934 // Purpose: validates LID process parameters.
935 // Input: j = LID process index
936 // Output: none
937 //
938 {
939 20 int layerMissing = FALSE;
940
941 //... check that LID type was supplied
942
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if ( LidProcs[j].lidType < 0 )
943 {
944 report_writeErrorMsg(ERR_LID_TYPE, LidProcs[j].ID);
945 return;
946 }
947
948 //... check that required layers were defined
949
5/5
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 10 times.
20 switch (LidProcs[j].lidType)
950 {
951 4 case BIO_CELL:
952 case RAIN_GARDEN:
953
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if ( LidProcs[j].soil.thickness <= 0.0 ) layerMissing = TRUE;
954 4 break;
955 2 case GREEN_ROOF:
956
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if ( LidProcs[j].soil.thickness <= 0.0 ) layerMissing = TRUE;
957
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if ( LidProcs[j].drainMat.thickness <= 0.0) layerMissing = TRUE;
958 2 break;
959 2 case POROUS_PAVEMENT:
960
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if ( LidProcs[j].pavement.thickness <= 0.0 ) layerMissing = TRUE;
961 2 break;
962 2 case INFIL_TRENCH:
963
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if ( LidProcs[j].storage.thickness <= 0.0 ) layerMissing = TRUE;
964 2 break;
965 }
966
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if ( layerMissing )
967 {
968 report_writeErrorMsg(ERR_LID_LAYER, LidProcs[j].ID);
969 return;
970 }
971
972 //... check pavement layer parameters
973
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 18 times.
20 if ( LidProcs[j].lidType == POROUS_PAVEMENT )
974 {
975
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if ( LidProcs[j].pavement.thickness <= 0.0
976
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 || LidProcs[j].pavement.kSat <= 0.0
977
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 || LidProcs[j].pavement.voidFrac <= 0.0
978
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 || LidProcs[j].pavement.voidFrac > 1.0
979
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 || LidProcs[j].pavement.impervFrac > 1.0 )
980
981 {
982 sstrncpy(Msg, LidProcs[j].ID, MAXMSG);
983 sstrcat(Msg, ERR_PAVE_LAYER, MAXMSG);
984 report_writeErrorMsg(ERR_LID_PARAMS, Msg);
985 }
986 }
987
988 //... check soil layer parameters
989
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 12 times.
20 if ( LidProcs[j].soil.thickness > 0.0 )
990 {
991
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if ( LidProcs[j].soil.porosity <= 0.0
992
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 || LidProcs[j].soil.fieldCap >= LidProcs[j].soil.porosity
993
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 || LidProcs[j].soil.wiltPoint >= LidProcs[j].soil.fieldCap
994
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 || LidProcs[j].soil.kSat <= 0.0
995
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 || LidProcs[j].soil.kSlope < 0.0 )
996 {
997 sstrncpy(Msg, LidProcs[j].ID, MAXMSG);
998 sstrcat(Msg, ERR_SOIL_LAYER, MAXMSG);
999 report_writeErrorMsg(ERR_LID_PARAMS, Msg);
1000 }
1001 }
1002
1003 //... check storage layer parameters
1004
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 if ( LidProcs[j].storage.thickness > 0.0 )
1005 {
1006
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if ( LidProcs[j].storage.voidFrac <= 0.0 ||
1007
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 LidProcs[j].storage.voidFrac > 1.0 )
1008 {
1009 sstrncpy(Msg, LidProcs[j].ID, MAXMSG);
1010 sstrcat(Msg, ERR_STOR_LAYER, MAXMSG);
1011 report_writeErrorMsg(ERR_LID_PARAMS, Msg);
1012 }
1013 }
1014
1015 //... if no storage layer adjust void fraction and drain offset
1016 else
1017 {
1018 10 LidProcs[j].storage.voidFrac = 1.0;
1019 10 LidProcs[j].drain.offset = 0.0;
1020 }
1021
1022 //... check for invalid drain open/closed heads
1023
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (LidProcs[j].drain.hOpen > 0.0 &&
1024 LidProcs[j].drain.hOpen <= LidProcs[j].drain.hClose)
1025 {
1026 sstrncpy(Msg, LidProcs[j].ID, MAXMSG);
1027 sstrcat(Msg, ERR_DRAIN_HEADS, MAXMSG);
1028 report_writeErrorMsg(ERR_LID_PARAMS, Msg);
1029 }
1030
1031 //... compute the surface layer's overland flow constant (alpha)
1032
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 16 times.
20 if ( LidProcs[j].lidType == VEG_SWALE )
1033 {
1034 4 if ( LidProcs[j].surface.roughness *
1035
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 LidProcs[j].surface.surfSlope <= 0.0 ||
1036
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 LidProcs[j].surface.thickness == 0.0
1037 )
1038 {
1039 sstrncpy(Msg, LidProcs[j].ID, MAXMSG);
1040 sstrcat(Msg, ERR_SWALE_SURF, MAXMSG);
1041 report_writeErrorMsg(ERR_LID_PARAMS, Msg);
1042 }
1043 4 else LidProcs[j].surface.alpha =
1044 4 1.49 * sqrt(LidProcs[j].surface.surfSlope) /
1045 4 LidProcs[j].surface.roughness;
1046 }
1047 else
1048 {
1049 //... compute surface overland flow coeff.
1050
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 5 times.
16 if ( LidProcs[j].surface.roughness > 0.0 )
1051 11 LidProcs[j].surface.alpha = 1.49 / LidProcs[j].surface.roughness *
1052 11 sqrt(LidProcs[j].surface.surfSlope);
1053 5 else LidProcs[j].surface.alpha = 0.0;
1054 }
1055
1056 //... compute drainage mat layer's flow coeff.
1057
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 18 times.
20 if ( LidProcs[j].drainMat.roughness > 0.0 )
1058 {
1059 2 LidProcs[j].drainMat.alpha = 1.49 / LidProcs[j].drainMat.roughness *
1060 2 sqrt(LidProcs[j].surface.surfSlope);
1061 }
1062 18 else LidProcs[j].drainMat.alpha = 0.0;
1063
1064
1065 //... convert clogging factors to void volume basis
1066
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 18 times.
20 if ( LidProcs[j].pavement.thickness > 0.0 )
1067 {
1068 2 LidProcs[j].pavement.clogFactor *=
1069 2 LidProcs[j].pavement.thickness * LidProcs[j].pavement.voidFrac *
1070 2 (1.0 - LidProcs[j].pavement.impervFrac);
1071 }
1072
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 if ( LidProcs[j].storage.thickness > 0.0 )
1073 {
1074 10 LidProcs[j].storage.clogFactor *=
1075 10 LidProcs[j].storage.thickness * LidProcs[j].storage.voidFrac;
1076 }
1077 10 else LidProcs[j].storage.clogFactor = 0.0;
1078
1079 //... for certain LID types, immediate overflow of excess surface water
1080 // occurs if either the surface roughness or slope is zero
1081 20 LidProcs[j].surface.canOverflow = TRUE;
1082
3/3
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 8 times.
20 switch (LidProcs[j].lidType)
1083 {
1084 2 case ROOF_DISCON: LidProcs[j].surface.canOverflow = FALSE; break;
1085 10 case INFIL_TRENCH:
1086 case POROUS_PAVEMENT:
1087 case BIO_CELL:
1088 case RAIN_GARDEN:
1089 case GREEN_ROOF:
1090
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if ( LidProcs[j].surface.alpha > 0.0 )
1091 10 LidProcs[j].surface.canOverflow = FALSE;
1092 }
1093
1094 //... rain barrels have 100% void space and impermeable bottom
1095
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 16 times.
20 if ( LidProcs[j].lidType == RAIN_BARREL )
1096 {
1097 4 LidProcs[j].storage.voidFrac = 1.0;
1098 4 LidProcs[j].storage.kSat = 0.0;
1099 }
1100
1101 //... set storage layer parameters of a green roof
1102
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 18 times.
20 if ( LidProcs[j].lidType == GREEN_ROOF )
1103 {
1104 2 LidProcs[j].storage.thickness = LidProcs[j].drainMat.thickness;
1105 2 LidProcs[j].storage.voidFrac = LidProcs[j].drainMat.voidFrac;
1106 2 LidProcs[j].storage.clogFactor = 0.0;
1107 2 LidProcs[j].storage.kSat = 0.0;
1108 }
1109 }
1110
1111 //=============================================================================
1112
1113 2393 void validateLidGroup(int j)
1114 //
1115 // Purpose: validates properties of LID units grouped in a subcatchment.
1116 // Input: j = subcatchment index
1117 // Output: returns 1 if data are valid, 0 if not
1118 //
1119 {
1120 int k;
1121 double p[3];
1122 2393 double totalArea = Subcatch[j].area;
1123 2393 double totalLidArea = 0.0;
1124 2393 double fromImperv = 0.0;
1125 2393 double fromPerv = 0.0;
1126 TLidUnit* lidUnit;
1127 TLidList* lidList;
1128 TLidGroup lidGroup;
1129
1130 2393 lidGroup = LidGroups[j];
1131
2/2
✓ Branch 0 taken 2382 times.
✓ Branch 1 taken 11 times.
2393 if ( lidGroup == NULL ) return;
1132 11 lidList = lidGroup->lidList;
1133
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 11 times.
29 while ( lidList )
1134 {
1135 18 lidUnit = lidList->lidUnit;
1136 18 k = lidUnit->lidIndex;
1137
1138 //... update contributing fractions
1139 18 totalLidArea += (lidUnit->area * lidUnit->number);
1140 18 fromImperv += lidUnit->fromImperv;
1141 18 fromPerv += lidUnit->fromPerv;
1142
1143 //... assign biocell soil layer infiltration parameters
1144 18 lidUnit->soilInfil.Ks = 0.0;
1145
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 10 times.
18 if ( LidProcs[k].soil.thickness > 0.0 )
1146 {
1147 8 p[0] = LidProcs[k].soil.suction * UCF(RAINDEPTH);
1148 8 p[1] = LidProcs[k].soil.kSat * UCF(RAINFALL);
1149 8 p[2] = (LidProcs[k].soil.porosity - LidProcs[k].soil.wiltPoint) *
1150 8 (1.0 - lidUnit->initSat);
1151
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
8 if ( grnampt_setParams(&(lidUnit->soilInfil), p) == FALSE )
1152 {
1153 sstrncpy(Msg, LidProcs[k].ID, MAXMSG);
1154 sstrcat(Msg, ERR_SOIL_LAYER, MAXMSG);
1155 report_writeErrorMsg(ERR_LID_PARAMS, Msg);
1156 }
1157 }
1158
1159 //... assign vegetative swale infiltration parameters
1160
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 16 times.
18 if ( LidProcs[k].lidType == VEG_SWALE )
1161 {
1162
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if ( Subcatch[j].infilModel == GREEN_AMPT ||
1163
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 Subcatch[j].infilModel == MOD_GREEN_AMPT )
1164 {
1165 grnampt_getParams(j, p);
1166 if ( grnampt_setParams(&(lidUnit->soilInfil), p) == FALSE )
1167 {
1168 sstrncpy(Msg, LidProcs[k].ID, MAXMSG);
1169 sstrcat(Msg, ERR_GREEN_AMPT, MAXMSG);
1170 report_writeErrorMsg(ERR_LID_PARAMS, Msg);
1171 }
1172 }
1173
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if ( lidUnit->fullWidth <= 0.0 )
1174 {
1175 sstrncpy(Msg, LidProcs[k].ID, MAXMSG);
1176 sstrcat(Msg, ERR_SWALE_WIDTH, MAXMSG);
1177 report_writeErrorMsg(ERR_LID_PARAMS, Msg);
1178 }
1179 }
1180
1181 //... LID unit cannot send outflow back to subcatchment's
1182 // pervious area if none exists
1183
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 16 times.
18 if ( Subcatch[j].fracImperv >= 0.999 ) lidUnit->toPerv = 0;
1184
1185 //... assign drain outlet if not set by user
1186
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
18 if ( lidUnit->drainNode == -1 && lidUnit->drainSubcatch == -1 )
1187 {
1188 17 lidUnit->drainNode = Subcatch[j].outNode;
1189 17 lidUnit->drainSubcatch = Subcatch[j].outSubcatch;
1190 }
1191 18 lidList = lidList->nextLidUnit;
1192 }
1193
1194 //... check contributing area fractions
1195
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if ( totalLidArea > 1.001 * totalArea )
1196 {
1197 report_writeErrorMsg(ERR_LID_AREAS, Subcatch[j].ID);
1198 }
1199
2/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
11 if ( fromImperv > 1.001 || fromPerv > 1.001 )
1200 {
1201 report_writeErrorMsg(ERR_LID_CAPTURE_AREA, Subcatch[j].ID);
1202 }
1203
1204 //... Make subcatchment LID area equal total area if the two are close
1205
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 9 times.
11 if ( totalLidArea > 0.999 * totalArea ) totalLidArea = totalArea;
1206 11 Subcatch[j].lidArea = totalLidArea;
1207 }
1208
1209 //=============================================================================
1210
1211 58 void lid_initState()
1212 //
1213 // Purpose: initializes the internal state of each LID in a subcatchment.
1214 // Input: none
1215 // Output: none
1216 //
1217 {
1218 int i, j, k;
1219 TLidUnit* lidUnit;
1220 TLidList* lidList;
1221 TLidGroup lidGroup;
1222 double initVol;
1223 58 double initDryTime = StartDryDays * SECperDAY;
1224
1225 58 HasWetLids = FALSE;
1226
2/2
✓ Branch 0 taken 2393 times.
✓ Branch 1 taken 58 times.
2451 for (j = 0; j < GroupCount; j++)
1227 {
1228 //... check if group exists
1229 2393 lidGroup = LidGroups[j];
1230
2/2
✓ Branch 0 taken 2382 times.
✓ Branch 1 taken 11 times.
2393 if ( lidGroup == NULL ) continue;
1231
1232 //... initialize group variables
1233 11 lidGroup->pervArea = 0.0;
1234 11 lidGroup->flowToPerv = 0.0;
1235 11 lidGroup->oldDrainFlow = 0.0;
1236 11 lidGroup->newDrainFlow = 0.0;
1237
1238 //... examine each LID in the group
1239 11 lidList = lidGroup->lidList;
1240
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 11 times.
29 while ( lidList )
1241 {
1242 //... initialize depth & moisture content
1243 18 lidUnit = lidList->lidUnit;
1244 18 k = lidUnit->lidIndex;
1245 18 lidUnit->surfaceDepth = 0.0;
1246 18 lidUnit->storageDepth = 0.0;
1247 18 lidUnit->soilMoisture = 0.0;
1248 18 lidUnit->paveDepth = 0.0;
1249 18 lidUnit->dryTime = initDryTime;
1250 18 lidUnit->volTreated = 0.0;
1251 18 lidUnit->nextRegenDay = LidProcs[k].pavement.regenDays;
1252 18 initVol = 0.0;
1253
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 10 times.
18 if ( LidProcs[k].soil.thickness > 0.0 )
1254 {
1255 8 lidUnit->soilMoisture = LidProcs[k].soil.wiltPoint +
1256 8 lidUnit->initSat * (LidProcs[k].soil.porosity -
1257 8 LidProcs[k].soil.wiltPoint);
1258 8 initVol += lidUnit->soilMoisture * LidProcs[k].soil.thickness;
1259 }
1260
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
18 if ( LidProcs[k].storage.thickness > 0.0 )
1261 {
1262 12 lidUnit->storageDepth = lidUnit->initSat *
1263 12 LidProcs[k].storage.thickness;
1264 12 initVol += lidUnit->storageDepth * LidProcs[k].storage.voidFrac;
1265 }
1266
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if ( lidUnit->initSat > 0.0 ) HasWetLids = TRUE;
1267
1268 //... initialize water balance totals
1269 18 lidproc_initWaterBalance(lidUnit, initVol);
1270 18 lidUnit->volTreated = 0.0;
1271
1272 //... initialize report file for the LID
1273
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 15 times.
18 if ( lidUnit->rptFile )
1274 {
1275 3 initLidRptFile(Title[0], LidProcs[k].ID, Subcatch[j].ID, lidUnit);
1276 }
1277
1278 //... initialize drain flows
1279 18 lidUnit->oldDrainFlow = 0.0;
1280 18 lidUnit->newDrainFlow = 0.0;
1281
1282 //... set previous flux rates to 0
1283
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 18 times.
90 for (i = 0; i < MAX_LAYERS; i++)
1284 {
1285 72 lidUnit->oldFluxRates[i] = 0.0;
1286 }
1287
1288 //... initialize infiltration state variables
1289
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 10 times.
18 if ( lidUnit->soilInfil.Ks > 0.0 )
1290 8 grnampt_initState(&(lidUnit->soilInfil));
1291
1292 //... add contribution to pervious LID area
1293
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 6 times.
18 if ( isLidPervious(lidUnit->lidIndex) )
1294 12 lidGroup->pervArea += (lidUnit->area * lidUnit->number);
1295 18 lidList = lidList->nextLidUnit;
1296 }
1297 }
1298 58 }
1299
1300 //=============================================================================
1301
1302 3309970 void lid_setOldGroupState(int j)
1303 //
1304 // Purpose: saves the current drain flow rate for the LIDs in a subcatchment.
1305 // Input: j = subcatchment index
1306 // Output: none
1307 //
1308 {
1309 TLidList* lidList;
1310
2/2
✓ Branch 0 taken 4443 times.
✓ Branch 1 taken 3305527 times.
3309970 if ( LidGroups[j] != NULL )
1311 {
1312 4443 LidGroups[j]->oldDrainFlow = LidGroups[j]->newDrainFlow;
1313 4443 LidGroups[j]->newDrainFlow = 0.0;
1314 4443 lidList = LidGroups[j]->lidList;
1315
2/2
✓ Branch 0 taken 8475 times.
✓ Branch 1 taken 4443 times.
12918 while (lidList)
1316 {
1317 8475 lidList->lidUnit->oldDrainFlow = lidList->lidUnit->newDrainFlow;
1318 8475 lidList->lidUnit->newDrainFlow = 0.0;
1319 8475 lidList = lidList->nextLidUnit;
1320 }
1321 }
1322 3309970 }
1323
1324 //=============================================================================
1325
1326 8493 int isLidPervious(int k)
1327 //
1328 // Purpose: determines if a LID process allows infiltration or not.
1329 // Input: k = LID process index
1330 // Output: returns 1 if process is pervious or 0 if not
1331 //
1332 {
1333
2/2
✓ Branch 0 taken 5535 times.
✓ Branch 1 taken 2958 times.
14028 return ( LidProcs[k].storage.thickness == 0.0 ||
1334
2/2
✓ Branch 0 taken 3078 times.
✓ Branch 1 taken 2457 times.
5535 LidProcs[k].storage.kSat > 0.0 );
1335 }
1336
1337 //=============================================================================
1338
1339 795 double getSurfaceDepth(int j)
1340 //
1341 // Purpose: computes the depth (volume per unit area) of ponded water on the
1342 // surface of all LIDs within a subcatchment.
1343 // Input: j = subcatchment index
1344 // Output: returns volumetric depth of ponded water (ft)
1345 //
1346 {
1347 int k;
1348 795 double depth = 0.0;
1349 TLidUnit* lidUnit;
1350 TLidList* lidList;
1351 TLidGroup lidGroup;
1352
1353 795 lidGroup = LidGroups[j];
1354
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 795 times.
795 if ( lidGroup == NULL ) return 0.0;
1355
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 795 times.
795 if ( Subcatch[j].lidArea == 0.0 ) return 0.0;
1356 795 lidList = lidGroup->lidList;
1357
2/2
✓ Branch 0 taken 795 times.
✓ Branch 1 taken 795 times.
1590 while ( lidList )
1358 {
1359 795 lidUnit = lidList->lidUnit;
1360 795 k = lidUnit->lidIndex;
1361 795 depth += lidUnit->surfaceDepth * LidProcs[k].surface.voidFrac *
1362 795 lidUnit->area * lidUnit->number;
1363 795 lidList = lidList->nextLidUnit;
1364 }
1365 795 return depth / Subcatch[j].lidArea;
1366 }
1367
1368 //=============================================================================
1369
1370 double lid_getPervArea(int j)
1371 //
1372 // Purpose: retrieves amount of pervious LID area in a subcatchment.
1373 // Input: j = subcatchment index
1374 // Output: returns amount of pervious LID area (ft2)
1375 //
1376 {
1377 if ( LidGroups[j] ) return LidGroups[j]->pervArea;
1378 else return 0.0;
1379 }
1380
1381 //=============================================================================
1382
1383 3795 double lid_getFlowToPerv(int j)
1384 //
1385 // Purpose: retrieves flow returned from LID treatment to pervious area of
1386 // a subcatchment.
1387 // Input: j = subcatchment index
1388 // Output: returns flow returned to pervious area (cfs)
1389 //
1390 {
1391
1/2
✓ Branch 0 taken 3795 times.
✗ Branch 1 not taken.
3795 if ( LidGroups[j] != NULL ) return LidGroups[j]->flowToPerv;
1392 return 0.0;
1393 }
1394
1395 //=============================================================================
1396
1397 4786 double lid_getStoredVolume(int j)
1398 //
1399 // Purpose: computes stored volume of water for all LIDs
1400 // grouped within a subcatchment.
1401 // Input: j = subcatchment index
1402 // Output: returns stored volume of water (ft3)
1403 //
1404 {
1405 4786 double total = 0.0;
1406 TLidUnit* lidUnit;
1407 TLidList* lidList;
1408 TLidGroup lidGroup;
1409
1410 4786 lidGroup = LidGroups[j];
1411
3/4
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 4764 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
4786 if ( lidGroup == NULL || Subcatch[j].lidArea == 0.0 ) return 0.0;
1412 22 lidList = lidGroup->lidList;
1413
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 22 times.
58 while ( lidList )
1414 {
1415 36 lidUnit = lidList->lidUnit;
1416 36 total += lidUnit->waterBalance.finalVol * lidUnit->area * lidUnit->number;
1417 36 lidList = lidList->nextLidUnit;
1418 }
1419 22 return total;
1420 }
1421
1422 //=============================================================================
1423
1424 5808 double lid_getDrainFlow(int j, int timePeriod)
1425 //
1426 // Purpose: returns flow from all of a subcatchment's LID drains for
1427 // a designated time period
1428 // Input: j = subcatchment index
1429 // timePeriod = either PREVIOUS or CURRENT
1430 // Output: total drain flow (cfs) from the subcatchment.
1431 {
1432
1/2
✓ Branch 0 taken 5808 times.
✗ Branch 1 not taken.
5808 if ( LidGroups[j] != NULL )
1433 {
1434
2/2
✓ Branch 0 taken 2904 times.
✓ Branch 1 taken 2904 times.
5808 if ( timePeriod == PREVIOUS ) return LidGroups[j]->oldDrainFlow;
1435 2904 else return LidGroups[j]->newDrainFlow;
1436 }
1437 return 0.0;
1438 }
1439
1440 //=============================================================================
1441
1442 576 void lid_addDrainLoads(int j, double c[], double tStep)
1443 //
1444 // Purpose: adds pollutant loads routed from drains to system
1445 // mass balance totals.
1446 // Input: j = subcatchment index
1447 // c = array of pollutant washoff concentrations (mass/L)
1448 // tStep = time step (sec)
1449 // Output: none.
1450 //
1451 {
1452 int isRunoffLoad; // true if drain becomes external runoff load
1453 int p; // pollutant index
1454 double r; // pollutant fractional removal
1455 double w; // pollutant mass load (lb or kg)
1456 TLidUnit* lidUnit;
1457 TLidList* lidList;
1458 TLidGroup lidGroup;
1459
1460 //... check if LID group exists
1461 576 lidGroup = LidGroups[j];
1462
1/2
✓ Branch 0 taken 576 times.
✗ Branch 1 not taken.
576 if ( lidGroup != NULL )
1463 {
1464 //... examine each LID unit in the group
1465 576 lidList = lidGroup->lidList;
1466
2/2
✓ Branch 0 taken 4608 times.
✓ Branch 1 taken 576 times.
5184 while ( lidList )
1467 {
1468 4608 lidUnit = lidList->lidUnit;
1469
1470 //... see if unit's drain flow becomes external runoff
1471
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4608 times.
4608 isRunoffLoad = (lidUnit->drainNode >= 0 ||
1472 lidUnit->drainSubcatch == j);
1473
1474 //... for each pollutant not routed back on to subcatchment surface
1475
4/4
✓ Branch 0 taken 576 times.
✓ Branch 1 taken 4032 times.
✓ Branch 2 taken 576 times.
✓ Branch 3 taken 576 times.
5184 if (!lidUnit->toPerv) for (p = 0; p < Nobjects[POLLUT]; p++)
1476 {
1477 //... get mass load flowing through the drain
1478 576 w = lidUnit->newDrainFlow * c[p] * tStep * LperFT3 * Pollut[p].mcf;
1479
1480 //... get fractional removal for this load
1481 576 r = LidProcs[lidUnit->lidIndex].drainRmvl[p];
1482
1483 //... update system mass balance totals
1484 576 massbal_updateLoadingTotals(BMP_REMOVAL_LOAD, p, r*w);
1485
1/2
✓ Branch 0 taken 576 times.
✗ Branch 1 not taken.
576 if (isRunoffLoad)
1486 576 massbal_updateLoadingTotals(RUNOFF_LOAD, p, w*(1.0 - r));
1487 }
1488
1489 // process next LID unit in the group
1490 4608 lidList = lidList->nextLidUnit;
1491 }
1492 }
1493 576 }
1494
1495 //=============================================================================
1496
1497 4443 void lid_addDrainRunon(int j)
1498 //
1499 // Purpose: adds drain flows from LIDs in a given subcatchment to the
1500 // subcatchments that were designated to receive them
1501 // Input: j = index of subcatchment contributing underdrain flows
1502 // Output: none.
1503 //
1504 {
1505 int i; // index of an LID unit's LID process
1506 int k; // index of subcatchment receiving LID drain flow
1507 int p; // pollutant index
1508 double q; // drain flow rate (cfs)
1509 double w; // mass of polllutant from drain flow
1510 TLidUnit* lidUnit;
1511 TLidList* lidList;
1512 TLidGroup lidGroup;
1513
1514 //... check if LID group exists
1515 4443 lidGroup = LidGroups[j];
1516
1/2
✓ Branch 0 taken 4443 times.
✗ Branch 1 not taken.
4443 if ( lidGroup != NULL )
1517 {
1518 //... examine each LID in the group
1519 4443 lidList = lidGroup->lidList;
1520
2/2
✓ Branch 0 taken 8475 times.
✓ Branch 1 taken 4443 times.
12918 while ( lidList )
1521 {
1522 //... see if LID's drain discharges to another subcatchment
1523 8475 lidUnit = lidList->lidUnit;
1524 8475 i = lidUnit->lidIndex;
1525 8475 k = lidUnit->drainSubcatch;
1526
3/4
✓ Branch 0 taken 147 times.
✓ Branch 1 taken 8328 times.
✓ Branch 2 taken 147 times.
✗ Branch 3 not taken.
8475 if ( k >= 0 && k != j )
1527 {
1528 //... distribute drain flow across subcatchment's areas
1529 147 q = lidUnit->oldDrainFlow;
1530 147 subcatch_addRunonFlow(k, q);
1531
1532 //... add pollutant loads from drain to subcatchment
1533 // (newQual[] contains loading rate (mass/sec) at this
1534 // point which is converted later on to a concentration)
1535
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 147 times.
147 for (p = 0; p < Nobjects[POLLUT]; p++)
1536 {
1537 w = q * Subcatch[j].oldQual[p] * LperFT3;
1538 w = w * (1.0 - LidProcs[i].drainRmvl[p]);
1539 Subcatch[k].newQual[p] += w;
1540 }
1541 }
1542 8475 lidList = lidList->nextLidUnit;
1543 }
1544 }
1545 4443 }
1546
1547 //=============================================================================
1548
1549 48241 void lid_addDrainInflow(int j, double f)
1550 //
1551 // Purpose: adds LID drain flow to conveyance system nodes
1552 // Input: j = subcatchment index
1553 // f = time interval weighting factor
1554 // Output: none.
1555 //
1556 // Note: this function updates the total lateral flow (Node[].newLatFlow)
1557 // and pollutant mass (Node[].newQual[]) inflow seen by nodes that
1558 // receive drain flow from the LID units in subcatchment j.
1559 {
1560 int i, // LID process index
1561 k, // node index
1562 p; // pollutant index
1563 double q, // drain flow (cfs)
1564 w, w1, w2; // pollutant mass loads (mass/sec)
1565 TLidUnit* lidUnit;
1566 TLidList* lidList;
1567 TLidGroup lidGroup;
1568
1569 //... check if LID group exists
1570 48241 lidGroup = LidGroups[j];
1571
1/2
✓ Branch 0 taken 48241 times.
✗ Branch 1 not taken.
48241 if ( lidGroup != NULL )
1572 {
1573 //... examine each LID in the group
1574 48241 lidList = lidGroup->lidList;
1575
2/2
✓ Branch 0 taken 88561 times.
✓ Branch 1 taken 48241 times.
136802 while ( lidList )
1576 {
1577 //... see if LID's drain discharges to conveyance system node
1578 88561 lidUnit = lidList->lidUnit;
1579 88561 i = lidUnit->lidIndex;
1580 88561 k = lidUnit->drainNode;
1581
2/2
✓ Branch 0 taken 87121 times.
✓ Branch 1 taken 1440 times.
88561 if ( k >= 0 )
1582 {
1583 //... add drain flow to node's wet weather inflow
1584 87121 q = (1.0 - f) * lidUnit->oldDrainFlow + f * lidUnit->newDrainFlow;
1585 87121 Node[k].newLatFlow += q;
1586 87121 massbal_addInflowFlow(WET_WEATHER_INFLOW, q);
1587
1588 //... add pollutant load, based on parent subcatchment quality
1589
2/2
✓ Branch 0 taken 46080 times.
✓ Branch 1 taken 87121 times.
133201 for (p = 0; p < Nobjects[POLLUT]; p++)
1590 {
1591 //... get previous & current drain loads
1592 46080 w1 = lidUnit->oldDrainFlow * Subcatch[j].oldQual[p];
1593 46080 w2 = lidUnit->newDrainFlow * Subcatch[j].newQual[p];
1594
1595 //... add interpolated load to node's wet weather loading
1596 46080 w = (1.0 - f) * w1 + f * w2;
1597 46080 w = w * (1.0 - LidProcs[i].drainRmvl[p]);
1598 46080 Node[k].newQual[p] += w;
1599 46080 massbal_addInflowQual(WET_WEATHER_INFLOW, p, w);
1600 }
1601 }
1602 88561 lidList = lidList->nextLidUnit;
1603 }
1604 }
1605 48241 }
1606
1607 //=============================================================================
1608
1609 4443 void lid_getRunoff(int j, double tStep)
1610 //
1611 // Purpose: computes runoff and drain flows from the LIDs in a subcatchment.
1612 // Input: j = subcatchment index
1613 // tStep = time step (sec)
1614 // Output: updates following global quantities after LID treatment applied:
1615 // Vevap, Vpevap, VlidInfil, VlidIn, VlidOut, VlidDrain.
1616 //
1617 {
1618 TLidGroup theLidGroup; // group of LIDs placed in the subcatchment
1619 TLidList* lidList; // list of LID units in the group
1620 TLidUnit* lidUnit; // a member of the list of LID units
1621 double lidArea; // area of an LID unit
1622 4443 double qImperv = 0.0; // runoff from impervious areas (cfs)
1623 4443 double qPerv = 0.0; // runoff from pervious areas (cfs)
1624 4443 double lidInflow = 0.0; // inflow to an LID unit (ft/s)
1625 4443 double qRunoff = 0.0; // surface runoff from all LID units (cfs)
1626 4443 double qDrain = 0.0; // drain flow from all LID units (cfs)
1627 4443 double qReturn = 0.0; // LID outflow returned to pervious area (cfs)
1628
1629 //... return if there are no LID's
1630 4443 theLidGroup = LidGroups[j];
1631
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4443 times.
4443 if ( !theLidGroup ) return;
1632 4443 lidList = theLidGroup->lidList;
1633
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4443 times.
4443 if ( !lidList ) return;
1634
1635 //... determine if evaporation can occur
1636 4443 EvapRate = Evap.rate;
1637
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4443 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
4443 if ( Evap.dryOnly && Subcatch[j].rainfall > 0.0 ) EvapRate = 0.0;
1638
1639 //... find subcatchment's infiltration rate into native soil
1640 4443 findNativeInfil(j, tStep);
1641
1642 //... get impervious and pervious area runoff from non-LID
1643 // portion of subcatchment (cfs)
1644
2/2
✓ Branch 0 taken 4296 times.
✓ Branch 1 taken 147 times.
4443 if ( Subcatch[j].area > Subcatch[j].lidArea )
1645 {
1646 4296 qImperv = getImpervAreaRunoff(j);
1647 4296 qPerv = getPervAreaRunoff(j);
1648 }
1649
1650 //... evaluate performance of each LID unit placed in the subcatchment
1651
2/2
✓ Branch 0 taken 8475 times.
✓ Branch 1 taken 4443 times.
12918 while ( lidList )
1652 {
1653 //... find area of the LID unit
1654 8475 lidUnit = lidList->lidUnit;
1655 8475 lidArea = lidUnit->area * lidUnit->number;
1656
1657 //... if LID unit has area, evaluate its performance
1658
1/2
✓ Branch 0 taken 8475 times.
✗ Branch 1 not taken.
8475 if ( lidArea > 0.0 )
1659 {
1660 //... find runoff from non-LID area treated by LID area (ft/sec)
1661 8475 lidInflow = (qImperv * lidUnit->fromImperv +
1662 8475 qPerv * lidUnit->fromPerv) / lidArea;
1663
1664 //... update total runoff volume treated
1665 8475 VlidIn += lidInflow * lidArea * tStep;
1666
1667 //... add rainfall onto LID inflow (ft/s)
1668 8475 lidInflow = lidInflow + getRainInflow(j, lidUnit);
1669
1670 // ... add upstream runon only if LID occupies full subcatchment
1671
2/2
✓ Branch 0 taken 147 times.
✓ Branch 1 taken 8328 times.
8475 if ( Subcatch[j].area == Subcatch[j].lidArea )
1672 {
1673 147 lidInflow += Subcatch[j].runon;
1674 }
1675
1676 //... evaluate the LID unit's performance, updating the LID group's
1677 // total surface runoff, drain flow, and flow returned to
1678 // pervious area
1679 8475 evalLidUnit(j, lidUnit, lidArea, lidInflow, tStep,
1680 &qRunoff, &qDrain, &qReturn);
1681 }
1682 8475 lidList = lidList->nextLidUnit;
1683 }
1684
1685 //... save the LID group's total drain & return flows
1686 4443 theLidGroup->newDrainFlow = qDrain;
1687 4443 theLidGroup->flowToPerv = qReturn;
1688
1689 //... save the LID group's total surface, drain and return flow volumes
1690 4443 VlidOut = qRunoff * tStep;
1691 4443 VlidDrain = qDrain * tStep;
1692 4443 VlidReturn = qReturn * tStep;
1693 }
1694
1695 //=============================================================================
1696
1697 4443 void findNativeInfil(int j, double tStep)
1698 //
1699 // Purpose: determines a subcatchment's current infiltration rate into
1700 // its native soil.
1701 // Input: j = subcatchment index
1702 // tStep = time step (sec)
1703 // Output: sets values for module-level variables NativeInfil
1704 //
1705 {
1706 double nonLidArea;
1707
1708 //... subcatchment has non-LID pervious area
1709 4443 nonLidArea = Subcatch[j].area - Subcatch[j].lidArea;
1710
4/4
✓ Branch 0 taken 4296 times.
✓ Branch 1 taken 147 times.
✓ Branch 2 taken 3648 times.
✓ Branch 3 taken 648 times.
4443 if ( nonLidArea > 0.0 && Subcatch[j].fracImperv < 1.0 )
1711 {
1712 3648 NativeInfil = Vinfil / nonLidArea / tStep;
1713 }
1714
1715 //... otherwise find infil. rate for the subcatchment's rainfall + runon
1716 else
1717 {
1718 1590 NativeInfil = infil_getInfil(j, tStep,
1719 795 Subcatch[j].rainfall,
1720 795 Subcatch[j].runon,
1721 getSurfaceDepth(j));
1722 }
1723
1724 //... see if there is any groundwater-imposed limit on infil.
1725
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4443 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
4443 if ( !IgnoreGwater && Subcatch[j].groundwater )
1726 {
1727 MaxNativeInfil = Subcatch[j].groundwater->maxInfilVol / tStep;
1728 }
1729 4443 else MaxNativeInfil = BIG;
1730 4443 }
1731
1732 //=============================================================================
1733
1734 8475 double getRainInflow(int j, TLidUnit* lidUnit)
1735 //
1736 // Purpose: gets rainfall inflow to an LID unit.
1737 // Input: j = subcatchment index
1738 // lidUnit = ptr. to an LID unit
1739 // Output: returns rainfall rate over the LID unit (ft/sec)
1740 //
1741 {
1742 8475 TLidProc* lidProc = &LidProcs[lidUnit->lidIndex];
1743
1744
2/2
✓ Branch 0 taken 1299 times.
✓ Branch 1 taken 7176 times.
8475 if (lidProc->lidType == RAIN_BARREL &&
1745
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1299 times.
1299 lidProc->storage.covered == TRUE) return 0.0;
1746 8475 return Subcatch[j].rainfall;
1747 }
1748
1749 //=============================================================================
1750
1751 4296 double getImpervAreaRunoff(int j)
1752 //
1753 // Purpose: computes runoff from impervious area of a subcatchment that
1754 // is available for LID treatment.
1755 // Input: j = subcatchment index
1756 // Output: returns runoff flow rate (cfs)
1757 //
1758 {
1759 int i;
1760 4296 double q = 0.0, // runoff rate (ft/sec)
1761 nonLidArea; // non-LID area (ft2)
1762
1763 // --- runoff from impervious area w/ & w/o depression storage
1764
2/2
✓ Branch 0 taken 8592 times.
✓ Branch 1 taken 4296 times.
12888 for (i = IMPERV0; i <= IMPERV1; i++)
1765 {
1766 8592 q += Subcatch[j].subArea[i].runoff * Subcatch[j].subArea[i].fArea;
1767 }
1768
1769 // --- adjust for any fraction of runoff sent to pervious area
1770
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4296 times.
4296 if ( Subcatch[j].subArea[IMPERV0].routeTo == TO_PERV &&
1771 Subcatch[j].fracImperv < 1.0 )
1772 {
1773 q *= Subcatch[j].subArea[IMPERV0].fOutlet;
1774 }
1775 4296 nonLidArea = Subcatch[j].area - Subcatch[j].lidArea;
1776 4296 return q * nonLidArea;
1777 }
1778
1779 //=============================================================================
1780
1781 4296 double getPervAreaRunoff(int j)
1782 //
1783 // Purpose: computes runoff from pervious area of a subcatchment that
1784 // is available for LID treatment.
1785 // Input: j = subcatchment index
1786 // Output: returns runoff flow rate (cfs)
1787 //
1788 {
1789 4296 double q = 0.0, // runoff rate (ft/sec)
1790 nonLidArea; // non-LID area (ft2)
1791
1792 // --- runoff from pervious area
1793 4296 q = Subcatch[j].subArea[PERV].runoff * Subcatch[j].subArea[PERV].fArea;
1794
1795 // --- adjust for any fraction of runoff sent to impervious area
1796
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4296 times.
4296 if (Subcatch[j].subArea[PERV].routeTo == TO_IMPERV &&
1797 Subcatch[j].fracImperv > 0.0)
1798 {
1799 q *= Subcatch[j].subArea[PERV].fOutlet;
1800 }
1801 4296 nonLidArea = Subcatch[j].area - Subcatch[j].lidArea;
1802 4296 return q * nonLidArea;
1803 }
1804
1805 //=============================================================================
1806
1807 8475 void evalLidUnit(int j, TLidUnit* lidUnit, double lidArea, double lidInflow,
1808 double tStep, double *qRunoff, double *qDrain, double *qReturn)
1809 //
1810 // Purpose: evaluates performance of a specific LID unit over current time step.
1811 // Input: j = subcatchment index
1812 // lidUnit = ptr. to LID unit being evaluated
1813 // lidArea = area of LID unit
1814 // lidInflow = inflow to LID unit (ft/s)
1815 // tStep = time step (sec)
1816 // Output: qRunoff = sum of surface runoff from all LIDs (cfs)
1817 // qDrain = sum of drain flows from all LIDs (cfs)
1818 // qReturn = sum of LID flows returned to pervious area (cfs)
1819 //
1820 {
1821 TLidProc* lidProc; // LID process associated with lidUnit
1822 double lidRunoff, // surface runoff from LID unit (cfs)
1823 lidEvap, // evaporation rate from LID unit (ft/s)
1824 lidInfil, // infiltration rate from LID unit (ft/s)
1825 lidDrain; // drain flow rate from LID unit (ft/s & cfs)
1826
1827 //... identify the LID process of the LID unit being analyzed
1828 8475 lidProc = &LidProcs[lidUnit->lidIndex];
1829
1830 //... initialize evap and infil losses
1831 8475 lidEvap = 0.0;
1832 8475 lidInfil = 0.0;
1833
1834 //... find surface runoff from the LID unit (in cfs)
1835 8475 lidRunoff = lidproc_getOutflow(lidUnit, lidProc, lidInflow, EvapRate,
1836 NativeInfil, MaxNativeInfil, tStep,
1837 &lidEvap, &lidInfil, &lidDrain) * lidArea;
1838
1839 //... convert drain flow to CFS
1840 8475 lidDrain *= lidArea;
1841
1842 //... revise flows if LID outflow returned to pervious area
1843
4/4
✓ Branch 0 taken 7251 times.
✓ Branch 1 taken 1224 times.
✓ Branch 2 taken 7104 times.
✓ Branch 3 taken 147 times.
8475 if ( lidUnit->toPerv && Subcatch[j].area > Subcatch[j].lidArea )
1844 {
1845 //... surface runoff is always returned
1846 7104 *qReturn += lidRunoff;
1847 7104 lidRunoff = 0.0;
1848
1849 //... drain flow returned if it has same outlet as subcatchment
1850
1/2
✓ Branch 0 taken 7104 times.
✗ Branch 1 not taken.
7104 if ( lidUnit->drainNode == Subcatch[j].outNode &&
1851
1/2
✓ Branch 0 taken 7104 times.
✗ Branch 1 not taken.
7104 lidUnit->drainSubcatch == Subcatch[j].outSubcatch )
1852 {
1853 7104 *qReturn += lidDrain;
1854 7104 lidDrain = 0.0;
1855 }
1856 }
1857
1858 //... update system flow balance if drain flow goes to a
1859 // conveyance system node
1860
2/2
✓ Branch 0 taken 8328 times.
✓ Branch 1 taken 147 times.
8475 if ( lidUnit->drainNode >= 0 )
1861 {
1862 8328 massbal_updateRunoffTotals(RUNOFF_DRAINS, lidDrain * tStep);
1863 }
1864
1865 //... save new drain outflow
1866 8475 lidUnit->newDrainFlow = lidDrain;
1867
1868 //... update moisture losses (ft3)
1869 8475 Vevap += lidEvap * tStep * lidArea;
1870 8475 VlidInfil += lidInfil * tStep * lidArea;
1871
2/2
✓ Branch 1 taken 6024 times.
✓ Branch 2 taken 2451 times.
8475 if ( isLidPervious(lidUnit->lidIndex) )
1872 {
1873 6024 Vpevap += lidEvap * tStep * lidArea;
1874 }
1875
1876 //... update time since last rainfall (for Rain Barrel emptying)
1877
2/2
✓ Branch 0 taken 1086 times.
✓ Branch 1 taken 7389 times.
8475 if ( Subcatch[j].rainfall > MIN_RUNOFF ) lidUnit->dryTime = 0.0;
1878 7389 else lidUnit->dryTime += tStep;
1879
1880 //... update LID water balance and save results
1881 8475 lidproc_saveResults(lidUnit, UCF(RAINFALL), UCF(RAINDEPTH));
1882
1883 //... update LID group totals
1884 8475 *qRunoff += lidRunoff;
1885 8475 *qDrain += lidDrain;
1886 8475 }
1887
1888 //=============================================================================
1889
1890 37 void lid_writeWaterBalance()
1891 //
1892 // Purpose: writes a LID performance summary table to the project's report file.
1893 // Input: none
1894 // Output: none
1895 //
1896 {
1897 int j;
1898 37 int k = 0;
1899 37 double ucf = UCF(RAINDEPTH);
1900 double inflow;
1901 double outflow;
1902 double err;
1903 TLidUnit* lidUnit;
1904 TLidList* lidList;
1905 TLidGroup lidGroup;
1906
1907 //... check that project has LIDs
1908
2/2
✓ Branch 0 taken 2393 times.
✓ Branch 1 taken 37 times.
2430 for ( j = 0; j < GroupCount; j++ )
1909 {
1910
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 2382 times.
2393 if ( LidGroups[j] ) k++;
1911 }
1912
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 11 times.
37 if ( k == 0 ) return;
1913
1914 //... write table header
1915 11 fprintf(Frpt.file,
1916 "\n"
1917 "\n ***********************"
1918 "\n LID Performance Summary"
1919 "\n ***********************\n");
1920
1921 11 fprintf(Frpt.file,
1922 "\n --------------------------------------------------------------------------------------------------------------------"
1923 "\n Total Evap Infil Surface Drain Initial Final Continuity"
1924 "\n Inflow Loss Loss Outflow Outflow Storage Storage Error");
1925
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if ( UnitSystem == US ) fprintf(Frpt.file,
1926 "\n Subcatchment LID Control in in in in in in in %%");
1927 else fprintf(Frpt.file,
1928 "\n Subcatchment LID Control mm mm mm mm mm mm mm %%");
1929 11 fprintf(Frpt.file,
1930 "\n --------------------------------------------------------------------------------------------------------------------");
1931
1932 //... examine each LID unit in each subcatchment
1933
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 11 times.
47 for ( j = 0; j < GroupCount; j++ )
1934 {
1935 36 lidGroup = LidGroups[j];
1936
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
36 if ( !lidGroup || Subcatch[j].lidArea == 0.0 ) continue;
1937 11 lidList = lidGroup->lidList;
1938
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 11 times.
29 while ( lidList )
1939 {
1940 //... write water balance components to report file
1941 18 lidUnit = lidList->lidUnit;
1942 18 k = lidUnit->lidIndex;
1943 18 fprintf(Frpt.file, "\n %-16s %-16s", Subcatch[j].ID,
1944 18 LidProcs[k].ID);
1945 18 fprintf(Frpt.file, "%10.2f%10.2f%10.2f%10.2f%10.2f%10.2f%10.2f",
1946 18 lidUnit->waterBalance.inflow*ucf,
1947 18 lidUnit->waterBalance.evap*ucf,
1948 18 lidUnit->waterBalance.infil*ucf,
1949 18 lidUnit->waterBalance.surfFlow*ucf,
1950 18 lidUnit->waterBalance.drainFlow*ucf,
1951 18 lidUnit->waterBalance.initVol*ucf,
1952 18 lidUnit->waterBalance.finalVol*ucf);
1953
1954 //... compute flow balance error
1955 18 inflow = lidUnit->waterBalance.initVol +
1956 18 lidUnit->waterBalance.inflow;
1957 18 outflow = lidUnit->waterBalance.finalVol +
1958 18 lidUnit->waterBalance.evap +
1959 18 lidUnit->waterBalance.infil +
1960 18 lidUnit->waterBalance.surfFlow +
1961 18 lidUnit->waterBalance.drainFlow;
1962
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 if ( inflow > 0.0 ) err = (inflow - outflow) / inflow;
1963 else err = 1.0;
1964 18 fprintf(Frpt.file, " %10.2f", err*100.0);
1965 18 lidList = lidList->nextLidUnit;
1966 }
1967 }
1968 }
1969
1970 //=============================================================================
1971
1972 3 void initLidRptFile(char* title, char* lidID, char* subcatchID, TLidUnit* lidUnit)
1973 //
1974 // Purpose: initializes the report file used for a specific LID unit
1975 // Input: title = project's title
1976 // lidID = LID process name
1977 // subcatchID = subcatchment ID name
1978 // lidUnit = ptr. to LID unit
1979 // Output: none
1980 //
1981 {
1982 static int colCount = 14;
1983 static char* head1[] = {
1984 "\n \t", " Elapsed\t",
1985 " Total\t", " Total\t", " Surface\t", " Pavement\t", " Soil\t",
1986 " Storage\t", " Surface\t", " Drain\t", " Surface\t", " Pavement\t",
1987 " Soil\t", " Storage"};
1988 static char* head2[] = {
1989 "\n \t", " Time\t",
1990 " Inflow\t", " Evap\t", " Infil\t", " Perc\t", " Perc\t",
1991 " Exfil\t", " Runoff\t", " OutFlow\t", " Level\t", " Level\t",
1992 " Moisture\t", " Level"};
1993 static char* units1[] = {
1994 "\nDate Time \t", " Hours\t",
1995 " in/hr\t", " in/hr\t", " in/hr\t", " in/hr\t", " in/hr\t",
1996 " in/hr\t", " in/hr\t", " in/hr\t", " inches\t", " inches\t",
1997 " Content\t", " inches"};
1998 static char* units2[] = {
1999 "\nDate Time \t", " Hours\t",
2000 " mm/hr\t", " mm/hr\t", " mm/hr\t", " mm/hr\t", " mm/hr\t",
2001 " mm/hr\t", " mm/hr\t", " mm/hr\t", " mm\t", " mm\t",
2002 " Content\t", " mm"};
2003 static char line9[] = " ---------";
2004 int i;
2005 3 FILE* f = lidUnit->rptFile->file;
2006
2007 //... check that file was opened
2008
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if ( f == NULL ) return;
2009
2010 //... write title lines
2011 3 fprintf(f, "SWMM5 LID Report File\n");
2012 3 fprintf(f, "\nProject: %s", title);
2013 3 fprintf(f, "\nLID Unit: %s in Subcatchment %s\n", lidID, subcatchID);
2014
2015 //... write column headings
2016
2/2
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 3 times.
45 for ( i = 0; i < colCount; i++) fprintf(f, "%s", head1[i]);
2017
2/2
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 3 times.
45 for ( i = 0; i < colCount; i++) fprintf(f, "%s", head2[i]);
2018
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if ( UnitSystem == US )
2019 {
2020
2/2
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 3 times.
45 for ( i = 0; i < colCount; i++) fprintf(f, "%s", units1[i]);
2021 }
2022 else for ( i = 0; i < colCount; i++) fprintf(f, "%s", units2[i]);
2023 3 fprintf(f, "\n----------- --------");
2024
2/2
✓ Branch 1 taken 39 times.
✓ Branch 2 taken 3 times.
42 for ( i = 1; i < colCount; i++) fprintf(f, "\t%s", line9);
2025
2026 //... initialize LID dryness state
2027 3 lidUnit->rptFile->wasDry = 1;
2028 3 sstrncpy(lidUnit->rptFile->results, "", 0);
2029 }
2030