runoff.c
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | //----------------------------------------------------------------------------- | ||
| 2 | // runoff.c | ||
| 3 | // | ||
| 4 | // Project: EPA SWMM5 | ||
| 5 | // Version: 5.2 | ||
| 6 | // Date: 10/17/22 (Build 5.2.2) | ||
| 7 | // Author: L. Rossman | ||
| 8 | // M. Tryby | ||
| 9 | // | ||
| 10 | // Runoff analysis functions. | ||
| 11 | // | ||
| 12 | // Update History | ||
| 13 | // ============== | ||
| 14 | // Build 5.1.007: | ||
| 15 | // - Climate file now opened in climate.c module. | ||
| 16 | // Build 5.1.008: | ||
| 17 | // - Memory for runoff pollutant load now allocated and freed in this module. | ||
| 18 | // - Runoff time step chosen so that simulation does not exceed total duration. | ||
| 19 | // - State of LIDs considered when choosing wet or dry time step. | ||
| 20 | // - More checks added to skip over subcatchments with zero area. | ||
| 21 | // - Support added for sending outfall node discharge onto a subcatchment. | ||
| 22 | // Build 5.1.011: | ||
| 23 | // - Runoff wet time step kept aligned with reporting times. | ||
| 24 | // - Prior runoff time step used to convert returned outfall volume to flow. | ||
| 25 | // Build 5.1.012: | ||
| 26 | // - Runoff wet time step no longer kept aligned with reporting times. | ||
| 27 | // Build 5.1.014: | ||
| 28 | // - Fixed street sweeping bug. | ||
| 29 | // Build 5.2.0: | ||
| 30 | // - Support added for saving rainfall amounts in previous 48 hours. | ||
| 31 | // Build 5.2.2: | ||
| 32 | // - Fixed possible use of canSweep in runoff_execute() with no assigned value. | ||
| 33 | //----------------------------------------------------------------------------- | ||
| 34 | #define _CRT_SECURE_NO_DEPRECATE | ||
| 35 | |||
| 36 | #include <stdio.h> | ||
| 37 | #include <string.h> | ||
| 38 | #include <stdlib.h> | ||
| 39 | #include "headers.h" | ||
| 40 | #include "odesolve.h" | ||
| 41 | |||
| 42 | //----------------------------------------------------------------------------- | ||
| 43 | // Shared variables | ||
| 44 | //----------------------------------------------------------------------------- | ||
| 45 | static char IsRaining; // TRUE if precip. falls on study area | ||
| 46 | static char HasRunoff; // TRUE if study area generates runoff | ||
| 47 | static char HasSnow; // TRUE if any snow cover on study area | ||
| 48 | static int Nsteps; // number of runoff time steps taken | ||
| 49 | static int MaxSteps; // final number of runoff time steps | ||
| 50 | static long MaxStepsPos; // position in Runoff interface file | ||
| 51 | // where MaxSteps is saved | ||
| 52 | |||
| 53 | //----------------------------------------------------------------------------- | ||
| 54 | // Exportable variables | ||
| 55 | //----------------------------------------------------------------------------- | ||
| 56 | char HasWetLids; // TRUE if any LIDs are wet (used in lidproc.c) | ||
| 57 | double* OutflowLoad; // exported pollutant mass load (used in surfqual.c) | ||
| 58 | |||
| 59 | //----------------------------------------------------------------------------- | ||
| 60 | // Imported variables | ||
| 61 | //----------------------------------------------------------------------------- | ||
| 62 | extern float* SubcatchResults; // Results vector defined in OUTPUT.C | ||
| 63 | |||
| 64 | //----------------------------------------------------------------------------- | ||
| 65 | // External functions (declared in funcs.h) | ||
| 66 | //----------------------------------------------------------------------------- | ||
| 67 | // runoff_open (called from swmm_start in swmm5.c) | ||
| 68 | // runoff_execute (called from swmm_step in swmm5.c) | ||
| 69 | // runoff_close (called from swmm_end in swmm5.c) | ||
| 70 | |||
| 71 | //----------------------------------------------------------------------------- | ||
| 72 | // Local functions | ||
| 73 | //----------------------------------------------------------------------------- | ||
| 74 | static double runoff_getTimeStep(DateTime currentDate); | ||
| 75 | static void runoff_initFile(void); | ||
| 76 | static void runoff_readFromFile(void); | ||
| 77 | static void runoff_saveToFile(float tStep); | ||
| 78 | static void runoff_getOutfallRunon(double tStep); | ||
| 79 | |||
| 80 | //============================================================================= | ||
| 81 | |||
| 82 | 37 | int runoff_open() | |
| 83 | // | ||
| 84 | // Input: none | ||
| 85 | // Output: returns the global error code | ||
| 86 | // Purpose: opens the runoff analyzer. | ||
| 87 | // | ||
| 88 | { | ||
| 89 | 37 | IsRaining = FALSE; | |
| 90 | 37 | HasRunoff = FALSE; | |
| 91 | 37 | HasSnow = FALSE; | |
| 92 | 37 | Nsteps = 0; | |
| 93 | |||
| 94 | // --- open the Ordinary Differential Equation solver | ||
| 95 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
|
37 | if ( !odesolve_open(MAXODES) ) report_writeErrorMsg(ERR_ODE_SOLVER, ""); |
| 96 | |||
| 97 | // --- allocate memory for pollutant runoff loads | ||
| 98 | 37 | OutflowLoad = NULL; | |
| 99 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 23 times.
|
37 | if ( Nobjects[POLLUT] > 0 ) |
| 100 | { | ||
| 101 | 14 | OutflowLoad = (double *) calloc(Nobjects[POLLUT], sizeof(double)); | |
| 102 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | if ( !OutflowLoad ) report_writeErrorMsg(ERR_MEMORY, ""); |
| 103 | } | ||
| 104 | |||
| 105 | // --- see if a runoff interface file should be opened | ||
| 106 |
3/3✓ Branch 0 taken 1 time.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 33 times.
|
37 | switch ( Frunoff.mode ) |
| 107 | { | ||
| 108 | 1 | case USE_FILE: | |
| 109 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
|
1 | if ( (Frunoff.file = fopen(Frunoff.name, "r+b")) == NULL) |
| 110 | ✗ | report_writeErrorMsg(ERR_RUNOFF_FILE_OPEN, Frunoff.name); | |
| 111 | 1 | else runoff_initFile(); | |
| 112 | 1 | break; | |
| 113 | 3 | case SAVE_FILE: | |
| 114 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | if ( (Frunoff.file = fopen(Frunoff.name, "w+b")) == NULL) |
| 115 | ✗ | report_writeErrorMsg(ERR_RUNOFF_FILE_OPEN, Frunoff.name); | |
| 116 | 3 | else runoff_initFile(); | |
| 117 | 3 | break; | |
| 118 | } | ||
| 119 | 37 | return ErrorCode; | |
| 120 | } | ||
| 121 | |||
| 122 | //============================================================================= | ||
| 123 | |||
| 124 | 37 | void runoff_close() | |
| 125 | // | ||
| 126 | // Input: none | ||
| 127 | // Output: none | ||
| 128 | // Purpose: closes the runoff analyzer. | ||
| 129 | // | ||
| 130 | { | ||
| 131 | // --- close the ODE solver | ||
| 132 | 37 | odesolve_close(); | |
| 133 | |||
| 134 | // --- free memory for pollutant runoff loads | ||
| 135 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 23 times.
|
37 | FREE(OutflowLoad); |
| 136 | |||
| 137 | // --- close runoff interface file if in use | ||
| 138 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 33 times.
|
37 | if ( Frunoff.file ) |
| 139 | { | ||
| 140 | // --- write to file number of time steps simulated | ||
| 141 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 time.
|
4 | if ( Frunoff.mode == SAVE_FILE ) |
| 142 | { | ||
| 143 | 3 | fseek(Frunoff.file, MaxStepsPos, SEEK_SET); | |
| 144 | 3 | fwrite(&Nsteps, sizeof(int), 1, Frunoff.file); | |
| 145 | } | ||
| 146 | 4 | fclose(Frunoff.file); | |
| 147 | } | ||
| 148 | |||
| 149 | // --- close climate file if in use | ||
| 150 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 26 times.
|
37 | if ( Fclimate.file ) fclose(Fclimate.file); |
| 151 | 37 | } | |
| 152 | |||
| 153 | //============================================================================= | ||
| 154 | |||
| 155 | 33334 | void runoff_execute() | |
| 156 | // | ||
| 157 | // Input: none | ||
| 158 | // Output: none | ||
| 159 | // Purpose: computes runoff from each subcatchment at current runoff time. | ||
| 160 | // | ||
| 161 | { | ||
| 162 | int j; // object index | ||
| 163 | int day; // day of calendar year | ||
| 164 | double runoffStep; // runoff time step (sec) | ||
| 165 | double oldRunoffStep; // previous runoff time step (sec) | ||
| 166 | double runoff; // subcatchment runoff (ft/sec) | ||
| 167 | DateTime currentDate; // current date/time | ||
| 168 | char canSweep; // TRUE if street sweeping can occur | ||
| 169 | |||
| 170 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 33334 times.
|
33334 | if ( ErrorCode ) return; |
| 171 | |||
| 172 | // --- find previous runoff time step in sec | ||
| 173 | 33334 | oldRunoffStep = (NewRunoffTime - OldRunoffTime) / 1000.0; | |
| 174 | |||
| 175 | // --- convert elapsed runoff time in milliseconds to a calendar date | ||
| 176 | 33334 | currentDate = getDateTime(NewRunoffTime); | |
| 177 | |||
| 178 | // --- update climatological conditions | ||
| 179 | 33334 | climate_setState(currentDate); | |
| 180 | |||
| 181 | // --- if no subcatchments then simply update runoff elapsed time | ||
| 182 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 33334 times.
|
33334 | if ( Nobjects[SUBCATCH] == 0 ) |
| 183 | { | ||
| 184 | ✗ | OldRunoffTime = NewRunoffTime; | |
| 185 | ✗ | NewRunoffTime += (double)(DryStep) * 1000.; | |
| 186 | ✗ | NewRunoffTime = MIN(NewRunoffTime, TotalDuration); | |
| 187 | ✗ | return; | |
| 188 | } | ||
| 189 | |||
| 190 | // --- update current rainfall at each raingage | ||
| 191 | // NOTE: must examine gages in sequential order due to possible | ||
| 192 | // presence of co-gages (gages that share same rain time series). | ||
| 193 | 33334 | IsRaining = FALSE; | |
| 194 |
2/2✓ Branch 0 taken 34070 times.
✓ Branch 1 taken 33334 times.
|
67404 | for (j = 0; j < Nobjects[GAGE]; j++) |
| 195 | { | ||
| 196 | 34070 | gage_setState(j, currentDate); | |
| 197 |
2/2✓ Branch 0 taken 4024 times.
✓ Branch 1 taken 30046 times.
|
34070 | if ( Gage[j].rainfall > 0.0 ) IsRaining = TRUE; |
| 198 | } | ||
| 199 | |||
| 200 | // --- read runoff results from interface file if applicable | ||
| 201 |
2/2✓ Branch 0 taken 244 times.
✓ Branch 1 taken 33090 times.
|
33334 | if ( Frunoff.mode == USE_FILE ) |
| 202 | { | ||
| 203 | 244 | runoff_readFromFile(); | |
| 204 | 244 | return; | |
| 205 | } | ||
| 206 | |||
| 207 | // --- see if street sweeping can occur on current date | ||
| 208 | 33090 | day = datetime_dayOfYear(currentDate); | |
| 209 | 33090 | canSweep = FALSE; | |
| 210 |
1/2✓ Branch 0 taken 33090 times.
✗ Branch 1 not taken.
|
33090 | if ( SweepStart <= SweepEnd ) |
| 211 | { | ||
| 212 |
3/4✓ Branch 0 taken 33090 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 32802 times.
✓ Branch 3 taken 288 times.
|
33090 | if ( day >= SweepStart && day <= SweepEnd ) canSweep = TRUE; |
| 213 | } | ||
| 214 | ✗ | else if ( day <= SweepEnd || day >= SweepStart ) canSweep = TRUE; | |
| 215 | |||
| 216 | // --- get runoff time step (in seconds) | ||
| 217 | 33090 | runoffStep = runoff_getTimeStep(currentDate); | |
| 218 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 33090 times.
|
33090 | if ( runoffStep <= 0.0 ) |
| 219 | { | ||
| 220 | ✗ | ErrorCode = ERR_TIMESTEP; | |
| 221 | ✗ | return; | |
| 222 | } | ||
| 223 | |||
| 224 | // --- update runoff time clock (in milliseconds) | ||
| 225 | 33090 | OldRunoffTime = NewRunoffTime; | |
| 226 | 33090 | NewRunoffTime += (double)(1000 * runoffStep); | |
| 227 | |||
| 228 | // --- adjust runoff step so that total duration not exceeded | ||
| 229 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 33081 times.
|
33090 | if ( NewRunoffTime > TotalDuration ) |
| 230 | { | ||
| 231 | 9 | runoffStep = (TotalDuration - OldRunoffTime) / 1000.0; | |
| 232 | 9 | NewRunoffTime = TotalDuration; | |
| 233 | } | ||
| 234 | |||
| 235 | // --- update past n-hour rain totals | ||
| 236 |
2/2✓ Branch 0 taken 33826 times.
✓ Branch 1 taken 33090 times.
|
66916 | for (j = 0; j < Nobjects[GAGE]; j++) |
| 237 | 33826 | gage_updatePastRain(j, (int)runoffStep); | |
| 238 | |||
| 239 | // --- update old state of each subcatchment, | ||
| 240 |
2/2✓ Branch 1 taken 3229694 times.
✓ Branch 2 taken 33090 times.
|
3262784 | for (j = 0; j < Nobjects[SUBCATCH]; j++) subcatch_setOldState(j); |
| 241 | |||
| 242 | // --- determine any runon from drainage system outfall nodes | ||
| 243 |
2/2✓ Branch 0 taken 33054 times.
✓ Branch 1 taken 36 times.
|
33090 | if ( oldRunoffStep > 0.0 ) runoff_getOutfallRunon(oldRunoffStep); |
| 244 | |||
| 245 | // --- determine runon from upstream subcatchments, and implement snow removal | ||
| 246 |
2/2✓ Branch 0 taken 3229694 times.
✓ Branch 1 taken 33090 times.
|
3262784 | for (j = 0; j < Nobjects[SUBCATCH]; j++) |
| 247 | { | ||
| 248 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3229694 times.
|
3229694 | if ( Subcatch[j].area == 0.0 ) continue; |
| 249 | 3229694 | subcatch_getRunon(j); | |
| 250 |
2/2✓ Branch 0 taken 3115063 times.
✓ Branch 1 taken 114631 times.
|
3229694 | if ( !IgnoreSnowmelt ) snow_plowSnow(j, runoffStep); |
| 251 | } | ||
| 252 | |||
| 253 | // --- determine runoff and pollutant buildup/washoff in each subcatchment | ||
| 254 | 33090 | HasSnow = FALSE; | |
| 255 | 33090 | HasRunoff = FALSE; | |
| 256 | 33090 | HasWetLids = FALSE; | |
| 257 |
2/2✓ Branch 0 taken 3229694 times.
✓ Branch 1 taken 33090 times.
|
3262784 | for (j = 0; j < Nobjects[SUBCATCH]; j++) |
| 258 | { | ||
| 259 | // --- find total runoff rate (in ft/sec) over the subcatchment | ||
| 260 | // (the amount that actually leaves the subcatchment (in cfs) | ||
| 261 | // is also computed and is stored in Subcatch[j].newRunoff) | ||
| 262 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3229694 times.
|
3229694 | if ( Subcatch[j].area == 0.0 ) continue; |
| 263 | 3229694 | runoff = subcatch_getRunoff(j, runoffStep); | |
| 264 | |||
| 265 | // --- update state of study area surfaces | ||
| 266 |
2/2✓ Branch 0 taken 929812 times.
✓ Branch 1 taken 2299882 times.
|
3229694 | if ( runoff > 0.0 ) HasRunoff = TRUE; |
| 267 |
2/2✓ Branch 0 taken 589753 times.
✓ Branch 1 taken 2639941 times.
|
3229694 | if ( Subcatch[j].newSnowDepth > 0.0 ) HasSnow = TRUE; |
| 268 | |||
| 269 | // --- skip pollutant buildup/washoff if quality ignored | ||
| 270 |
2/2✓ Branch 0 taken 23040 times.
✓ Branch 1 taken 3206654 times.
|
3229694 | if ( IgnoreQuality ) continue; |
| 271 | |||
| 272 | // --- add to pollutant buildup if runoff is negligible | ||
| 273 |
2/2✓ Branch 0 taken 2728851 times.
✓ Branch 1 taken 477803 times.
|
3206654 | if ( runoff < MIN_RUNOFF ) surfqual_getBuildup(j, runoffStep); |
| 274 | |||
| 275 | // --- reduce buildup by street sweeping | ||
| 276 |
4/4✓ Branch 0 taken 3111902 times.
✓ Branch 1 taken 94752 times.
✓ Branch 2 taken 2848978 times.
✓ Branch 3 taken 262924 times.
|
3206654 | if ( canSweep && Subcatch[j].rainfall <= MIN_RUNOFF) |
| 277 | 2848978 | surfqual_sweepBuildup(j, currentDate); | |
| 278 | |||
| 279 | // --- compute pollutant washoff | ||
| 280 | 3206654 | surfqual_getWashoff(j, runoff, runoffStep); | |
| 281 | } | ||
| 282 | |||
| 283 | // --- update tracking of system-wide max. runoff rate | ||
| 284 | 33090 | stats_updateMaxRunoff(); | |
| 285 | |||
| 286 | // --- save runoff results to interface file if one is used | ||
| 287 | 33090 | Nsteps++; | |
| 288 |
2/2✓ Branch 0 taken 334 times.
✓ Branch 1 taken 32756 times.
|
33090 | if ( Frunoff.mode == SAVE_FILE ) |
| 289 | { | ||
| 290 | 334 | runoff_saveToFile((float)runoffStep); | |
| 291 | } | ||
| 292 | |||
| 293 | // --- reset subcatchment runon to 0 | ||
| 294 |
2/2✓ Branch 0 taken 3229694 times.
✓ Branch 1 taken 33090 times.
|
3262784 | for (j = 0; j < Nobjects[SUBCATCH]; j++) Subcatch[j].runon = 0.0; |
| 295 | } | ||
| 296 | |||
| 297 | //============================================================================= | ||
| 298 | |||
| 299 | 33090 | double runoff_getTimeStep(DateTime currentDate) | |
| 300 | // | ||
| 301 | // Input: currentDate = current simulation date/time | ||
| 302 | // Output: time step (sec) | ||
| 303 | // Purpose: computes a time step to use for runoff calculations. | ||
| 304 | // | ||
| 305 | { | ||
| 306 | int j; | ||
| 307 | long timeStep; | ||
| 308 | 33090 | long maxStep = DryStep; | |
| 309 | |||
| 310 | // --- find shortest time until next evaporation or rainfall value | ||
| 311 | // (this represents the maximum possible time step) | ||
| 312 | 33090 | timeStep = datetime_timeDiff(climate_getNextEvapDate(), currentDate); | |
| 313 |
3/4✓ Branch 0 taken 33090 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 33089 times.
|
33090 | if ( timeStep > 0.0 && timeStep < maxStep ) maxStep = timeStep; |
| 314 |
2/2✓ Branch 0 taken 33826 times.
✓ Branch 1 taken 33090 times.
|
66916 | for (j = 0; j < Nobjects[GAGE]; j++) |
| 315 | { | ||
| 316 | 33826 | timeStep = datetime_timeDiff(gage_getNextRainDate(j, currentDate), | |
| 317 | currentDate); | ||
| 318 |
4/4✓ Branch 0 taken 22463 times.
✓ Branch 1 taken 11363 times.
✓ Branch 2 taken 2888 times.
✓ Branch 3 taken 19575 times.
|
33826 | if ( timeStep > 0 && timeStep < maxStep ) maxStep = timeStep; |
| 319 | } | ||
| 320 | |||
| 321 | // --- determine whether wet or dry time step applies | ||
| 322 |
8/8✓ Branch 0 taken 29186 times.
✓ Branch 1 taken 3904 times.
✓ Branch 2 taken 25555 times.
✓ Branch 3 taken 3631 times.
✓ Branch 4 taken 3282 times.
✓ Branch 5 taken 22273 times.
✓ Branch 6 taken 936 times.
✓ Branch 7 taken 2346 times.
|
33090 | if ( IsRaining || HasSnow || HasRunoff || HasWetLids ) |
| 323 | { | ||
| 324 | 30744 | timeStep = WetStep; | |
| 325 | } | ||
| 326 | 2346 | else timeStep = DryStep; | |
| 327 | |||
| 328 | // --- limit time step if necessary | ||
| 329 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 33081 times.
|
33090 | if ( timeStep > maxStep ) timeStep = maxStep; |
| 330 | 33090 | return (double)timeStep; | |
| 331 | } | ||
| 332 | |||
| 333 | //============================================================================= | ||
| 334 | |||
| 335 | 4 | void runoff_initFile(void) | |
| 336 | // | ||
| 337 | // Input: none | ||
| 338 | // Output: none | ||
| 339 | // Purpose: initializes a Runoff Interface file for saving results. | ||
| 340 | // | ||
| 341 | { | ||
| 342 | int nSubcatch; | ||
| 343 | int nPollut; | ||
| 344 | int flowUnits; | ||
| 345 | 4 | char fileStamp[] = "SWMM5-RUNOFF"; | |
| 346 | 4 | char fStamp[] = "SWMM5-RUNOFF"; | |
| 347 | |||
| 348 | 4 | MaxSteps = 0; | |
| 349 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 time.
|
4 | if ( Frunoff.mode == SAVE_FILE ) |
| 350 | { | ||
| 351 | // --- write file stamp, # subcatchments & # pollutants to file | ||
| 352 | 3 | nSubcatch = Nobjects[SUBCATCH]; | |
| 353 | 3 | nPollut = Nobjects[POLLUT]; | |
| 354 | 3 | flowUnits = FlowUnits; | |
| 355 | 3 | fwrite(fileStamp, sizeof(char), strlen(fileStamp), Frunoff.file); | |
| 356 | 3 | fwrite(&nSubcatch, sizeof(int), 1, Frunoff.file); | |
| 357 | 3 | fwrite(&nPollut, sizeof(int), 1, Frunoff.file); | |
| 358 | 3 | fwrite(&flowUnits, sizeof(int), 1, Frunoff.file); | |
| 359 | 3 | MaxStepsPos = ftell(Frunoff.file); | |
| 360 | 3 | fwrite(&MaxSteps, sizeof(int), 1, Frunoff.file); | |
| 361 | } | ||
| 362 | |||
| 363 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 3 times.
|
4 | if ( Frunoff.mode == USE_FILE ) |
| 364 | { | ||
| 365 | // --- check that interface file contains proper header records | ||
| 366 | 1 | fread(fStamp, sizeof(char), strlen(fileStamp), Frunoff.file); | |
| 367 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | if ( strcmp(fStamp, fileStamp) != 0 ) |
| 368 | { | ||
| 369 | ✗ | report_writeErrorMsg(ERR_RUNOFF_FILE_FORMAT, ""); | |
| 370 | ✗ | return; | |
| 371 | } | ||
| 372 | 1 | nSubcatch = -1; | |
| 373 | 1 | nPollut = -1; | |
| 374 | 1 | flowUnits = -1; | |
| 375 | 1 | fread(&nSubcatch, sizeof(int), 1, Frunoff.file); | |
| 376 | 1 | fread(&nPollut, sizeof(int), 1, Frunoff.file); | |
| 377 | 1 | fread(&flowUnits, sizeof(int), 1, Frunoff.file); | |
| 378 | 1 | fread(&MaxSteps, sizeof(int), 1, Frunoff.file); | |
| 379 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | if ( nSubcatch != Nobjects[SUBCATCH] |
| 380 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | || nPollut != Nobjects[POLLUT] |
| 381 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | || flowUnits != FlowUnits |
| 382 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | || MaxSteps <= 0 ) |
| 383 | { | ||
| 384 | ✗ | report_writeErrorMsg(ERR_RUNOFF_FILE_FORMAT, ""); | |
| 385 | } | ||
| 386 | } | ||
| 387 | } | ||
| 388 | |||
| 389 | //============================================================================= | ||
| 390 | |||
| 391 | 334 | void runoff_saveToFile(float tStep) | |
| 392 | // | ||
| 393 | // Input: tStep = runoff time step (sec) | ||
| 394 | // Output: none | ||
| 395 | // Purpose: saves current runoff results to Runoff Interface file. | ||
| 396 | // | ||
| 397 | { | ||
| 398 | int j; | ||
| 399 | 334 | int n = MAX_SUBCATCH_RESULTS + Nobjects[POLLUT] - 1; | |
| 400 | |||
| 401 | |||
| 402 | 334 | fwrite(&tStep, sizeof(float), 1, Frunoff.file); | |
| 403 |
2/2✓ Branch 0 taken 80636 times.
✓ Branch 1 taken 334 times.
|
80970 | for (j=0; j<Nobjects[SUBCATCH]; j++) |
| 404 | { | ||
| 405 | 80636 | subcatch_getResults(j, 1.0, SubcatchResults); | |
| 406 | 80636 | fwrite(SubcatchResults, sizeof(float), n, Frunoff.file); | |
| 407 | } | ||
| 408 | 334 | } | |
| 409 | |||
| 410 | //============================================================================= | ||
| 411 | |||
| 412 | 244 | void runoff_readFromFile(void) | |
| 413 | // | ||
| 414 | // Input: none | ||
| 415 | // Output: none | ||
| 416 | // Purpose: reads runoff results from Runoff Interface file for current time. | ||
| 417 | // | ||
| 418 | { | ||
| 419 | int i, j; | ||
| 420 | int nResults; // number of results per subcatch. | ||
| 421 | int kount; // count of items read from file | ||
| 422 | float tStep; // runoff time step (sec) | ||
| 423 | TGroundwater* gw; // ptr. to Groundwater object | ||
| 424 | |||
| 425 | // --- make sure not past end of file | ||
| 426 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 244 times.
|
244 | if ( Nsteps > MaxSteps ) |
| 427 | { | ||
| 428 | ✗ | report_writeErrorMsg(ERR_RUNOFF_FILE_END, ""); | |
| 429 | ✗ | return; | |
| 430 | } | ||
| 431 | |||
| 432 | // --- replace old state with current one for all subcatchments | ||
| 433 |
2/2✓ Branch 1 taken 80276 times.
✓ Branch 2 taken 244 times.
|
80520 | for (j = 0; j < Nobjects[SUBCATCH]; j++) subcatch_setOldState(j); |
| 434 | |||
| 435 | // --- read runoff time step | ||
| 436 | 244 | kount = 0; | |
| 437 | 244 | kount += (int)fread(&tStep, sizeof(float), 1, Frunoff.file); | |
| 438 | |||
| 439 | // --- compute number of results saved for each subcatchment | ||
| 440 | 244 | nResults = MAX_SUBCATCH_RESULTS + Nobjects[POLLUT] - 1; | |
| 441 | |||
| 442 | // --- for each subcatchment | ||
| 443 |
2/2✓ Branch 0 taken 80276 times.
✓ Branch 1 taken 244 times.
|
80520 | for (j = 0; j < Nobjects[SUBCATCH]; j++) |
| 444 | { | ||
| 445 | // --- read vector of saved results | ||
| 446 | 80276 | kount += (int)fread(SubcatchResults, sizeof(float), nResults, Frunoff.file); | |
| 447 | |||
| 448 | // --- extract hydrologic results, converting units where necessary | ||
| 449 | // (results were saved to file in user's units) | ||
| 450 | 160552 | Subcatch[j].newSnowDepth = SubcatchResults[SUBCATCH_SNOWDEPTH] / | |
| 451 | 80276 | UCF(RAINDEPTH); | |
| 452 | 160552 | Subcatch[j].evapLoss = SubcatchResults[SUBCATCH_EVAP] / | |
| 453 | 80276 | UCF(RAINFALL); | |
| 454 | 160552 | Subcatch[j].infilLoss = SubcatchResults[SUBCATCH_INFIL] / | |
| 455 | 80276 | UCF(RAINFALL); | |
| 456 | 160552 | Subcatch[j].newRunoff = SubcatchResults[SUBCATCH_RUNOFF] / | |
| 457 | 80276 | UCF(FLOW); | |
| 458 | 80276 | gw = Subcatch[j].groundwater; | |
| 459 |
2/2✓ Branch 0 taken 77836 times.
✓ Branch 1 taken 2440 times.
|
80276 | if ( gw ) |
| 460 | { | ||
| 461 | 77836 | gw->newFlow = SubcatchResults[SUBCATCH_GW_FLOW] / UCF(FLOW); | |
| 462 | 155672 | gw->lowerDepth = Aquifer[gw->aquifer].bottomElev - | |
| 463 | 77836 | (SubcatchResults[SUBCATCH_GW_ELEV] / UCF(LENGTH)); | |
| 464 | 77836 | gw->theta = SubcatchResults[SUBCATCH_SOIL_MOIST]; | |
| 465 | } | ||
| 466 | |||
| 467 | // --- extract water quality results | ||
| 468 |
2/2✓ Branch 0 taken 321104 times.
✓ Branch 1 taken 80276 times.
|
401380 | for (i = 0; i < Nobjects[POLLUT]; i++) |
| 469 | { | ||
| 470 | 321104 | Subcatch[j].newQual[i] = SubcatchResults[SUBCATCH_WASHOFF + i]; | |
| 471 | } | ||
| 472 | } | ||
| 473 | |||
| 474 | // --- report error if not enough values were read | ||
| 475 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 244 times.
|
244 | if ( kount < 1 + Nobjects[SUBCATCH] * nResults ) |
| 476 | { | ||
| 477 | ✗ | report_writeErrorMsg(ERR_RUNOFF_FILE_READ, ""); | |
| 478 | ✗ | return; | |
| 479 | } | ||
| 480 | |||
| 481 | // --- update runoff time clock | ||
| 482 | 244 | OldRunoffTime = NewRunoffTime; | |
| 483 | 244 | NewRunoffTime = OldRunoffTime + (double)(tStep)*1000.0; | |
| 484 |
1/2✓ Branch 0 taken 244 times.
✗ Branch 1 not taken.
|
244 | NewRunoffTime = MIN(NewRunoffTime, TotalDuration); |
| 485 | 244 | Nsteps++; | |
| 486 | } | ||
| 487 | |||
| 488 | //============================================================================= | ||
| 489 | |||
| 490 | |||
| 491 | 33054 | void runoff_getOutfallRunon(double tStep) | |
| 492 | // | ||
| 493 | // Input: tStep = previous runoff time step (sec) | ||
| 494 | // Output: none | ||
| 495 | // Purpose: adds flow and pollutant loads leaving drainage system outfalls | ||
| 496 | // during the previous runoff time step to designated subcatchments. | ||
| 497 | // | ||
| 498 | { | ||
| 499 | int i, k, p; | ||
| 500 | double w; | ||
| 501 | |||
| 502 | // --- examine each outfall node | ||
| 503 |
2/2✓ Branch 0 taken 364451 times.
✓ Branch 1 taken 33054 times.
|
397505 | for (i = 0; i < Nnodes[OUTFALL]; i++) |
| 504 | { | ||
| 505 | // --- ignore node if outflow not re-routed onto a subcatchment | ||
| 506 | 364451 | k = Outfall[i].routeTo; | |
| 507 |
2/2✓ Branch 0 taken 364212 times.
✓ Branch 1 taken 239 times.
|
364451 | if ( k < 0 ) continue; |
| 508 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 239 times.
|
239 | if ( Subcatch[k].area == 0.0 ) continue; |
| 509 | |||
| 510 | // --- add outfall's flow to subcatchment as runon and re-set routed | ||
| 511 | // flow volume to 0 | ||
| 512 | 239 | subcatch_addRunonFlow(k, Outfall[i].vRouted/tStep); | |
| 513 | 239 | massbal_updateRunoffTotals(RUNOFF_RUNON, Outfall[i].vRouted); | |
| 514 | 239 | Outfall[i].vRouted = 0.0; | |
| 515 | |||
| 516 | // --- add outfall's pollutant load on to subcatchment's wet | ||
| 517 | // deposition load and re-set routed load to 0 | ||
| 518 | // (Subcatch.newQual is being used as a temporary load accumulator) | ||
| 519 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 239 times.
|
239 | for (p = 0; p < Nobjects[POLLUT]; p++) |
| 520 | { | ||
| 521 | ✗ | w = Outfall[i].wRouted[p] * LperFT3; | |
| 522 | ✗ | massbal_updateLoadingTotals(DEPOSITION_LOAD, p, w * Pollut[p].mcf); | |
| 523 | ✗ | Subcatch[k].newQual[p] += w / tStep; | |
| 524 | ✗ | Outfall[i].wRouted[p] = 0.0; | |
| 525 | } | ||
| 526 | } | ||
| 527 | 33054 | } | |
| 528 |