diff --git a/src/solver/dynwave.c b/src/solver/dynwave.c index 0269c7b6d..85968e2a9 100644 --- a/src/solver/dynwave.c +++ b/src/solver/dynwave.c @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 06/12/23 (Build 5.2.4) +// Date: 07/13/23 (Build 5.2.4) // Author: L. Rossman // M. Tryby (EPA) // R. Dickinson (CDM) @@ -599,7 +599,7 @@ int findNodeDepths(double dt) // { int i; - double yOld; // previous node depth (ft) + double yOld = 0.0; // previous node depth (ft) // --- compute outfall depths based on flow in connecting link for ( i = 0; i < Nobjects[LINK]; i++ ) link_setOutfallDepth(i); diff --git a/src/solver/inlet.c b/src/solver/inlet.c index 4defe127e..d7232d717 100644 --- a/src/solver/inlet.c +++ b/src/solver/inlet.c @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 10/08/22 (Build 5.2.2) +// Date: 07/13/23 (Build 5.2.4) // Author: L. Rossman // // Street/Channel Inlet Functions @@ -18,6 +18,10 @@ // - Substitutes the constant BIG for HUGE. // Build 5.2.2: // - Additional statistics added to Street Flow Summary table. +// Build 5.2.4: +// - Fixed expression for equivalent gutter slope in getCurbInletCapture. +// - Corrected sign in equation for effective head in a curb inlet +// with an inclined throat opening in getCurbOrificeFlow. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -1491,7 +1495,7 @@ double getCurbInletCapture(double Q, double L) { Sr = Sw / Sx; Eo = getEo(Sr, T-W, W); - Se = Sx + Sw * Eo; //HEC-22 Eq(4-24) + Se = Sx + (a/W) * Eo; //HEC-22 Eq(4-24) } // --- opening length for full capture @@ -1772,7 +1776,7 @@ double getCurbOrificeFlow(double di, double h, double L, int throatAngle) if (throatAngle == HORIZONTAL_THROAT) d = di - h / 2.0; else if (throatAngle == INCLINED_THROAT) - d = di + (h / 2.0) * 0.7071; + d = di - (h / 2.0) * 0.7071; return 0.67 * h * L * sqrt(2.0 * 32.16 * d); //HEC-22 Eq(4-31a) } diff --git a/src/solver/lid.c b/src/solver/lid.c index e77542897..ddab7b6da 100644 --- a/src/solver/lid.c +++ b/src/solver/lid.c @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 02/10/23 (Build 5.2.3) +// Date: 07/13/23 (Build 5.2.4) // Author: L. Rossman // // This module handles all data processing involving LID (Low Impact @@ -70,6 +70,8 @@ // - Covered property added to RAIN_BARREL parameters // Build 5.2.3 // - Fixed double counting of initial water volume in green roof drain mat. +// Build 5.2.4 +// - Fixed test for invalid data in readDrainData function. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -765,7 +767,7 @@ int readDrainData(int j, char* toks[], int ntoks) for (i = 0; i < 6; i++) x[i] = 0.0; for (i = 2; i < 8; i++) { - if ( (ntoks > i) && (! getDouble(toks[i], &x[i-2]) || x[i-2]) < 0.0 ) + if ( (ntoks > i) && (! getDouble(toks[i], &x[i-2]) || x[i-2] < 0.0) ) return error_setInpError(ERR_NUMBER, toks[i]); } diff --git a/src/solver/lidproc.c b/src/solver/lidproc.c index aae0ac9bd..85245fb30 100644 --- a/src/solver/lidproc.c +++ b/src/solver/lidproc.c @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 11/01/21 (Build 5.2.0) +// Date: 07/13/23 (Build 5.2.4) // Author: L. Rossman // // This module computes the hydrologic performance of an LID (Low Impact @@ -53,6 +53,11 @@ // - Fixed failure to account for effect of Impervious Surface Fraction on // pavement permeability for Permeable Pavement LID // - Fixed units conversion for pavement depth in detailed report file. +// Build 5.2.4: +// - Modified flux limits in biocellFluxRates, pavementFluxRates and +// trenchFluxRates. +// - Corrected head calculation in getStorageDrainRate when unit has both +// a soil and pavement layer. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -654,61 +659,64 @@ void biocellFluxRates(double x[], double f[]) SurfaceInfil = MIN(SurfaceInfil, maxRate); } - //... storage & soil layers are full - else if ( soilTheta >= soilPorosity && storageDepth >= storageThickness ) + else { - //... limiting rate is smaller of soil perc and storage outflow - maxRate = StorageExfil + StorageDrain; - if ( SoilPerc < maxRate ) + //... storage & soil layers are full + if ( soilTheta >= soilPorosity && storageDepth >= storageThickness ) { - maxRate = SoilPerc; - if ( maxRate > StorageExfil ) StorageDrain = maxRate - StorageExfil; - else + //... limiting rate is smaller of soil perc and storage outflow + maxRate = StorageExfil + StorageDrain; + if ( SoilPerc < maxRate ) { - StorageExfil = maxRate; - StorageDrain = 0.0; + maxRate = SoilPerc; + if ( maxRate > StorageExfil ) StorageDrain = maxRate - StorageExfil; + else + { + StorageExfil = maxRate; + StorageDrain = 0.0; + } } - } - else SoilPerc = maxRate; - - //... apply limiting rate to surface infil. - SurfaceInfil = MIN(SurfaceInfil, maxRate); - } + else SoilPerc = maxRate; - //... either layer not full - else if ( storageThickness > 0.0 ) - { - //... limit storage exfiltration by available storage volume - maxRate = SoilPerc - StorageEvap + storageDepth*storageVoidFrac/Tstep; - StorageExfil = MIN(StorageExfil, maxRate); - StorageExfil = MAX(StorageExfil, 0.0); + //... apply limiting rate to surface infil. + SurfaceInfil = MIN(SurfaceInfil, maxRate); + } - //... limit underdrain flow by volume above drain offset - if ( StorageDrain > 0.0 ) + //... either layer not full + else { - maxRate = -StorageExfil - StorageEvap; - if ( storageDepth >= storageThickness) maxRate += SoilPerc; - if ( theLidProc->drain.offset <= storageDepth ) + //... limit storage exfiltration by available storage volume + maxRate = SoilPerc - StorageEvap + storageDepth*storageVoidFrac/Tstep; + StorageExfil = MIN(StorageExfil, maxRate); + StorageExfil = MAX(StorageExfil, 0.0); + + //... limit underdrain flow by volume above drain offset + if ( StorageDrain > 0.0 ) { - maxRate += (storageDepth - theLidProc->drain.offset) * - storageVoidFrac/Tstep; + maxRate = -StorageExfil - StorageEvap; + if ( storageDepth >= storageThickness) maxRate += SoilPerc; + if ( theLidProc->drain.offset <= storageDepth ) + { + maxRate += (storageDepth - theLidProc->drain.offset) * + storageVoidFrac/Tstep; + } + maxRate = MAX(maxRate, 0.0); + StorageDrain = MIN(StorageDrain, maxRate); } - maxRate = MAX(maxRate, 0.0); - StorageDrain = MIN(StorageDrain, maxRate); - } - - //... limit soil perc by unused storage volume - maxRate = StorageExfil + StorageDrain + StorageEvap + - (storageThickness - storageDepth) * - storageVoidFrac/Tstep; - SoilPerc = MIN(SoilPerc, maxRate); + + //... limit soil perc by unused storage volume + maxRate = StorageExfil + StorageDrain + StorageEvap + + (storageThickness - storageDepth) * + storageVoidFrac/Tstep; + SoilPerc = MIN(SoilPerc, maxRate); - //... limit surface infil. by unused soil volume - maxRate = (soilPorosity - soilTheta) * soilThickness / Tstep + - SoilPerc + SoilEvap; - SurfaceInfil = MIN(SurfaceInfil, maxRate); + //... limit surface infil. by unused soil volume + maxRate = (soilPorosity - soilTheta) * soilThickness / Tstep + + SoilPerc + SoilEvap; + SurfaceInfil = MIN(SurfaceInfil, maxRate); + } } - + //... find surface layer outflow rate SurfaceOutflow = getSurfaceOutflowRate(surfaceDepth); @@ -803,7 +811,7 @@ void trenchFluxRates(double x[], double f[]) SurfaceOutflow = getSurfaceOutflowRate(surfaceDepth); // ... find net fluxes for each layer - f[SURF] = SurfaceInflow - SurfaceEvap - StorageInflow - SurfaceOutflow / + f[SURF] = (SurfaceInflow - SurfaceEvap - StorageInflow - SurfaceOutflow) / theLidProc->surface.voidFrac;; f[STOR] = (StorageInflow - StorageEvap - StorageExfil - StorageDrain) / theLidProc->storage.voidFrac; @@ -966,6 +974,7 @@ void pavementFluxRates(double x[], double f[]) StorageExfil = MIN(StorageExfil, SoilPerc); StorageDrain = SoilPerc - StorageExfil; } + PavePerc = MIN(PavePerc, SoilPerc); //... limit surface infil. by available pavement volume availVolume = (paveThickness - paveDepth) * paveVoidFrac; @@ -981,6 +990,8 @@ void pavementFluxRates(double x[], double f[]) PavePerc = MIN(PavePerc, SoilPerc); SoilPerc = PavePerc; SurfaceInfil = MIN(SurfaceInfil,PavePerc); + maxRate = MAX(StorageVolume / Tstep + SoilPerc - StorageEvap, 0.0); + StorageExfil = MIN(StorageExfil, maxRate); } //... no adjoining layers are full @@ -1370,7 +1381,11 @@ double getStorageDrainRate(double storageDepth, double soilTheta, // depth in layer above it if ( soilTheta >= soilPorosity ) { - if ( paveThickness > 0.0 ) head += paveDepth; + if ( paveThickness > 0.0 ) + { + head += paveDepth; + if ( paveDepth >= paveThickness ) head += surfaceDepth; + } else head += surfaceDepth; } } @@ -1378,7 +1393,7 @@ double getStorageDrainRate(double storageDepth, double soilTheta, // --- no soil layer so increase head by water level in pavement // layer and possibly surface layer - if ( paveThickness > 0.0 ) + else if ( paveThickness > 0.0 ) { head += paveDepth; if ( paveDepth >= paveThickness ) head += surfaceDepth; diff --git a/src/solver/street.c b/src/solver/street.c index fd05451b7..0c55d9115 100644 --- a/src/solver/street.c +++ b/src/solver/street.c @@ -3,11 +3,14 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 11/01/21 (Build 5.2.0) +// Date: 07/13/23 (Build 5.2.4) // Author: L. Rossman // // Street Cross-Section Functions // +// Build 5.2.4: +// - Fixed incorrect index used to retrieve street backing parameters +// in street_readParams. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -106,8 +109,8 @@ int street_readParams(char* tok[], int ntoks) // --- read street backing parameters if (ntoks > 8) { - if (!getDouble(tok[8], &x[8]) || x[k] < 0.0) - return error_setInpError(ERR_NUMBER, tok[k]); + if (!getDouble(tok[8], &x[8]) || x[8] < 0.0) + return error_setInpError(ERR_NUMBER, tok[8]); if (x[8] > 0.0) { if (ntoks < 11) return error_setInpError(ERR_ITEMS, ""); diff --git a/src/solver/surfqual.c b/src/solver/surfqual.c index aa17ed644..4b1a2f7d3 100644 --- a/src/solver/surfqual.c +++ b/src/solver/surfqual.c @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 11/01/21 (Build 5.2.0) +// Date: 07/14/23 (Build 5.2.4) // Author: L. Rossman // // Subcatchment water quality functions. @@ -16,6 +16,10 @@ // - Support for separate accounting of LID drain flows included. // Build 5.1.014: // - Fixed bug in computing effective BMP removal by LIDs. +// Build 5.2.4: +// - Set low runoff flow concentrations to zero before computing runoff +// mass loads rather than after so that they match wet weather mass +// inflows reported for conveyance system nodes. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -253,7 +257,7 @@ void surfqual_getWashoff(int j, double runoff, double tStep) { // --- convert washoff load to a concentration cOut = 0.0; - if ( vOut1 > 0.0 ) cOut = OutflowLoad[p] / vOut1; + if ( vOut1 > 0.0 && hasOutflow ) cOut = OutflowLoad[p] / vOut1; // --- assign any difference between pre- and post-LID // subcatchment outflow loads to BMP removal @@ -279,7 +283,6 @@ void surfqual_getWashoff(int j, double runoff, double tStep) } // --- save new washoff concentration - if ( !hasOutflow ) cOut = 0.0; Subcatch[j].newQual[p] = cOut / LperFT3; } diff --git a/src/solver/transect.c b/src/solver/transect.c index 831ba017f..6ebd25558 100644 --- a/src/solver/transect.c +++ b/src/solver/transect.c @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 11/01/21 (Build 5.2.0) +// Date: 07/13/23 (Build 5.2.4) // Author: L. Rossman // // Geometry processing for irregular cross-section transects. @@ -12,6 +12,8 @@ // ============== // Build 5.2.0: // - Function added to create a transect for a Street cross-section. +// Build 5.2.4: +// - Corrected street transect points in transect_createStreetTransect. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -610,8 +612,8 @@ void transect_createStreetTransect(TStreet* street) w2 = street->gutterWidth; w3 = street->width; w4 = w3 - w2; - y3 = street->gutterDepression; - y1 = street->curbHeight + y3; + y3 = street->gutterDepression + street->slope * w2; + y1 = street->curbHeight + street->gutterDepression; ymax = street->backSlope * street->backWidth + y1; y4 = y3 + street->slope * w4; ymax = MAX(ymax, y4);