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 |