diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 2e2d3ee1f..c224b9e7d 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -144,7 +144,7 @@ jobs: - name: Before reg test env: NRTESTS_URL: https://github.com/OpenWaterAnalytics/swmm-nrtestsuite - BENCHMARK_TAG: v3.0.0 + BENCHMARK_TAG: v3.0.1 run: ./${{ matrix.before_reg_test }} ${{ env.BENCHMARK_TAG }} - name: Run reg test diff --git a/CMakeLists.txt b/CMakeLists.txt index d73d30e59..b7ebd6629 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ # CMakeLists.txt - CMake configuration file for swmm-solver # # Created: July 11, 2019 -# Updated: May 19, 2021 +# Modified: Aug 16, 2022 # # Authors: Michael E. Tryby # US EPA ORD/CESER @@ -22,7 +22,7 @@ endif() project(swmm-solver - VERSION 5.2.1 + VERSION 5.2.3 LANGUAGES C CXX ) diff --git a/README.md b/README.md index e5c747a1b..8ec778bbd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Stormwater-Management-Model -ORD Stormwater Management Model (aka "SWMM") +Stormwater Management Model (aka "SWMM") solver only ## Introduction This is the open source SWMM source code repository maintained by the Open diff --git a/src/solver/consts.h b/src/solver/consts.h index 23000bbdb..3cf490793 100644 --- a/src/solver/consts.h +++ b/src/solver/consts.h @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 06/01/22 (Build 5.2.1) +// Date: 02/12/23 (Build 5.2.3) // Author: L. Rossman // // Various Constants @@ -17,7 +17,7 @@ //------------------ // OWA Version string stored in version.h -// #define VERSION 52001 +// #define VERSION 52003 #define MAGICNUMBER 516114522 #define EOFMARK 0x1A // Use 0x04 for UNIX systems #define MAXTITLE 3 // Max. # title lines diff --git a/src/solver/controls.c b/src/solver/controls.c index 34e3612cc..b46054006 100644 --- a/src/solver/controls.c +++ b/src/solver/controls.c @@ -1198,8 +1198,8 @@ void updateActionList(struct TAction* a) listItem->next = ActionList; ActionList = listItem; } - listItem->action = a; - } + listItem->action = a; +} //============================================================================= diff --git a/src/solver/enums.h b/src/solver/enums.h index 22b514274..b1946778c 100644 --- a/src/solver/enums.h +++ b/src/solver/enums.h @@ -116,18 +116,18 @@ // Cross section shape types //------------------------------------- enum XsectType { - DUMMY, // 0 + DUMMY, // 0 CIRCULAR, // 1 closed FILLED_CIRCULAR, // 2 closed RECT_CLOSED, // 3 closed - RECT_OPEN, // 4 - TRAPEZOIDAL, // 5 - TRIANGULAR, // 6 + RECT_OPEN, // 4 + TRAPEZOIDAL, // 5 + TRIANGULAR, // 6 PARABOLIC, // 7 - POWERFUNC, // 8 - RECT_TRIANG, // 9 + POWERFUNC, // 8 + RECT_TRIANG, // 9 RECT_ROUND, // 10 - MOD_BASKET, // 11 + MOD_BASKET, // 11 HORIZ_ELLIPSE, // 12 closed VERT_ELLIPSE, // 13 closed ARCH, // 14 closed @@ -197,7 +197,7 @@ //------------------------------------- // Computed node quantities //------------------------------------- - #define MAX_NODE_RESULTS 7 + #define MAX_NODE_RESULTS 7 enum NodeResultType { NODE_DEPTH, // water depth above invert NODE_HEAD, // hydraulic head @@ -418,7 +418,7 @@ enum CompatibilityType { enum PumpCurveType { TYPE1_PUMP, // flow varies stepwise with wet well volume - TYPE2_PUMP, // flow varies stepwise with inlet depth + TYPE2_PUMP, // flow varies stepwise with inlet depth TYPE3_PUMP, // flow varies with head delivered TYPE4_PUMP, // flow varies with inlet depth TYPE5_PUMP, // variable speed version of TYPE3 pump diff --git a/src/solver/funcs.h b/src/solver/funcs.h index aad84fc04..21af0d54d 100644 --- a/src/solver/funcs.h +++ b/src/solver/funcs.h @@ -93,7 +93,7 @@ void report_writeTimeStepStats(TTimeStepStats* timeStepStats); void report_writeErrorMsg(int code, char* msg); void report_writeErrorCode(void); void report_writeInputErrorMsg(int k, int sect, char* line, long lineCount); -void report_writeWarningMsg(char* msg, char* id); +void report_writeWarningMsg(char* msg, char* id); void report_writeTseriesErrorMsg(int code, TTable *tseries); void inputrpt_writeInput(void); @@ -270,7 +270,7 @@ void massbal_addSeepageLoss(int pollut, double seepLoss); void massbal_addToFinalStorage(int pollut, double mass); double massbal_getStepFlowError(void); double massbal_getRunoffError(void); -double massbal_getFlowError(void); +double massbal_getFlowError(char isFinalStorage); // OWA EDIT - added isFinalStorage param to allow running flow error calcs //----------------------------------------------------------------------------- // Simulation Statistics Methods @@ -496,7 +496,7 @@ void controls_addToCount(char* s); int controls_addVariable(char* tok[], int ntoks); int controls_addExpression(char* tok[], int ntoks); int controls_addRuleClause(int rule, int keyword, char* Tok[], int nTokens); -int controls_evaluate(DateTime currentTime, DateTime elapsedTime, +int controls_evaluate(DateTime currentTime, DateTime elapsedTime, double tStep); //----------------------------------------------------------------------------- diff --git a/src/solver/gage.c b/src/solver/gage.c index 84e0af2da..d8e4e2b4f 100644 --- a/src/solver/gage.c +++ b/src/solver/gage.c @@ -406,7 +406,7 @@ void gage_setState(int j, DateTime t) // --- otherwise update next rainfall interval date Gage[j].startDate = Gage[j].nextDate; Gage[j].endDate = datetime_addSeconds(Gage[j].startDate, - Gage[j].rainInterval); + Gage[j].rainInterval); Gage[j].rainfall = Gage[j].nextRainfall; if ( !getNextRainfall(j) ) Gage[j].nextDate = NO_DATE; } @@ -670,11 +670,11 @@ int getNextRainfall(int j) { if ( Frain.file && Gage[j].currentFilePos < Gage[j].endFilePos ) { - fseek(Frain.file, Gage[j].currentFilePos, SEEK_SET); - fread(&Gage[j].nextDate, sizeof(DateTime), 1, Frain.file); - fread(&vNext, sizeof(float), 1, Frain.file); - Gage[j].currentFilePos = ftell(Frain.file); - rNext = convertRainfall(j, (double)vNext); + fseek(Frain.file, Gage[j].currentFilePos, SEEK_SET); + fread(&Gage[j].nextDate, sizeof(DateTime), 1, Frain.file); + fread(&vNext, sizeof(float), 1, Frain.file); + Gage[j].currentFilePos = ftell(Frain.file); + rNext = convertRainfall(j, (double)vNext); } else return 0; } @@ -684,9 +684,9 @@ int getNextRainfall(int j) k = Gage[j].tSeries; if ( k >= 0 ) { - if ( !table_getNextEntry(&Tseries[k], - &Gage[j].nextDate, &rNext) ) return 0; - rNext = convertRainfall(j, rNext); + if ( !table_getNextEntry(&Tseries[k], + &Gage[j].nextDate, &rNext) ) return 0; + rNext = convertRainfall(j, rNext); } else return 0; } diff --git a/src/solver/globals.h b/src/solver/globals.h index 193903697..cdc04eac3 100644 --- a/src/solver/globals.h +++ b/src/solver/globals.h @@ -19,7 +19,7 @@ // - Minimum dynamic wave routing variable time step added. // Build 5.1.011: // - Changed WarningCode to Warnings (# warnings issued) -// - Added error message text as a variable. +// - Added error message text as a variable. // - Added elapsed simulation time (in decimal days) variable. // - Added variables associated with detailed routing events. // Build 5.1.012: diff --git a/src/solver/include/toolkit.h b/src/solver/include/toolkit.h index ad2bdcdeb..339dbd09a 100644 --- a/src/solver/include/toolkit.h +++ b/src/solver/include/toolkit.h @@ -25,6 +25,7 @@ #include "../enums.h" #include "../datetime.h" #include "../lid.h" +#include "../inlet.h" #ifdef __cplusplus extern "C" { @@ -312,6 +313,24 @@ EXPORT_TOOLKIT int swmm_getLinkParam(int index, SM_LinkProperty param, double *v */ EXPORT_TOOLKIT int swmm_setLinkParam(int index, SM_LinkProperty param, double value); +/** + @brief Get a property value for the inlets of a specified link. + @param index The index of a link + @param Param The property type code (See @ref SM_InletProperty) + @param[out] value The value of the inlet's property + @return Error code +*/ +EXPORT_TOOLKIT int swmm_getInletParam(int index, SM_InletProperty param, double *value); + +/** + @brief Set a property value for the inlets of a specified link. + @param index The index of a link + @param Param The property type code (See @ref SM_InletProperty) + @param value The new value of the inlet's property + @return Error code +*/ +EXPORT_TOOLKIT int swmm_setInletParam(int index, SM_InletProperty param, double value); + /** @brief Get a property value for specified subcatchment. @param index The index of a subcatchment @@ -421,6 +440,17 @@ EXPORT_TOOLKIT int swmm_setLinkPollut(int index, SM_LinkPollut type, int polluta */ EXPORT_TOOLKIT int swmm_getLinkResult(int index, SM_LinkResult type, double *result); +/** + @brief Gets results for the inlets of a specified link. + @param index The index of a link with inlets + @param type The result type code (See @ref SM_InletResult) + @param result Pollutant index to set + @param[out] result The result of the inlet's property + @return Error code +*/ +EXPORT_TOOLKIT int swmm_getInletResult(int index, SM_InletResult type, double *result); + + /** @brief Gets pollutant values for a specified link. @param index The index of a link diff --git a/src/solver/include/toolkit_enums.h b/src/solver/include/toolkit_enums.h index 9b54f7b2d..651743b37 100644 --- a/src/solver/include/toolkit_enums.h +++ b/src/solver/include/toolkit_enums.h @@ -275,5 +275,21 @@ typedef enum { SM_STORAGEDRAIN = 29, /**< Underdrain flow rate layer */ } SM_LidResult; +typedef enum { + SM_INLETNUMINLETS = 0, + SM_INLETCLOGFACTOR = 1, + SM_INLETFLOWLIMIT = 2, + SM_INLETLOCALDEPRESS = 3, + SM_INLETLOCALWIDTH = 4 +} SM_InletProperty; + +typedef enum { + SM_INLETFLOWFACTOR = 0, + SM_INLETFLOWCAPTURE = 1, + SM_INLETBACKFLOW = 2, + SM_INLETBACKFLOWRATIO = 3, + +} SM_InletResult; + #endif /* TOOLKIT_ENUMS_H_ */ diff --git a/src/solver/include/toolkit_error.h b/src/solver/include/toolkit_error.h index 2081edefd..3f58128ec 100644 --- a/src/solver/include/toolkit_error.h +++ b/src/solver/include/toolkit_error.h @@ -13,6 +13,7 @@ enum ToolkitErrorType { ERR_TKAPI_LIDUNIT_INDEX = 2009, ERR_TKAPI_UNDEFINED_LID = 2010, ERR_TKAPI_MEMORY = 2011, + ERR_TKAPI_NO_INLET = 2012, TKMAXERRMSG = 3000 }; diff --git a/src/solver/include/toolkit_errors.txt b/src/solver/include/toolkit_errors.txt index 3a5b9782e..4a9dd1f8e 100644 --- a/src/solver/include/toolkit_errors.txt +++ b/src/solver/include/toolkit_errors.txt @@ -12,3 +12,4 @@ ERR(2008, "\n API Key Error: Invalid Pattern Index") ERR(2009, "\n API Key Error: Invalid Lid Unit Index") ERR(2010, "\n API Key Error: Undefined Subcatchment Lid") ERR(2011, "\n API Key Error: No memory allocated for return value") +ERR(2012, "\n API Key Error: Specified link is not assigned an inlet") diff --git a/src/solver/inlet.c b/src/solver/inlet.c index 1ec914c4d..c44ae9fcb 100644 --- a/src/solver/inlet.c +++ b/src/solver/inlet.c @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 06/01/22 (Build 5.2.1) +// Date: 10/08/22 (Build 5.2.2) // Author: L. Rossman // // Street/Channel Inlet Functions @@ -16,6 +16,8 @@ // // Build 5.2.1: // - Substitutes the constant BIG for HUGE. +// Build 5.2.2: +// - Additional statistics added to Street Flow Summary table. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -68,38 +70,7 @@ typedef struct } TInletDesign; -// Inlet performance statistics -typedef struct -{ - int flowPeriods; // # periods with approach flow - int capturePeriods; // # periods with captured flow - int backflowPeriods; // # periods with backflow - double peakFlow; // peak flow seen by inlet (cfs) - double peakFlowCapture; // capture efficiency at peak flow - double avgFlowCapture; // average capture efficiency - double bypassFreq; // frequency of bypass flow -} TInletStats; - -// Inlet list object -struct TInlet -{ - int linkIndex; // index of conduit link with the inlet - int designIndex; // index of inlet's design - int nodeIndex; // index of node receiving captured flow - int numInlets; // # inlets on each side of street or in channel - int placement; // whether inlet is on-grade or on-sag - double clogFactor; // fractional degree of inlet clogging - double flowLimit; // inlet flow restriction (cfs) - double localDepress; // local gutter depression (ft) - double localWidth; // local depression width (ft) - - double flowFactor; // flow = flowFactor * (flow spread)^2.67 - double flowCapture; // captured flow rate (cfs) - double backflow; // backflow from capture node (cfs) - double backflowRatio; // inlet backflow / capture node overflow - TInletStats stats; // inlet performance statistics - TInlet * nextInlet; // next inlet in list -}; +// OWA EDIT - TInlet and TInletStats struct defs moved to inlet.h to be shared by toolkit.c // Shared inlet variables TInletDesign * InletDesigns; // array of available inlet designs @@ -1030,17 +1001,18 @@ void writeStreetStatsHeader() report_writeLine("*******************"); report_writeLine(""); fprintf(Frpt.file, -"\n ----------------------------------------------------------------------------------------------------------------------" -"\n Peak Maximum Maximum Peak Flow Average Bypass BackFlow" -"\n Flow Spread Depth Inlet Inlet Capture Capture Frequency Frequency"); +"\n ---------------------------------------------------------------------------------------------------------------------------------------" +"\n Peak Avg. Bypass Back Peak Peak" +"\n Peak Maximum Maximum Flow Flow Flow Flow Capture Bypass" +"\n Flow Spread Depth Inlet Inlet Inlet Capture Capture Freq Freq / Inlet Flow"); if (UnitSystem == US) fprintf(Frpt.file, -"\n Street Conduit %3s ft ft Design Location %% %% %% %%", - FlowUnitWords[FlowUnits]); +"\n Street Conduit %3s ft ft Design Location Count Pcnt Pcnt Pcnt Pcnt %3s %3s", + FlowUnitWords[FlowUnits], FlowUnitWords[FlowUnits], FlowUnitWords[FlowUnits]); else fprintf(Frpt.file, -"\n Street Conduit %3s m m Design Location %% %% %% %%", - FlowUnitWords[FlowUnits]); +"\n Street Conduit %3s m m Design Location Pcnt Pcnt Pcnt Pcnt %3s %3s", + FlowUnitWords[FlowUnits], FlowUnitWords[FlowUnits], FlowUnitWords[FlowUnits]); fprintf(Frpt.file, -"\n ----------------------------------------------------------------------------------------------------------------------"); +"\n ---------------------------------------------------------------------------------------------------------------------------------------"); } //============================================================================= @@ -1095,19 +1067,24 @@ void writeStreetStats(int link) fprintf(Frpt.file, " ON-GRADE"); else fprintf(Frpt.file, " ON-SAG "); + fprintf(Frpt.file, " %5d", inlet->numInlets); fp = inlet->stats.flowPeriods / 100.0; if (fp > 0.0) { cp = inlet->stats.capturePeriods / 100.0; - fprintf(Frpt.file, " %9.2f", inlet->stats.peakFlowCapture); + fprintf(Frpt.file, " %7.2f", inlet->stats.peakFlowCapture); if (cp > 0.0) { afc = inlet->stats.avgFlowCapture / cp; bpf = inlet->stats.bypassFreq / cp; } - fprintf(Frpt.file, " %9.2f", afc); - fprintf(Frpt.file, " %9.2f", bpf); - fprintf(Frpt.file, " %9.2f", inlet->stats.backflowPeriods / fp); + fprintf(Frpt.file, " %7.2f", afc); + fprintf(Frpt.file, " %7.2f", bpf); + fprintf(Frpt.file, " %7.2f", inlet->stats.backflowPeriods / fp); + fprintf(Frpt.file, " %7.2f", (maxFlow / Street[t].sides) * UCF(FLOW) * + 0.01 * inlet->stats.peakFlowCapture / inlet->numInlets); + fprintf(Frpt.file, " %7.2f", maxFlow * UCF(FLOW) * 0.01 * + (100.0 - inlet->stats.peakFlowCapture)); } } } diff --git a/src/solver/inlet.h b/src/solver/inlet.h index ca7830725..52b6dcb54 100644 --- a/src/solver/inlet.h +++ b/src/solver/inlet.h @@ -27,4 +27,39 @@ void inlet_adjustQualOutflows(); void inlet_writeStatsReport(); double inlet_capturedFlow(int link); +// OWA EDIT ################################################################################## +// TInlet and TInletStats struct defs moved to inlet.h to be shared by toolkit.c +typedef struct +{ + int flowPeriods; // # periods with approach flow + int capturePeriods; // # periods with captured flow + int backflowPeriods; // # periods with backflow + double peakFlow; // peak flow seen by inlet (cfs) + double peakFlowCapture; // capture efficiency at peak flow + double avgFlowCapture; // average capture efficiency + double bypassFreq; // frequency of bypass flow +} TInletStats; + +// Inlet list object +struct TInlet +{ + int linkIndex; // index of conduit link with the inlet + int designIndex; // index of inlet's design + int nodeIndex; // index of node receiving captured flow + int numInlets; // # inlets on each side of street or in channel + int placement; // whether inlet is on-grade or on-sag + double clogFactor; // fractional degree of inlet clogging + double flowLimit; // inlet flow restriction (cfs) + double localDepress; // local gutter depression (ft) + double localWidth; // local depression width (ft) + + double flowFactor; // flow = flowFactor * (flow spread)^2.67 + double flowCapture; // captured flow rate (cfs) + double backflow; // backflow from capture node (cfs) + double backflowRatio; // inlet backflow / capture node overflow + TInletStats stats; // inlet performance statistics + TInlet * nextInlet; // next inlet in list +}; +// ########################################################################################### + #endif diff --git a/src/solver/lid.c b/src/solver/lid.c index d9a0c7e78..a6e82e16c 100644 --- a/src/solver/lid.c +++ b/src/solver/lid.c @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 11/01/21 (Build 5.2.0) +// Date: 02/10/23 (Build 5.2.3) // Author: L. Rossman // // This module handles all data processing involving LID (Low Impact @@ -57,7 +57,7 @@ // - Redefined initialization of wasDry for LID reporting. // Build 5.1.013: // - Support added for LID units treating pervious area runoff. -// - Support added for open/closed head levels and multiplier v. head +// - Support added for open/closed head levels and multiplier v. head // control curve for underdrain flow. // - Support added for unclogging permeable pavement at fixed intervals. // - Support added for pollutant removal in underdrain flow. @@ -68,6 +68,8 @@ // - Support added for mutiple infiltration methods within a project. // Build 5.2.0: // - Covered property added to RAIN_BARREL parameters +// Build 5.2.3 +// - Fixed double counting of initial water volume in green roof drain mat. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -97,7 +99,7 @@ enum LidLayerTypes { REMOVALS}; // pollutant removals //// Note: DRAINMAT must be placed before DRAIN so the two keywords can -/// be distinguished from one another when parsing a line of input. +/// be distinguished from one another when parsing a line of input. char* LidLayerWords[] = {"SURFACE", "SOIL", "STORAGE", "PAVEMENT", "DRAINMAT", "DRAIN", @@ -134,7 +136,7 @@ static double MaxNativeInfil; // native soil infil. rate limit (ft/s) //----------------------------------------------------------------------------- // Imported Variables (from SUBCATCH.C) //----------------------------------------------------------------------------- -// Volumes (ft3) for a subcatchment over a time step +// Volumes (ft3) for a subcatchment over a time step extern double Vevap; // evaporation extern double Vpevap; // pervious area evaporation extern double Vinfil; // non-LID infiltration @@ -249,7 +251,7 @@ void lid_create(int lidCount, int subcatchCount) //... initialize LID groups for (j = 0; j < GroupCount; j++) LidGroups[j] = NULL; - + //... create LID objects if ( LidCount == 0 ) return; LidProcs = (TLidProc *) calloc(LidCount, sizeof(TLidProc)); @@ -543,7 +545,7 @@ int addLidUnit(int j, int k, int n, double x[], char* fname, //... open report file if it was supplied if ( fname != NULL ) { - if ( !createLidRptFile(lidUnit, fname) ) + if ( !createLidRptFile(lidUnit, fname) ) return error_setInpError(ERR_RPT_FILE, fname); } return 0; @@ -554,7 +556,7 @@ int addLidUnit(int j, int k, int n, double x[], char* fname, int createLidRptFile(TLidUnit* lidUnit, char* fname) { TLidRptFile* rptFile; - + rptFile = (TLidRptFile *) malloc(sizeof(TLidRptFile)); if ( rptFile == NULL ) return 0; lidUnit->rptFile = rptFile; @@ -569,7 +571,7 @@ int readSurfaceData(int j, char* toks[], int ntoks) // // Purpose: reads surface layer data for a LID process from line of input // data file -// Input: j = LID process index +// Input: j = LID process index // toks = array of string tokens // ntoks = number of tokens // Output: returns error code @@ -587,7 +589,7 @@ int readSurfaceData(int j, char* toks[], int ntoks) if ( ! getDouble(toks[i], &x[i-2]) || x[i-2] < 0.0 ) return error_setInpError(ERR_NUMBER, toks[i]); } - if ( x[1] >= 1.0 ) return error_setInpError(ERR_NUMBER, toks[3]); + if ( x[1] >= 1.0 ) return error_setInpError(ERR_NUMBER, toks[3]); if ( x[0] == 0.0 ) x[1] = 0.0; LidProcs[j].surface.thickness = x[0] / UCF(RAINDEPTH); @@ -604,7 +606,7 @@ int readPavementData(int j, char* toks[], int ntoks) // // Purpose: reads pavement layer data for a LID process from line of input // data file -// Input: j = LID process index +// Input: j = LID process index // toks = array of string tokens // ntoks = number of tokens // Output: returns error code @@ -672,7 +674,7 @@ int readSoilData(int j, char* toks[], int ntoks) // // Purpose: reads soil layer data for a LID process from line of input // data file -// Input: j = LID process index +// Input: j = LID process index // toks = array of string tokens // ntoks = number of tokens // Output: returns error code @@ -706,7 +708,7 @@ int readStorageData(int j, char* toks[], int ntoks) // // Purpose: reads drainage layer data for a LID process from line of input // data file -// Input: j = LID process index +// Input: j = LID process index // toks = array of string tokens // ntoks = number of tokens // Output: returns error code @@ -760,14 +762,14 @@ int readStorageData(int j, char* toks[], int ntoks) LidProcs[j].storage.covered = covered; return 0; } - + //============================================================================= int readDrainData(int j, char* toks[], int ntoks) // // Purpose: reads underdrain data for a LID process from line of input // data file -// Input: j = LID process index +// Input: j = LID process index // toks = array of string tokens // ntoks = number of tokens // Output: returns error code @@ -805,14 +807,14 @@ int readDrainData(int j, char* toks[], int ntoks) LidProcs[j].drain.qCurve = i; return 0; } - + //============================================================================= int readDrainMatData(int j, char* toks[], int ntoks) // // Purpose: reads drainage mat data for a LID process from line of input // data file -// Input: j = LID process index +// Input: j = LID process index // toks = array of string tokens // ntoks = number of tokens // Output: returns error code @@ -846,7 +848,7 @@ int readRemovalsData(int j, char* toks[], int ntoks) // // Purpose: reads pollutant removal data for a LID process from line of input // data file -// Input: j = LID process index +// Input: j = LID process index // toks = array of string tokens // ntoks = number of tokens // Output: returns error code @@ -895,7 +897,7 @@ void lid_writeSummary() TLidUnit* lidUnit; TLidList* lidList; TLidGroup lidGroup; - + fprintf(Frpt.file, "\n"); fprintf(Frpt.file, "\n"); fprintf(Frpt.file, "\n *******************"); @@ -935,7 +937,7 @@ void lid_writeSummary() void lid_validate() // // Purpose: validates LID process and group parameters. -// Input: none +// Input: none // Output: none // { @@ -949,7 +951,7 @@ void lid_validate() void validateLidProc(int j) // // Purpose: validates LID process parameters. -// Input: j = LID process index +// Input: j = LID process index // Output: none // { @@ -970,7 +972,7 @@ void validateLidProc(int j) if ( LidProcs[j].soil.thickness <= 0.0 ) layerMissing = TRUE; break; case GREEN_ROOF: - if ( LidProcs[j].soil.thickness <= 0.0 ) layerMissing = TRUE; + if ( LidProcs[j].soil.thickness <= 0.0 ) layerMissing = TRUE; if ( LidProcs[j].drainMat.thickness <= 0.0) layerMissing = TRUE; break; case POROUS_PAVEMENT: @@ -989,8 +991,8 @@ void validateLidProc(int j) //... check pavement layer parameters if ( LidProcs[j].lidType == POROUS_PAVEMENT ) { - if ( LidProcs[j].pavement.thickness <= 0.0 - || LidProcs[j].pavement.kSat <= 0.0 + if ( LidProcs[j].pavement.thickness <= 0.0 + || LidProcs[j].pavement.kSat <= 0.0 || LidProcs[j].pavement.voidFrac <= 0.0 || LidProcs[j].pavement.voidFrac > 1.0 || LidProcs[j].pavement.impervFrac > 1.0 ) @@ -1005,7 +1007,7 @@ void validateLidProc(int j) //... check soil layer parameters if ( LidProcs[j].soil.thickness > 0.0 ) { - if ( LidProcs[j].soil.porosity <= 0.0 + if ( LidProcs[j].soil.porosity <= 0.0 || LidProcs[j].soil.fieldCap >= LidProcs[j].soil.porosity || LidProcs[j].soil.wiltPoint >= LidProcs[j].soil.fieldCap || LidProcs[j].soil.kSat <= 0.0 @@ -1029,9 +1031,9 @@ void validateLidProc(int j) } } - //... if no storage layer adjust void fraction and drain offset + //... if no storage layer adjust void fraction and drain offset else - { + { LidProcs[j].storage.voidFrac = 1.0; LidProcs[j].drain.offset = 0.0; } @@ -1048,7 +1050,7 @@ void validateLidProc(int j) //... compute the surface layer's overland flow constant (alpha) if ( LidProcs[j].lidType == VEG_SWALE ) { - if ( LidProcs[j].surface.roughness * + if ( LidProcs[j].surface.roughness * LidProcs[j].surface.surfSlope <= 0.0 || LidProcs[j].surface.thickness == 0.0 ) @@ -1057,7 +1059,7 @@ void validateLidProc(int j) sstrcat(Msg, ERR_SWALE_SURF, MAXMSG); report_writeErrorMsg(ERR_LID_PARAMS, Msg); } - else LidProcs[j].surface.alpha = + else LidProcs[j].surface.alpha = 1.49 * sqrt(LidProcs[j].surface.surfSlope) / LidProcs[j].surface.roughness; } @@ -1104,7 +1106,7 @@ void validateLidProc(int j) LidProcs[j].storage.kSat = 0.0; } - //... set storage layer parameters of a green roof + //... set storage layer parameters of a green roof if ( LidProcs[j].lidType == GREEN_ROOF ) { LidProcs[j].storage.thickness = LidProcs[j].drainMat.thickness; @@ -1119,7 +1121,7 @@ void validateLidProc(int j) void validateLidGroup(int j) // // Purpose: validates properties of LID units grouped in a subcatchment. -// Input: j = subcatchment index +// Input: j = subcatchment index // Output: returns 1 if data are valid, 0 if not // { @@ -1161,7 +1163,7 @@ void validateLidGroup(int j) report_writeErrorMsg(ERR_LID_PARAMS, Msg); } } - + //... assign vegetative swale infiltration parameters if ( LidProcs[k].lidType == VEG_SWALE ) { @@ -1217,7 +1219,7 @@ void validateLidGroup(int j) void lid_initState() // // Purpose: initializes the internal state of each LID in a subcatchment. -// Input: none +// Input: none // Output: none // { @@ -1258,7 +1260,7 @@ void lid_initState() initVol = 0.0; if ( LidProcs[k].soil.thickness > 0.0 ) { - lidUnit->soilMoisture = LidProcs[k].soil.wiltPoint + + lidUnit->soilMoisture = LidProcs[k].soil.wiltPoint + lidUnit->initSat * (LidProcs[k].soil.porosity - LidProcs[k].soil.wiltPoint); initVol += lidUnit->soilMoisture * LidProcs[k].soil.thickness; @@ -1269,12 +1271,6 @@ void lid_initState() LidProcs[k].storage.thickness; initVol += lidUnit->storageDepth * LidProcs[k].storage.voidFrac; } - if ( LidProcs[k].drainMat.thickness > 0.0 ) - { - lidUnit->storageDepth = lidUnit->initSat * - LidProcs[k].drainMat.thickness; - initVol += lidUnit->storageDepth * LidProcs[k].drainMat.voidFrac; - } if ( lidUnit->initSat > 0.0 ) HasWetLids = TRUE; //... initialize water balance totals @@ -1298,7 +1294,7 @@ void lid_initState() //... set previous flux rates to 0 for (i = 0; i < MAX_LAYERS; i++) - { + { lidUnit->oldFluxRates[i] = 0.0; } @@ -1319,7 +1315,7 @@ void lid_initState() void lid_setOldGroupState(int j) // // Purpose: saves the current drain flow rate for the LIDs in a subcatchment. -// Input: j = subcatchment index +// Input: j = subcatchment index // Output: none // { @@ -1343,7 +1339,7 @@ void lid_setOldGroupState(int j) int isLidPervious(int k) // // Purpose: determines if a LID process allows infiltration or not. -// Input: k = LID process index +// Input: k = LID process index // Output: returns 1 if process is pervious or 0 if not // { @@ -1357,7 +1353,7 @@ double getSurfaceDepth(int j) // // Purpose: computes the depth (volume per unit area) of ponded water on the // surface of all LIDs within a subcatchment. -// Input: j = subcatchment index +// Input: j = subcatchment index // Output: returns volumetric depth of ponded water (ft) // { @@ -1413,9 +1409,9 @@ double lid_getFlowToPerv(int j) double lid_getStoredVolume(int j) // -// Purpose: computes stored volume of water for all LIDs +// Purpose: computes stored volume of water for all LIDs // grouped within a subcatchment. -// Input: j = subcatchment index +// Input: j = subcatchment index // Output: returns stored volume of water (ft3) // { @@ -1442,7 +1438,7 @@ double lid_getDrainFlow(int j, int timePeriod) // // Purpose: returns flow from all of a subcatchment's LID drains for // a designated time period -// Input: j = subcatchment index +// Input: j = subcatchment index // timePeriod = either PREVIOUS or CURRENT // Output: total drain flow (cfs) from the subcatchment. { @@ -1468,11 +1464,11 @@ void lid_addDrainLoads(int j, double c[], double tStep) { int isRunoffLoad; // true if drain becomes external runoff load int p; // pollutant index - double r; // pollutant fractional removal + double r; // pollutant fractional removal double w; // pollutant mass load (lb or kg) TLidUnit* lidUnit; - TLidList* lidList; - TLidGroup lidGroup; + TLidList* lidList; + TLidGroup lidGroup; //... check if LID group exists lidGroup = LidGroups[j]; @@ -1483,11 +1479,11 @@ void lid_addDrainLoads(int j, double c[], double tStep) while ( lidList ) { lidUnit = lidList->lidUnit; - + //... see if unit's drain flow becomes external runoff isRunoffLoad = (lidUnit->drainNode >= 0 || lidUnit->drainSubcatch == j); - + //... for each pollutant not routed back on to subcatchment surface if (!lidUnit->toPerv) for (p = 0; p < Nobjects[POLLUT]; p++) { @@ -1514,7 +1510,7 @@ void lid_addDrainLoads(int j, double c[], double tStep) void lid_addDrainRunon(int j) // // Purpose: adds drain flows from LIDs in a given subcatchment to the -// subcatchments that were designated to receive them +// subcatchments that were designated to receive them // Input: j = index of subcatchment contributing underdrain flows // Output: none. // @@ -1525,8 +1521,8 @@ void lid_addDrainRunon(int j) double q; // drain flow rate (cfs) double w; // mass of polllutant from drain flow TLidUnit* lidUnit; - TLidList* lidList; - TLidGroup lidGroup; + TLidList* lidList; + TLidGroup lidGroup; //... check if LID group exists lidGroup = LidGroups[j]; @@ -1565,7 +1561,7 @@ void lid_addDrainRunon(int j) void lid_addDrainInflow(int j, double f) // -// Purpose: adds LID drain flow to conveyance system nodes +// Purpose: adds LID drain flow to conveyance system nodes // Input: j = subcatchment index // f = time interval weighting factor // Output: none. @@ -1602,12 +1598,12 @@ void lid_addDrainInflow(int j, double f) Node[k].newLatFlow += q; massbal_addInflowFlow(WET_WEATHER_INFLOW, q); - //... add pollutant load, based on parent subcatchment quality + //... add pollutant load, based on parent subcatchment quality for (p = 0; p < Nobjects[POLLUT]; p++) { //... get previous & current drain loads w1 = lidUnit->oldDrainFlow * Subcatch[j].oldQual[p]; - w2 = lidUnit->newDrainFlow * Subcatch[j].newQual[p]; + w2 = lidUnit->newDrainFlow * Subcatch[j].newQual[p]; //... add interpolated load to node's wet weather loading w = (1.0 - f) * w1 + f * w2; @@ -1626,7 +1622,7 @@ void lid_addDrainInflow(int j, double f) void lid_getRunoff(int j, double tStep) // // Purpose: computes runoff and drain flows from the LIDs in a subcatchment. -// Input: j = subcatchment index +// Input: j = subcatchment index // tStep = time step (sec) // Output: updates following global quantities after LID treatment applied: // Vevap, Vpevap, VlidInfil, VlidIn, VlidOut, VlidDrain. @@ -1641,7 +1637,7 @@ void lid_getRunoff(int j, double tStep) double lidInflow = 0.0; // inflow to an LID unit (ft/s) double qRunoff = 0.0; // surface runoff from all LID units (cfs) double qDrain = 0.0; // drain flow from all LID units (cfs) - double qReturn = 0.0; // LID outflow returned to pervious area (cfs) + double qReturn = 0.0; // LID outflow returned to pervious area (cfs) //... return if there are no LID's theLidGroup = LidGroups[j]; @@ -1659,7 +1655,7 @@ void lid_getRunoff(int j, double tStep) //... get impervious and pervious area runoff from non-LID // portion of subcatchment (cfs) if ( Subcatch[j].area > Subcatch[j].lidArea ) - { + { qImperv = getImpervAreaRunoff(j); qPerv = getPervAreaRunoff(j); } @@ -1692,7 +1688,7 @@ void lid_getRunoff(int j, double tStep) //... evaluate the LID unit's performance, updating the LID group's // total surface runoff, drain flow, and flow returned to - // pervious area + // pervious area evalLidUnit(j, lidUnit, lidArea, lidInflow, tStep, &qRunoff, &qDrain, &qReturn); } @@ -1704,7 +1700,7 @@ void lid_getRunoff(int j, double tStep) theLidGroup->flowToPerv = qReturn; //... save the LID group's total surface, drain and return flow volumes - VlidOut = qRunoff * tStep; + VlidOut = qRunoff * tStep; VlidDrain = qDrain * tStep; VlidReturn = qReturn * tStep; } @@ -1852,7 +1848,7 @@ void evalLidUnit(int j, TLidUnit* lidUnit, double lidArea, double lidInflow, lidRunoff = lidproc_getOutflow(lidUnit, lidProc, lidInflow, EvapRate, NativeInfil, MaxNativeInfil, tStep, &lidEvap, &lidInfil, &lidDrain) * lidArea; - + //... convert drain flow to CFS lidDrain *= lidArea; @@ -1871,7 +1867,7 @@ void evalLidUnit(int j, TLidUnit* lidUnit, double lidArea, double lidInflow, lidDrain = 0.0; } } - + //... update system flow balance if drain flow goes to a // conveyance system node if ( lidUnit->drainNode >= 0 ) @@ -1939,7 +1935,7 @@ void lid_writeWaterBalance() "\n --------------------------------------------------------------------------------------------------------------------" "\n Total Evap Infil Surface Drain Initial Final Continuity" "\n Inflow Loss Loss Outflow Outflow Storage Storage Error"); - if ( UnitSystem == US ) fprintf(Frpt.file, + if ( UnitSystem == US ) fprintf(Frpt.file, "\n Subcatchment LID Control in in in in in in in %%"); else fprintf(Frpt.file, "\n Subcatchment LID Control mm mm mm mm mm mm mm %%"); @@ -1969,7 +1965,7 @@ void lid_writeWaterBalance() lidUnit->waterBalance.finalVol*ucf); //... compute flow balance error - inflow = lidUnit->waterBalance.initVol + + inflow = lidUnit->waterBalance.initVol + lidUnit->waterBalance.inflow; outflow = lidUnit->waterBalance.finalVol + lidUnit->waterBalance.evap + diff --git a/src/solver/lid.h b/src/solver/lid.h index c3ff11592..565cdb0b4 100644 --- a/src/solver/lid.h +++ b/src/solver/lid.h @@ -15,7 +15,7 @@ // - Support added for separate routing of LID drain flows. // - Detailed LID reporting modified. // Build 5.1.011: -// - Water depth replaces moisture content for LID's pavement layer. +// - Water depth replaces moisture content for LID's pavement layer. // - Arguments for lidproc_saveResults() modified. // Build 5.1.012: // - Redefined meaning of wasDry in TLidRptFile structure. @@ -47,8 +47,8 @@ //----------------------------------------------------------------------------- enum LidTypes { BIO_CELL, // bio-retention cell - RAIN_GARDEN, // rain garden - GREEN_ROOF, // green roof + RAIN_GARDEN, // rain garden + GREEN_ROOF, // green roof INFIL_TRENCH, // infiltration trench POROUS_PAVEMENT, // porous pavement RAIN_BARREL, // rain barrel @@ -69,7 +69,7 @@ typedef struct { double thickness; // depression storage or berm ht. (ft) double voidFrac; // available fraction of storage volume - double roughness; // surface Mannings n + double roughness; // surface Mannings n double surfSlope; // land surface slope (fraction) double sideSlope; // swale side slope (run/rise) double alpha; // slope/roughness term in Manning eqn. @@ -204,7 +204,7 @@ typedef struct int drainNode; // node receiving drain flow TLidRptFile* rptFile; // pointer to detailed report file - TGrnAmpt soilInfil; // infil. object for biocell soil layer + TGrnAmpt soilInfil; // infil. object for biocell soil layer double surfaceDepth; // depth of ponded water on surface layer (ft) double paveDepth; // depth of water in porous pavement layer double soilMoisture; // moisture content of biocell soil layer @@ -212,7 +212,7 @@ typedef struct // net inflow - outflow from previous time step for each LID layer (ft/s) double oldFluxRates[MAX_LAYERS]; - + double dryTime; // time since last rainfall (sec) double oldDrainFlow; // previous drain flow (cfs) double newDrainFlow; // current drain flow (cfs) diff --git a/src/solver/link.c b/src/solver/link.c index b93cdfbaa..052a030b9 100644 --- a/src/solver/link.c +++ b/src/solver/link.c @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 06/01/22 (Build 5.2.1) +// Date: 10/29/22 (Build 5.2.2) // Author: L. Rossman // M. Tryby (EPA) // @@ -44,6 +44,8 @@ // - Support added for variable speed pumps. // Build 5.2.1 // - Warning no longer issued when conduit elevation drop < MIN_DELTA_Z. +// Build 5.2.2: +// - Warning for conduit elevation drop < MIN_DELTA_Z restored. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -1264,9 +1266,7 @@ double conduit_getSlope(int j) delta = fabs(elev1 - elev2); if ( delta < MIN_DELTA_Z ) { - /* Deprecated as of v.5.2.1 report_writeWarningMsg(WARN04, Link[j].ID); - */ delta = MIN_DELTA_Z; } diff --git a/src/solver/massbal.c b/src/solver/massbal.c index 893cf36d6..f6443ffef 100644 --- a/src/solver/massbal.c +++ b/src/solver/massbal.c @@ -298,7 +298,7 @@ void massbal_report() if ( Nobjects[NODE] > 0 && !IgnoreRouting ) { - if ( massbal_getFlowError() > MAX_FLOW_BALANCE_ERR || + if ( massbal_getFlowError(TRUE) > MAX_FLOW_BALANCE_ERR || // OWA EDIT - added isFinalStorage param to massbal_getFlowError RptFlags.continuity == TRUE ) report_writeFlowError(&FlowTotals); @@ -855,9 +855,9 @@ double massbal_getGwaterError() //============================================================================= -double massbal_getFlowError() +double massbal_getFlowError(char isFinalStorage) // OWA EDIT - added isFinalStorage param to allow running flow error calcs // -// Input: none +// Input: isFinalStorage = TRUE if at final time period // Output: none // Purpose: computes flow routing mass balance error. // @@ -866,7 +866,7 @@ double massbal_getFlowError() double totalOutflow; // --- get final volume of nodes and links - FlowTotals.finalStorage = massbal_getStorage(TRUE); + FlowTotals.finalStorage = massbal_getStorage(isFinalStorage); // OWA EDIT - added isFinalStorage param to allow running flow error calcs // --- add contributions to total inflow and outflow that are always positive totalInflow = FlowTotals.initStorage + FlowTotals.wwInflow + FlowTotals.iiInflow; @@ -1052,10 +1052,11 @@ int massbal_getRoutingTotal(TRoutingTotals **routingTotal) // // Input: element = element to return // Return: value -// Purpose: Gets the routing total for toolkitAPI +// Purpose: Gets the routing total for toolkitAPI in volume units (ft^3 or m^3) // -{ - memcpy(*routingTotal, &FlowTotals, sizeof(TRoutingTotals)); +{ + double error = massbal_getFlowError(FALSE); + memcpy(*routingTotal, &FlowTotals, sizeof(TRoutingTotals)); // Cumulative Dry Weather Inflow Volume (*routingTotal)->dwInflow *= UCF(VOLUME); @@ -1076,33 +1077,33 @@ int massbal_getRoutingTotal(TRoutingTotals **routingTotal) // Cumulative Seepage Loss (*routingTotal)->seepLoss *= UCF(VOLUME); // Continuity Error - (*routingTotal)->pctError *= 100; + (*routingTotal)->pctError; - return 0; + return 0; } int massbal_getRunoffTotal(TRunoffTotals **runoffTotal) // // Input: element = element to return // Return: value -// Purpose: Gets the runoff total for toolkitAPI +// Purpose: Gets the runoff total for toolkitAPI in depth units (in or mm) // { - - memcpy(*runoffTotal, &RunoffTotals, sizeof(TRunoffTotals)); - + double error = massbal_getRunoffError(); + memcpy(*runoffTotal, &RunoffTotals, sizeof(TRunoffTotals)); + // Cumulative Rainfall Depth (*runoffTotal)->rainfall *= (UCF(RAINDEPTH) / TotalArea); // Cumulative Evaporation Volume - (*runoffTotal)->evap *= UCF(VOLUME); + (*runoffTotal)->evap *= (UCF(RAINDEPTH) / TotalArea); // Cumulative Infiltration Volume - (*runoffTotal)->infil *= UCF(VOLUME); + (*runoffTotal)->infil *= (UCF(RAINDEPTH) / TotalArea); // Cumulative Runoff Volume - (*runoffTotal)->runoff *= UCF(VOLUME); + (*runoffTotal)->runoff *= (UCF(RAINDEPTH) / TotalArea); // Cumulative Runon Volume - (*runoffTotal)->runon *= UCF(VOLUME); + (*runoffTotal)->runon *= (UCF(RAINDEPTH) / TotalArea); // Cumulative Drain Volume - (*runoffTotal)->drains *= UCF(VOLUME); + (*runoffTotal)->drains *= (UCF(RAINDEPTH) / TotalArea); // Cumulative Snow Removed Volume (*runoffTotal)->snowRemoved *= (UCF(RAINDEPTH) / TotalArea); // Initial Storage Volume @@ -1114,9 +1115,9 @@ int massbal_getRunoffTotal(TRunoffTotals **runoffTotal) // Final Snow Cover Volume (*runoffTotal)->finalSnowCover *= (UCF(RAINDEPTH) / TotalArea); // Continuity Error - (*runoffTotal)->pctError *= 100; + (*runoffTotal)->pctError; - return 0; + return 0; } diff --git a/src/solver/mathexpr.c b/src/solver/mathexpr.c index 2ce4d423d..c39dff7e1 100644 --- a/src/solver/mathexpr.c +++ b/src/solver/mathexpr.c @@ -6,9 +6,9 @@ ** operators. ** AUTHORS: L. Rossman, US EPA - NRMRL ** F. Shang, University of Cincinnati -** VERSION: 5.2.0 -** LAST UPDATE: 11/01/21 -** BUG FIXES: Problems related to '^' operator (L.Rossman, 11/01/21) +** VERSION: 5.2.2 +** LAST UPDATE: 09/02/2022 +** BUG FIXES: Problems related to '^' operator (F. Shang, 09/02/2022) ******************************************************************************/ /* ** Operand codes: @@ -34,12 +34,12 @@ ** 20 = acos ** 21 = atan ** 22 = acot -** 23 = sinh +** 23 = sinh ** 24 = cosh ** 25 = tanh ** 26 = coth ** 27 = log10 -** 28 = step (x<=0 ? 0 : 1) +** 28 = step (x<=0 ? 0 : 1) ** 31 = ^ ******************************************************************************/ #define _CRT_SECURE_NO_DEPRECATE @@ -190,6 +190,7 @@ double getNumber() char c[] = " "; char sNumber[255]; int errflag = 0; + int decimalCount = 0; /* --- get whole number portion of number */ sNumber[0] = '\0'; @@ -205,6 +206,8 @@ double getNumber() { if (S[Pos] == '.') { + decimalCount++; + if (decimalCount > 1) Err = 1; strcat(sNumber, "."); Pos++; while (Pos < Len && isDigit(S[Pos])) @@ -257,7 +260,7 @@ int getOperand() case '-': code = 4; if (Pos < Len-1 && isDigit(S[Pos+1]) && - (CurLex == 0 || CurLex == 1)) + (CurLex <= 6 || CurLex == 31)) { Pos++; Fvalue = -getNumber(); @@ -294,7 +297,7 @@ int getLex() n = getMathFunc(); if ( n == 0 ) n = getVariable(); } - else if ( isDigit(S[Pos]) ) + else if ( S[Pos] == '.' || isDigit(S[Pos]) ) { n = 7; Fvalue = getNumber(); @@ -330,6 +333,7 @@ ExprTree * getSingleOp(int *lex) { int opcode; ExprTree *left; + ExprTree *node; /* --- open parenthesis, so continue to grow the tree */ if ( *lex == 1 ) @@ -374,6 +378,17 @@ ExprTree * getSingleOp(int *lex) } } *lex = getLex(); + + /* --- exponentiation */ + if (*lex == 31) + { + node = newNode(); + node->left = left; + node->opcode = *lex; + *lex = getLex(); + node->right = getSingleOp(lex); + left = node; + } return left; } @@ -398,7 +413,7 @@ ExprTree * getOp(int *lex) else if ( *lex == 3) *lex = getLex(); } left = getSingleOp(lex); - while ( *lex == 5 || *lex == 6 || *lex == 31) + while ( *lex == 5 || *lex == 6) { opcode = *lex; *lex = getLex(); @@ -518,88 +533,88 @@ double mathexpr_eval(MathExpr *expr, double (*getVariableValue) (int)) case 3: r1 = ExprStack[stackindex]; stackindex--; - if (stackindex < 0) break; + if (stackindex < 0) break; r2 = ExprStack[stackindex]; ExprStack[stackindex] = r2 + r1; break; - case 4: - r1 = ExprStack[stackindex]; + case 4: + r1 = ExprStack[stackindex]; stackindex--; - if (stackindex < 0) break; + if (stackindex < 0) break; r2 = ExprStack[stackindex]; ExprStack[stackindex] = r2 - r1; break; - case 5: - r1 = ExprStack[stackindex]; + case 5: + r1 = ExprStack[stackindex]; stackindex--; - if (stackindex < 0) break; + if (stackindex < 0) break; r2 = ExprStack[stackindex]; ExprStack[stackindex] = r2 * r1; break; - case 6: + case 6: r1 = ExprStack[stackindex]; stackindex--; - if (stackindex < 0) break; - r2 = ExprStack[stackindex]; + if (stackindex < 0) break; + r2 = ExprStack[stackindex]; ExprStack[stackindex] = r2 / r1; break; - case 7: + case 7: stackindex++; - if (stackindex >= MAX_STACK_SIZE) break; + if (stackindex >= MAX_STACK_SIZE) break; ExprStack[stackindex] = node->fvalue; break; - case 8: - if (getVariableValue != NULL) - { - r1 = getVariableValue(node->ivar); - } - else r1 = 0.0; + case 8: + if (getVariableValue != NULL) + { + r1 = getVariableValue(node->ivar); + } + else r1 = 0.0; stackindex++; - if (stackindex >= MAX_STACK_SIZE) break; - ExprStack[stackindex] = r1; + if (stackindex >= MAX_STACK_SIZE) break; + ExprStack[stackindex] = r1; break; - case 9: + case 9: ExprStack[stackindex] = -ExprStack[stackindex]; break; - case 10: + case 10: r1 = ExprStack[stackindex]; r2 = cos(r1); ExprStack[stackindex] = r2; break; - case 11: + case 11: r1 = ExprStack[stackindex]; r2 = sin(r1); ExprStack[stackindex] = r2; break; - case 12: + case 12: r1 = ExprStack[stackindex]; r2 = tan(r1); ExprStack[stackindex] = r2; break; - case 13: + case 13: r1 = ExprStack[stackindex]; if (r1 == 0.0) r2 = 0.0; else r2 = 1.0/tan( r1 ); ExprStack[stackindex] = r2; break; - case 14: + case 14: r1 = ExprStack[stackindex]; r2 = fabs( r1 ); ExprStack[stackindex] = r2; break; - case 15: + case 15: r1 = ExprStack[stackindex]; if (r1 < 0.0) r2 = -1.0; else if (r1 > 0.0) r2 = 1.0; @@ -607,93 +622,93 @@ double mathexpr_eval(MathExpr *expr, double (*getVariableValue) (int)) ExprStack[stackindex] = r2; break; - case 16: + case 16: r1 = ExprStack[stackindex]; if (r1 < 0.0) r2 = 0.0; else r2 = sqrt( r1 ); ExprStack[stackindex] = r2; break; - case 17: + case 17: r1 = ExprStack[stackindex]; if (r1 <= 0) r2 = 0.0; else r2 = log(r1); ExprStack[stackindex] = r2; break; - case 18: + case 18: r1 = ExprStack[stackindex]; r2 = exp(r1); ExprStack[stackindex] = r2; break; - case 19: + case 19: r1 = ExprStack[stackindex]; r2 = asin( r1 ); ExprStack[stackindex] = r2; break; - case 20: + case 20: r1 = ExprStack[stackindex]; r2 = acos( r1 ); ExprStack[stackindex] = r2; break; - case 21: + case 21: r1 = ExprStack[stackindex]; r2 = atan( r1 ); ExprStack[stackindex] = r2; break; - case 22: + case 22: r1 = ExprStack[stackindex]; r2 = 1.57079632679489661923 - atan(r1); ExprStack[stackindex] = r2; break; - case 23: + case 23: r1 = ExprStack[stackindex]; r2 = (exp(r1)-exp(-r1))/2.0; ExprStack[stackindex] = r2; break; - case 24: + case 24: r1 = ExprStack[stackindex]; r2 = (exp(r1)+exp(-r1))/2.0; ExprStack[stackindex] = r2; break; - case 25: + case 25: r1 = ExprStack[stackindex]; r2 = (exp(r1)-exp(-r1))/(exp(r1)+exp(-r1)); ExprStack[stackindex] = r2; break; - case 26: + case 26: r1 = ExprStack[stackindex]; r2 = (exp(r1)+exp(-r1))/(exp(r1)-exp(-r1)); ExprStack[stackindex] = r2; break; - case 27: + case 27: r1 = ExprStack[stackindex]; if (r1 == 0.0) r2 = 0.0; else r2 = log10( r1 ); ExprStack[stackindex] = r2; break; - case 28: + case 28: r1 = ExprStack[stackindex]; if (r1 <= 0.0) r2 = 0.0; else r2 = 1.0; ExprStack[stackindex] = r2; break; - case 31: + case 31: r1 = ExprStack[stackindex]; - stackindex--; - if (stackindex < 0) break; - r2 = ExprStack[stackindex]; + stackindex--; + if (stackindex < 0) break; + r2 = ExprStack[stackindex]; if (r2 <= 0.0) r2 = 0.0; else r2 = pow(r2, r1); ExprStack[stackindex] = r2; @@ -741,9 +756,9 @@ MathExpr * mathexpr_create(char *formula, int (*getVar) (char *)) tree = getTree(); if (Bc == 0 && Err == 0) { - traverseTree(tree, &expr); - while (expr) - { + traverseTree(tree, &expr); + while (expr) + { result = expr; expr = expr->prev; } diff --git a/src/solver/node.c b/src/solver/node.c index c3ad97aad..2c8fa2501 100644 --- a/src/solver/node.c +++ b/src/solver/node.c @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 06/01/22 (Build 5.2.1) +// Date: 10/29/22 (Build 5.2.2) // Author: L. Rossman // // Conveyance system node functions. @@ -34,6 +34,9 @@ // - Warning no longer issued when node full depth is increased to match // crown of highest connecting link. // - a2 term for paraboloid shaped storage units was corrected +// Build 5.2.2: +// - Warning restored for node full depth being increased to crown of highest +// connecting link. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -204,12 +207,11 @@ void node_validate(int j) TDwfInflow* inflow; // --- see if full depth was increased to accommodate conduit crown -/* Deprecated as of v.5.2.1 if ( Node[j].fullDepth > Node[j].oldDepth && Node[j].oldDepth > 0.0 ) { report_writeWarningMsg(WARN02, Node[j].ID); } -*/ + // --- check that initial depth does not exceed max. depth if ( Node[j].initDepth > Node[j].fullDepth + Node[j].surDepth ) report_writeErrorMsg(ERR_NODE_DEPTH, Node[j].ID); @@ -1096,7 +1098,7 @@ double storage_getLosses(int j, double tStep) exfilRate *= lossRatio; } } - + // --- save evap & infil losses at the node Storage[Node[j].subIndex].evapLoss = evapRate * tStep; Storage[Node[j].subIndex].exfilLoss = exfilRate * tStep; diff --git a/src/solver/objects.h b/src/solver/objects.h index 2e5146444..07f5129fd 100644 --- a/src/solver/objects.h +++ b/src/solver/objects.h @@ -147,7 +147,7 @@ typedef struct int pastInterval; // seconds since pastRain last updated int coGage; // index of gage with same rain timeseries int isUsed; // TRUE if gage used by any subcatchment - int isCurrent; // TRUE if gage's rainfall is current + int isCurrent; // TRUE if gage's rainfall is current } TGage; //------------------- @@ -203,11 +203,11 @@ typedef struct int tSeries; // time series index double monthlyEvap[12]; // monthly evaporation values double panCoeff[12]; // monthly pan coeff. values - int recoveryPattern; // soil recovery factor pattern + int recoveryPattern; // soil recovery factor pattern int dryOnly; // true if evaporation only in dry periods //---------------------------- double rate; // current evaporation rate (ft/sec) - double recoveryFactor; // current soil recovery factor + double recoveryFactor; // current soil recovery factor } TEvap; //------------------- @@ -404,7 +404,7 @@ typedef struct double lidArea; // area devoted to LIDs (ft2) double rainfall; // current rainfall (ft/sec) double evapLoss; // current evap losses (ft/sec) - double infilLoss; // current infil losses (ft/sec) + double infilLoss; // current infil losses (ft/sec) double runon; // runon from other subcatchments (cfs) double oldRunoff; // previous runoff (cfs) double newRunoff; // current runoff (cfs) @@ -568,7 +568,7 @@ typedef struct TExfil* exfil; // ptr. to exfiltration object //----------------------------- double hrt; // hydraulic residence time (sec) - double evapLoss; // evaporation loss (ft3) + double evapLoss; // evaporation loss (ft3) double exfilLoss; // exfiltration loss (ft3) } TStorage; @@ -620,10 +620,10 @@ typedef struct double aFull; // area when full (ft2) double rFull; // hyd. radius when full (ft) double wMax; // width at widest point (ft) - double ywMax; // depth at max width (ft) + double ywMax; // depth at max width (ft) double sMax; // section factor at max. flow (ft^4/3) double aMax; // area at max. flow (ft2) - double lengthFactor; // floodplain / channel length + double lengthFactor; // floodplain / channel length //-------------------------------------- double roughness; // Manning's n double areaTbl[N_TRANSECT_TBL]; // table of area v. depth @@ -751,10 +751,10 @@ typedef struct { int type; // pump type int pumpCurve; // pump curve table index - double initSetting; // initial speed setting + double initSetting; // initial speed setting double yOn; // startup depth (ft) double yOff; // shutoff depth (ft) - double xMin; // minimum pt. on pump curve + double xMin; // minimum pt. on pump curve double xMax; // maximum pt. on pump curve } TPump; @@ -1115,14 +1115,14 @@ typedef struct int objType; // either NODE or LINK int index; // node or link index double value; // value of node or link statistic -} TMaxStats; +} TMaxStats; //------------------ // REPORT FIELD INFO //------------------ -typedef struct +typedef struct { - char Name[80]; // name of reported variable + char Name[80]; // name of reported variable char Units[80]; // units of reported variable char Enabled; // TRUE if appears in report table int Precision; // number of decimal places when reported diff --git a/src/solver/project.c b/src/solver/project.c index a9bc162a3..55a0866c8 100644 --- a/src/solver/project.c +++ b/src/solver/project.c @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 11/01/21 (Build 5.2.0) +// Date: 11/21/22 (Build 5.2.2) // Author: L. Rossman // // Project management functions. @@ -49,6 +49,9 @@ // - Support added for Streets and Inlets. // - Support added for RptFlags.disabled option. // - Object's rptFlag changed to record its index in output file. +// Build 5.2.2: +// - Default number of threads changed from OMP max. number to 1 +// to be consistent with User Manual. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -64,7 +67,7 @@ #endif #include "headers.h" -#include "lid.h" +#include "lid.h" #include "hash.h" #include "mempool.h" @@ -72,7 +75,7 @@ // Shared variables //----------------------------------------------------------------------------- static HTtable* Htable[MAX_OBJ_TYPES]; // Hash tables for object ID names -static char MemPoolAllocated; // TRUE if memory pool allocated +static char MemPoolAllocated; // TRUE if memory pool allocated //----------------------------------------------------------------------------- // External Functions (declared in funcs.h) @@ -290,7 +293,7 @@ int project_init(void) // Input: none // Output: returns an error code // Purpose: initializes the internal state of all objects. -// +// { int j, k; climate_initState(); @@ -508,7 +511,7 @@ int project_readOption(char* s1, char* s2) // --- simulation ending date case END_DATE: - if ( !datetime_strToDate(s2, &EndDate) ) + if ( !datetime_strToDate(s2, &EndDate) ) { return error_setInpError(ERR_DATETIME, s2); } @@ -626,8 +629,8 @@ int project_readOption(char* s1, char* s2) } break; - case NORMAL_FLOW_LTD: - m = findmatch(s2, NormalFlowWords); + case NORMAL_FLOW_LTD: + m = findmatch(s2, NormalFlowWords); if ( m < 0 ) return error_setInpError(ERR_KEYWORD, s2); NormalFlowLtd = m; break; @@ -704,7 +707,7 @@ int project_readOption(char* s1, char* s2) break; // --- minimum surface area (ft2 or sq. meters) associated with nodes - // under dynamic wave flow routing + // under dynamic wave flow routing case MIN_SURFAREA: if (!getDouble(s2, &MinSurfArea)) return error_setInpError(ERR_NUMBER, s2); @@ -821,7 +824,7 @@ void setDefaults() // Interface files Frain.mode = SCRATCH_FILE; // Use scratch rainfall file - Fclimate.mode = NO_FILE; + Fclimate.mode = NO_FILE; Frunoff.mode = NO_FILE; Frdii.mode = NO_FILE; Fhotstart1.mode = NO_FILE; @@ -852,14 +855,14 @@ void setDefaults() ForceMainEqn = H_W; // Hazen-Williams eqn. for force mains LinkOffsets = DEPTH_OFFSET; // Use depth for link offsets LengtheningStep = 0; // No lengthening of conduits - CourantFactor = 0.0; // No variable time step + CourantFactor = 0.0; // No variable time step MinSurfArea = 0.0; // Force use of default min. surface area MinSlope = 0.0; // No user supplied minimum conduit slope - SkipSteadyState = FALSE; // Do flow routing in steady state periods + SkipSteadyState = FALSE; // Do flow routing in steady state periods IgnoreRainfall = FALSE; // Analyze rainfall/runoff IgnoreRDII = FALSE; // Analyze RDII - IgnoreSnowmelt = FALSE; // Analyze snowmelt - IgnoreGwater = FALSE; // Analyze groundwater + IgnoreSnowmelt = FALSE; // Analyze snowmelt + IgnoreGwater = FALSE; // Analyze groundwater IgnoreRouting = FALSE; // Analyze flow routing IgnoreQuality = FALSE; // Analyze water quality WetStep = 300; // Runoff wet time step (secs) @@ -869,15 +872,15 @@ void setDefaults() MinRouteStep = 0.5; // Minimum variable time step (sec) ReportStep = 900; // Reporting time step (secs) StartDryDays = 0.0; // Antecedent dry days - MaxTrials = 0; // Force use of default max. trials + MaxTrials = 0; // Force use of default max. trials HeadTol = 0.0; // Force use of default head tolerance SysFlowTol = 0.05; // System flow tolerance for steady state LatFlowTol = 0.05; // Lateral flow tolerance for steady state - NumThreads = 0; // Number of parallel threads to use + NumThreads = 1; // Number of parallel threads to use NumEvents = 0; // Number of detailed routing events // Deprecated options - SlopeWeighting = TRUE; // Use slope weighting + SlopeWeighting = TRUE; // Use slope weighting Compatibility = SWMM4; // Use SWMM 4 up/dn weighting method // Starting & ending date/time @@ -934,7 +937,7 @@ void setDefaults() Evap.panCoeff[i] = 1.0; } Evap.recoveryPattern = -1; - Evap.recoveryFactor = 1.0; + Evap.recoveryFactor = 1.0; Evap.tSeries = -1; Evap.dryOnly = FALSE; diff --git a/src/solver/qualrout.c b/src/solver/qualrout.c index d535d9a25..d9c640f79 100644 --- a/src/solver/qualrout.c +++ b/src/solver/qualrout.c @@ -107,7 +107,7 @@ void qualrout_execute(double tStep) { int i, j; double qIn, vAvg; - + // --- find mass flow each link contributes to its downstream node for ( i = 0; i < Nobjects[LINK]; i++ ) findLinkMassFlow(i, tStep); @@ -125,7 +125,7 @@ void qualrout_execute(double tStep) if ( qIn < ZERO ) qIn = 0.0; treatmnt_setInflow(qIn, Node[j].newQual); } - + // --- find new quality at the node if ( Node[j].type == STORAGE || Node[j].oldVolume > ZeroVolume ) { @@ -330,7 +330,7 @@ void findLinkQual(int i, double tStep) // --- start with concen. at start of time step c1 = Link[i].oldQual[p]; - // --- update mass balance accounting for seepage loss + // --- update mass balance accounting for seepage loss massbal_addSeepageLoss(p, qSeep*c1); // --- increase concen. by evaporation factor diff --git a/src/solver/runoff.c b/src/solver/runoff.c index b8f9fb72b..080674fbb 100644 --- a/src/solver/runoff.c +++ b/src/solver/runoff.c @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 11/01/21 (Build 5.2.0) +// Date: 10/17/22 (Build 5.2.2) // Author: L. Rossman // M. Tryby // @@ -27,7 +27,9 @@ // Build 5.1.014: // - Fixed street sweeping bug. // Build 5.2.0: -// - Support added for saving rainfall amounts in previous 48 hours. +// - Support added for saving rainfall amounts in previous 48 hours. +// Build 5.2.2: +// - Fixed possible use of canSweep in runoff_execute() with no assigned value. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -204,12 +206,12 @@ void runoff_execute() // --- see if street sweeping can occur on current date day = datetime_dayOfYear(currentDate); + canSweep = FALSE; if ( SweepStart <= SweepEnd ) { if ( day >= SweepStart && day <= SweepEnd ) canSweep = TRUE; } else if ( day <= SweepEnd || day >= SweepStart ) canSweep = TRUE; - else canSweep = FALSE; // --- get runoff time step (in seconds) runoffStep = runoff_getTimeStep(currentDate); diff --git a/src/solver/statsrpt.c b/src/solver/statsrpt.c index f76ef7a48..baa3a40d8 100644 --- a/src/solver/statsrpt.c +++ b/src/solver/statsrpt.c @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 06/01/22 (Build 5.2.1) +// Date: 11/19/22 (Build 5.2.2) // Author: L. Rossman // // Report writing functions for summary statistics. @@ -27,6 +27,9 @@ // - Fixes value used for total reporting time. // Build 5.2.1: // - Replaces the "3" in "ft3" and "m3" with ANSI superscript (\xB3). +// Build 5.2.2 +// - Calculation of % Evaporation and % Exfiltration losses for storage +// units was corrected. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -512,7 +515,7 @@ void writeStorageVolumes() { int j, k, days, hrs, mins; double avgVol, maxVol, pctAvgVol, pctMaxVol; - double addedVol, pctEvapLoss, pctSeepLoss; + double pctEvapLoss, pctSeepLoss; if ( Nnodes[STORAGE] > 0 ) { @@ -524,16 +527,16 @@ void writeStorageVolumes() // OWA EDIT - write unicode super script 3 (\xC2\xB3) instead of extended ascii (\xB3) fprintf(Frpt.file, -"\n --------------------------------------------------------------------------------------------------" -"\n Average Avg Evap Exfil Maximum Max Time of Max Maximum" -"\n Volume Pcnt Pcnt Pcnt Volume Pcnt Occurrence Outflow"); +"\n ------------------------------------------------------------------------------------------------" +"\n Average Avg Evap Exfil Maximum Max Time of Max Maximum" +"\n Volume Pcnt Pcnt Pcnt Volume Pcnt Occurrence Outflow"); if ( UnitSystem == US ) fprintf(Frpt.file, -"\n Storage Unit 1000 ft\xC2\xB3 Full Loss Loss 1000 ft\xC2\xB3 Full days hr:min "); +"\n Storage Unit 1000 ft\xC2\xB3 Full Loss Loss 1000 ft\xC2\xB3 Full days hr:min "); else fprintf(Frpt.file, -"\n Storage Unit 1000 m\xC2\xB3 Full Loss Loss 1000 m\xC2\xB3 Full days hr:min "); +"\n Storage Unit 1000 m\xC2\xB3 Full Loss Loss 1000 m\xC2\xB3 Full days hr:min "); fprintf(Frpt.file, "%3s", FlowUnitWords[FlowUnits]); fprintf(Frpt.file, -"\n --------------------------------------------------------------------------------------------------"); +"\n ------------------------------------------------------------------------------------------------"); for ( j = 0; j < Nobjects[NODE]; j++ ) { @@ -551,14 +554,13 @@ void writeStorageVolumes() } pctEvapLoss = 0.0; pctSeepLoss = 0.0; - addedVol = NodeInflow[j] + StorageStats[k].initVol; - if ( addedVol > 0.0 ) + if ( NodeInflow[j] > 0.0 ) { - pctEvapLoss = StorageStats[k].evapLosses / addedVol * 100.0; - pctSeepLoss = StorageStats[k].exfilLosses / addedVol * 100.0; + pctEvapLoss = StorageStats[k].evapLosses / NodeInflow[j] * 100.0; + pctSeepLoss = StorageStats[k].exfilLosses / NodeInflow[j] * 100.0; } - fprintf(Frpt.file, "%10.3f %4.0f %4.0f %4.0f %10.3f %4.0f", + fprintf(Frpt.file, "%10.3f %5.1f %5.1f %5.1f %10.3f %5.1f", avgVol*UCF(VOLUME)/1000.0, pctAvgVol, pctEvapLoss, pctSeepLoss, maxVol*UCF(VOLUME)/1000.0, pctMaxVol); diff --git a/src/solver/swmm5.c b/src/solver/swmm5.c index 3ef3f6fc7..2e49e27f4 100644 --- a/src/solver/swmm5.c +++ b/src/solver/swmm5.c @@ -350,7 +350,7 @@ int DLLEXPORT swmm_open(const char *f1, const char *f2, const char *f3) int DLLEXPORT swmm_start(int saveResults) // -// Input: saveResults = TRUE if simulation results saved to binary file +// Input: saveResults = TRUE if simulation results saved to binary file // Output: returns an error code // Purpose: starts a SWMM simulation. // diff --git a/src/solver/table.c b/src/solver/table.c index aced49e13..f5917cacb 100644 --- a/src/solver/table.c +++ b/src/solver/table.c @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 11/01/21 (Build 5.2.0) +// Date: 10/17/22 (Build 5.2.2) // Author: L. Rossman // // Table (curve and time series) functions. @@ -28,6 +28,8 @@ // - The table_getInverseArea function was renamed table_getStorageDepth and // was refactored. // - Support added for relative file names. +// Build 5.2.2: +// - Prevent re-reading a time series file from start once end is reached. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -759,6 +761,13 @@ double table_tseriesLookup(TTable *table, double x, char extend) && table->x2 >= x && table->x1 != table->x2 ) return table_interpolate(x, table->x1, table->y1, table->x2, table->y2); + + // --- end of external time series file has been reached + if ( table->file.mode == USE_FILE && feof(table->file.file) ) + { + if (extend == TRUE) return table->y1; + else return 0; + } // --- x lies before current time bracket: // move to start of time series diff --git a/src/solver/text.h b/src/solver/text.h index 70bfc1f50..353296b8e 100644 --- a/src/solver/text.h +++ b/src/solver/text.h @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 06/01/22 (Build 5.2.1) +// Date: 12/22/22 (Build 5.2.3) // Author: L. Rossman // // Text strings @@ -25,7 +25,7 @@ #define FMT03 " There are errors.\n" #define FMT04 " There are warnings.\n" #define FMT08 \ - "\n EPA STORM WATER MANAGEMENT MODEL - VERSION 5.2 (Build 5.2.1)" + "\n EPA STORM WATER MANAGEMENT MODEL - VERSION 5.2 (Build 5.2.3)" #define FMT09 \ "\n ------------------------------------------------------------" #define FMT10 "\n" diff --git a/src/solver/toolkit.c b/src/solver/toolkit.c index fff5f4998..83571a97e 100644 --- a/src/solver/toolkit.c +++ b/src/solver/toolkit.c @@ -806,6 +806,148 @@ EXPORT_TOOLKIT int swmm_setLinkParam(int index, SM_LinkProperty param, double va return error_code; } +EXPORT_TOOLKIT int swmm_getInletParam(int index, SM_InletProperty param, double *value) +/// +/// Input: index = Index of the link with desired inlet +/// param = Parameter desired (Based on enum SM_InletProperty) +/// Output: value = value to be output +/// Return: API Error +/// Purpose: Gets Link Parameter +{ + int error_code = 0; + *value = 0; + TInlet* inlet; + + // Check if Open + if(swmm_IsOpenFlag() == FALSE) + { + error_code = ERR_TKAPI_INPUTNOTOPEN; + } + // Check if object index is within bounds + else if (index < 0 || index >= Nobjects[LINK]) + { + error_code = ERR_TKAPI_OBJECT_INDEX; + } + else + { + inlet = Link[index].inlet; + if (inlet) + { + switch(param) + { + case SM_INLETNUMINLETS: + *value = (double)inlet->numInlets; break; + case SM_INLETCLOGFACTOR: + *value = (1 - inlet->clogFactor) * 100; break; + case SM_INLETFLOWLIMIT: + *value = inlet->flowLimit * UCF(FLOW); break; + case SM_INLETLOCALDEPRESS: + *value = inlet->localDepress * UCF(LENGTH); break; + case SM_INLETLOCALWIDTH: + *value = inlet->localWidth * UCF(LENGTH); break; + default: error_code = ERR_TKAPI_OUTBOUNDS; break; + } + } + + else + { + error_code = ERR_TKAPI_NO_INLET; + } + } + return error_code; +}; + +EXPORT_TOOLKIT int swmm_setInletParam(int index, SM_InletProperty param, double value) +/// +/// Input: index = Index of link with desired inlets +/// param = Parameter desired (Based on enum SM_InletProperty) +/// value = value to be assigned +/// Return: API Error +/// Purpose: Sets Inlet Parameter +{ + int error_code = 0; + TInlet* inlet; + // Check if Open + if(swmm_IsOpenFlag() == FALSE) + { + error_code = ERR_TKAPI_INPUTNOTOPEN; + } + // Check if object index is within bounds + else if (index < 0 || index >= Nobjects[LINK]) + { + error_code = ERR_TKAPI_OBJECT_INDEX; + } + else + { + inlet = Link[index].inlet; + if (inlet) + { + switch(param) + { + case SM_INLETCLOGFACTOR: + inlet->clogFactor = 1.0 - (value / 100.); break; + case SM_INLETFLOWLIMIT: + inlet->flowLimit = value / UCF(FLOW); break; + default: error_code = ERR_TKAPI_OUTBOUNDS; break; + } + } + + else + { + error_code = ERR_TKAPI_NO_INLET; + } + } + return error_code; +} + +EXPORT_TOOLKIT int swmm_getInletResult(int index, SM_InletResult type, double *result) +/// +/// Input: index = Index of the link with desired inlet +/// param = Parameter desired (Based on enum SM_InletProperty) +/// Output: value = value to be output +/// Return: API Error +/// Purpose: Gets Link Parameter +{ + int error_code = 0; + *result = 0; + TInlet* inlet; + + // Check if Open + if(swmm_IsOpenFlag() == FALSE) + { + error_code = ERR_TKAPI_INPUTNOTOPEN; + } + // Check if object index is within bounds + else if (index < 0 || index >= Nobjects[LINK]) + { + error_code = ERR_TKAPI_OBJECT_INDEX; + } + else + { + inlet = Link[index].inlet; + if (inlet) + { + switch(type) + { + case SM_INLETFLOWFACTOR: + *result = inlet->flowFactor; break; + case SM_INLETFLOWCAPTURE: + *result = inlet->flowCapture * UCF(FLOW); break; + case SM_INLETBACKFLOW: + *result = inlet->backflow * UCF(FLOW); break; + case SM_INLETBACKFLOWRATIO: + *result = inlet->backflowRatio; break; + default: error_code = ERR_TKAPI_OUTBOUNDS; break; + } + } + + else + { + error_code = ERR_TKAPI_NO_INLET; + } + } + return error_code; +}; EXPORT_TOOLKIT int swmm_getSubcatchParam(int index, SM_SubcProperty param, double *value) /// diff --git a/src/solver/xsect.c b/src/solver/xsect.c index 5ebab53c0..1a53d36e2 100644 --- a/src/solver/xsect.c +++ b/src/solver/xsect.c @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 11/01/21 (Build 5.2.0) +// Date: 10/17/22 (Build 5.2.2) // Author: L. Rossman // M. Tryby (EPA) // @@ -32,6 +32,8 @@ // - Width at full height set to 0 for closed rectangular shape. // Build 5.2.0: // - Support added for Street cross sections. +// Build 5.2.2: +// - Feasibility check added to Mod. Baskethandle & Rect.-Round shapes. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -430,6 +432,7 @@ int xsect_setParams(TXsect *xsect, int type, double p[], double ucf) // --- depth of circular bottom xsect->yBot = xsect->rBot * (1.0 - cos(theta/2.0)); + if (xsect->yBot > xsect->yFull) return FALSE; xsect->ywMax = xsect->yFull; xsect->aFull = xsect->wMax * (xsect->yFull - xsect->yBot) + xsect->aBot; @@ -455,6 +458,7 @@ int xsect_setParams(TXsect *xsect, int type, double p[], double ucf) // --- height of circular arc xsect->yBot = xsect->rBot * (1.0 - cos(theta/2.0)); + if (xsect->yBot > xsect->yFull) return FALSE; xsect->ywMax = xsect->yFull - xsect->yBot; // --- area of circular arc diff --git a/src/solver/xsect.dat b/src/solver/xsect.dat index 10b10ed33..fbecb58ac 100644 --- a/src/solver/xsect.dat +++ b/src/solver/xsect.dat @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 06/01/22 (Build 5.2.1) +// Date: 08/01/22 (Build 5.2.1) // Author: L. Rossman // // Tables of relative geometric properties for rounded cross-sections. diff --git a/tests/solver/CMakeLists.txt b/tests/solver/CMakeLists.txt index da8a5d375..021832fbb 100644 --- a/tests/solver/CMakeLists.txt +++ b/tests/solver/CMakeLists.txt @@ -37,6 +37,7 @@ set(solver_test_srcs test_toolkit.cpp test_solver.cpp test_stats.cpp + test_inlets_and_drains.cpp # ADD NEW TEST SUITES TO EXISTING TOOLKIT TEST MODULE ) diff --git a/tests/solver/data/test_inlet_drains.inp b/tests/solver/data/test_inlet_drains.inp new file mode 100644 index 000000000..a60d798aa --- /dev/null +++ b/tests/solver/data/test_inlet_drains.inp @@ -0,0 +1,502 @@ +[TITLE] +;;Project Title/Notes +A dual drainage model with street inlets. +See Inlet_Drains_Model.txt for more details. + +[OPTIONS] +;;Option Value +FLOW_UNITS CFS +INFILTRATION HORTON +FLOW_ROUTING DYNWAVE +LINK_OFFSETS DEPTH +MIN_SLOPE 0 +ALLOW_PONDING NO +SKIP_STEADY_STATE NO + +START_DATE 01/01/2007 +START_TIME 00:00:00 +REPORT_START_DATE 01/01/2007 +REPORT_START_TIME 00:00:00 +END_DATE 01/01/2007 +END_TIME 06:00:00 +SWEEP_START 01/01 +SWEEP_END 12/31 +DRY_DAYS 0 +REPORT_STEP 00:01:00 +WET_STEP 00:01:00 +DRY_STEP 01:00:00 +ROUTING_STEP 0:00:15 +RULE_STEP 00:00:00 + +INERTIAL_DAMPING PARTIAL +NORMAL_FLOW_LIMITED SLOPE +FORCE_MAIN_EQUATION H-W +VARIABLE_STEP 0.75 +LENGTHENING_STEP 0 +MIN_SURFAREA 12.566 +MAX_TRIALS 8 +HEAD_TOLERANCE 0.005 +SYS_FLOW_TOL 5 +LAT_FLOW_TOL 5 +MINIMUM_STEP 0.5 +THREADS 1 + +[EVAPORATION] +;;Data Source Parameters +;;-------------- ---------------- +CONSTANT 0.0 +DRY_ONLY NO + +[RAINGAGES] +;;Name Format Interval SCF Source +;;-------------- --------- ------ ------ ---------- +RainGage INTENSITY 0:05 1.0 TIMESERIES 2-yr + +[SUBCATCHMENTS] +;;Name Rain Gage Outlet Area %Imperv Width %Slope CurbLen SnowPack +;;-------------- ---------------- ---------------- -------- -------- -------- -------- -------- ---------------- +S1 RainGage Aux1 4.55 56.8 1587 2 0 +S2 RainGage Aux4 4.74 63.0 1653 2 0 +S3 RainGage Aux3 3.74 39.5 1456 3.1 0 +S4 RainGage J7 6.79 49.9 2331 3.1 0 +S5 RainGage J10 4.79 87.7 1670 2 0 +S6 RainGage J11 1.98 95.0 690 2 0 +S7 RainGage J10 2.33 0.0 907 3.1 0 + +[SUBAREAS] +;;Subcatchment N-Imperv N-Perv S-Imperv S-Perv PctZero RouteTo PctRouted +;;-------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- +S1 0.015 0.24 0.06 0.3 25 OUTLET +S2 0.015 0.24 0.06 0.3 25 OUTLET +S3 0.015 0.24 0.06 0.3 25 OUTLET +S4 0.015 0.24 0.06 0.3 25 OUTLET +S5 0.015 0.24 0.06 0.3 25 OUTLET +S6 0.015 0.24 0.06 0.3 25 OUTLET +S7 0.015 0.24 0.06 0.3 25 OUTLET + +[INFILTRATION] +;;Subcatchment Param1 Param2 Param3 Param4 Param5 +;;-------------- ---------- ---------- ---------- ---------- ---------- +S1 4.5 0.2 6.5 7 0 +S2 4.5 0.2 6.5 7 0 +S3 4.5 0.2 6.5 7 0 +S4 4.5 0.2 6.5 7 0 +S5 4.5 0.2 6.5 7 0 +S6 4.5 0.2 6.5 7 0 +S7 4.5 0.2 6.5 7 0 + +[JUNCTIONS] +;;Name Elevation MaxDepth InitDepth SurDepth Aponded +;;-------------- ---------- ---------- ---------- ---------- ---------- +Aux1 4975 0 0 0 0 +Aux2 4973 0 0 0 0 +Aux3 4968.5 0 0 0 0 +Aux4 4971.8 0 0 0 0 +Aux5 4970.7 0 0 0 0 +Aux6 4969 0 0 0 0 +Aux7 4963 0 0 0 0 +J1 4969 4 0 0 0 +J10 4957.8 0 0 0 0 +J11 4957 0 0 0 0 +J2 4965 4 0 0 0 +J2a 4966.7 4 0 0 0 +J3 4973 0 0 0 0 +J4 4965 0 0 0 0 +J5 4965.8 0 0 0 0 +J6 4969 0 0 0 0 +J7 4963.5 0 0 0 0 +J8 4966.5 0 0 0 0 +J9 4964.8 0 0 0 0 + +[OUTFALLS] +;;Name Elevation Type Stage Data Gated Route To +;;-------------- ---------- ---------- ---------------- -------- ---------------- +O1 4956 FREE NO + +[CONDUITS] +;;Name From Node To Node Length Roughness InOffset OutOffset InitFlow MaxFlow +;;-------------- ---------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- +Street1 Aux1 Aux2 377.31 0.016 0 0 0 0 +Street2 Aux2 Aux4 286.06 0.016 0 0 0 0 +Street3 Aux4 Aux5 239.41 0.016 0 0 0 0 +Street4 Aux5 Aux6 157.48 0.016 0 0 0 0 +Street5 Aux6 Aux7 526.0 0.016 0 0 0 0 +C3 J3 J4 109.0 0.016 0 6 0 0 +C4 J4 J5 133.0 0.05 6 4 0 0 +C5 J5 J6 207.0 0.05 4 0 0 0 +C6 J7 J6 140.0 0.05 8 0 0 0 +C7 J6 J8 95.0 0.016 0 0 0 0 +C8 J8 J9 166.0 0.05 0 0 0 0 +C9 J9 J10 320.0 0.05 0 6 0 0 +C10 J10 J11 145.0 0.05 6 6 0 0 +C11 J11 O1 89.0 0.016 0 0 0 0 +C_Aux3 Aux3 J3 444.75 0.05 6 0 0 0 +P1 J1 J5 185.39 0.016 0 0 0 0 +P2 J2a J2 157.48 0.016 0 0 0 0 +P3 J2 J11 529.22 0.016 0 0 0 0 +P4 Aux3 J4 567.19 0.016 0 0 0 0 +P5 J5 J4 125.98 0.016 0 0 0 0 +P6 J4 J7 360.39 0.016 0 0 0 0 +P7 J7 J10 507.76 0.016 0 0 0 0 +P8 J10 J11 144.50 0.016 0 0 0 0 + +[XSECTIONS] +;;Link Shape Geom1 Geom2 Geom3 Geom4 Barrels Culvert +;;-------------- ------------ ---------------- ---------- ---------- ---------- ---------- ---------- +Street1 STREET FullStreet +Street2 STREET FullStreet +Street3 STREET FullStreet +Street4 STREET HalfStreet +Street5 STREET HalfStreet +C3 CIRCULAR 2.25 0 0 0 1 +C4 TRAPEZOIDAL 3 5 5 5 1 +C5 TRAPEZOIDAL 3 5 5 5 1 +C6 TRAPEZOIDAL 3 5 5 5 1 +C7 CIRCULAR 3.5 0 0 0 1 +C8 TRAPEZOIDAL 3 5 5 5 1 +C9 TRAPEZOIDAL 3 5 5 5 1 +C10 TRAPEZOIDAL 3 5 5 5 1 +C11 CIRCULAR 4.75 0 0 0 1 +C_Aux3 TRAPEZOIDAL 3 5 5 5 1 +P1 CIRCULAR 0.5 0 0 0 1 +P2 CIRCULAR 1.5 0 0 0 1 +P3 CIRCULAR 1.5 0 0 0 1 +P4 CIRCULAR 1.67 0 0 0 1 +P5 CIRCULAR 1.83 0 0 0 1 +P6 CIRCULAR 2 0 0 0 1 +P7 CIRCULAR 2 0 0 0 1 +P8 CIRCULAR 3.17 0 0 0 1 + +[STREETS] +;;Name Tcrown Hcurb Sx nRoad a W Sides Tback Sback nBack +;;-------------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- +HalfStreet 20 0.5 4 0.016 0 0 1 20 4 0.016 +FullStreet 20 0.5 4 0.016 0 0 2 20 4 0.016 + +[INLETS] +;;Name Type Parameters: +;;-------------- ---------------- ----------- +ComboInlet GRATE 2 2 P_BAR-50 +ComboInlet CURB 2 0.5 HORIZONTAL + +[INLET_USAGE] +;;Conduit Inlet Node Number %Clogged Qmax aLocal wLocal Placement +;;-------------- ---------------- ---------------- --------- --------- --------- --------- --------- --------- --------- +Street1 ComboInlet J1 1 50 2.2 0.5 2 +Street3 ComboInlet J2a 1 0 0 0 0 +Street4 ComboInlet J2 1 0 0 0 0 +Street5 ComboInlet J11 2 0 0 0 0 + +[TIMESERIES] +;;Name Date Time Value +;;-------------- ---------- ---------- ---------- +2-yr 0:00 0.29 +2-yr 0:05 0.33 +2-yr 0:10 0.38 +2-yr 0:15 0.64 +2-yr 0:20 0.81 +2-yr 0:25 1.57 +2-yr 0:30 2.85 +2-yr 0:35 1.18 +2-yr 0:40 0.71 +2-yr 0:45 0.42 +2-yr 0:50 0.35 +2-yr 0:55 0.3 +2-yr 1:00 0.2 +2-yr 1:05 0.19 +2-yr 1:10 0.18 +2-yr 1:15 0.17 +2-yr 1:20 0.17 +2-yr 1:25 0.16 +2-yr 1:30 0.15 +2-yr 1:35 0.15 +2-yr 1:40 0.14 +2-yr 1:45 0.14 +2-yr 1:50 0.13 +2-yr 1:55 0.13 +; +10-yr 0:00 0.49 +10-yr 0:05 0.56 +10-yr 0:10 0.65 +10-yr 0:15 1.09 +10-yr 0:20 1.39 +10-yr 0:25 2.69 +10-yr 0:30 4.87 +10-yr 0:35 2.02 +10-yr 0:40 1.21 +10-yr 0:45 0.71 +10-yr 0:50 0.6 +10-yr 0:55 0.52 +10-yr 1:00 0.39 +10-yr 1:05 0.37 +10-yr 1:10 0.35 +10-yr 1:15 0.34 +10-yr 1:20 0.32 +10-yr 1:25 0.31 +10-yr 1:30 0.3 +10-yr 1:35 0.29 +10-yr 1:40 0.28 +10-yr 1:45 0.27 +10-yr 1:50 0.26 +10-yr 1:55 0.25 + +[REPORT] +;;Reporting Options +INPUT YES +SUBCATCHMENTS ALL +NODES ALL +LINKS ALL + +[TAGS] +Link Street1 Full_Street +Link Street2 Full_Street +Link Street3 Full_Street +Link Street4 Half_Street +Link Street5 Half_Street +Link C3 Culvert +Link C4 Swale +Link C5 Swale +Link C6 Swale +Link C7 Culvert +Link C8 Swale +Link C9 Swale +Link C10 Swale +Link C11 Culvert +Link C_Aux3 Swale + +[MAP] +DIMENSIONS -255.206 -70.199 1490.833 1514.231 +Units Feet + +[COORDINATES] +;;Node X-Coord Y-Coord +;;-------------- ------------------ ------------------ +Aux1 293.152 1161.023 +Aux2 653.046 1052.180 +Aux3 122.363 696.959 +Aux4 914.142 1058.025 +Aux5 1175.238 1120.376 +Aux6 1260.972 956.704 +Aux7 1381.777 514.399 +J1 647.200 1022.952 +J10 1254.058 640.029 +J11 1270.714 491.017 +J2 1218.105 950.859 +J2a 1159.651 1069.716 +J3 405.287 905.702 +J4 505.345 862.573 +J5 631.281 859.123 +J6 803.079 869.022 +J7 831.398 709.035 +J8 915.930 840.146 +J9 1072.918 867.749 +O1 1411.468 477.401 + +[VERTICES] +;;Link X-Coord Y-Coord +;;-------------- ------------------ ------------------ +Street1 382.860 1112.719 +Street1 514.703 1061.922 +Street2 806.976 1042.437 +Street3 1062.227 1091.149 +Street4 1210.311 1061.922 +Street5 1338.911 781.341 +Street5 1387.623 662.483 +Street5 1393.468 586.493 +C4 559.710 846.393 +C5 672.684 850.497 +C5 712.363 829.795 +C5 743.415 805.643 +C5 768.006 833.950 +C6 791.719 734.912 +C6 798.620 784.942 +C8 965.959 838.421 +C8 995.287 831.520 +C8 1038.415 850.497 +C9 1102.246 867.749 +C9 1131.573 852.222 +C9 1147.099 829.795 +C9 1162.626 809.094 +C9 1198.854 779.766 +C9 1219.556 757.339 +C9 1233.357 721.111 +C9 1238.532 715.936 +C9 1235.082 674.532 +C9 1247.158 646.930 +C_Aux3 163.003 699.992 +C_Aux3 208.620 726.287 +C_Aux3 239.673 793.567 +C_Aux3 251.749 876.374 +C_Aux3 291.427 912.602 +C_Aux3 355.257 929.854 +P3 1331.117 691.711 +P3 1329.168 590.390 +P4 275.901 572.749 +P4 472.567 824.620 +P7 886.602 800.468 + +[Polygons] +;;Subcatchment X-Coord Y-Coord +;;-------------- ------------------ ------------------ +S1 282.657 1334.810 +S1 111.700 1101.604 +S1 172.525 1062.743 +S1 231.660 1027.262 +S1 306.002 990.092 +S1 370.206 959.679 +S1 409.066 946.163 +S1 444.547 936.025 +S1 493.545 924.198 +S1 532.405 915.750 +S1 569.576 907.302 +S1 610.125 897.165 +S1 655.744 897.165 +S1 684.338 1318.700 +S1 651.043 1321.922 +S1 596.269 1332.662 +S1 551.160 1346.624 +S1 495.312 1367.030 +S1 455.573 1384.214 +S1 410.465 1409.991 +S1 386.836 1427.175 +S1 363.208 1442.211 +S2 678.967 1238.149 +S2 673.584 1152.903 +S2 655.744 897.165 +S2 758.808 893.786 +S2 817.943 895.475 +S2 880.458 898.855 +S2 921.007 905.613 +S2 978.453 920.819 +S2 1042.657 937.715 +S2 1103.482 959.679 +S2 1159.238 985.023 +S2 1225.131 1010.367 +S2 1109.646 1274.665 +S2 1052.723 1400.325 +S2 985.061 1370.252 +S2 924.916 1348.772 +S2 861.549 1331.588 +S2 815.367 1325.144 +S2 762.740 1319.774 +S2 719.780 1316.552 +S2 684.338 1317.626 +S3 109.199 1103.258 +S3 141.754 1081.555 +S3 190.586 1051.713 +S3 247.557 1019.158 +S3 304.528 989.317 +S3 354.716 964.900 +S3 398.123 949.980 +S3 490.166 922.509 +S3 477.743 883.275 +S3 501.993 816.065 +S3 556.059 778.895 +S3 488.476 679.210 +S3 422.582 729.897 +S3 282.348 557.560 +S3 179.734 633.927 +S3 153.962 651.561 +S3 107.843 693.610 +S3 71.218 742.443 +S3 48.159 785.849 +S3 31.881 837.394 +S3 29.168 886.226 +S3 31.881 933.702 +S3 38.664 967.613 +S3 50.872 1001.525 +S3 65.793 1035.436 +S3 87.496 1070.704 +S3 109.199 1103.258 +S4 282.348 559.250 +S4 420.893 729.897 +S4 488.476 680.899 +S4 556.828 779.067 +S4 501.213 814.335 +S4 479.468 885.000 +S4 491.718 922.851 +S4 616.511 898.434 +S4 668.056 897.078 +S4 783.355 895.722 +S4 815.909 898.434 +S4 857.959 899.791 +S4 890.595 897.165 +S4 968.316 915.750 +S4 1042.657 937.715 +S4 1074.759 849.857 +S4 1054.484 773.826 +S4 1020.692 702.864 +S4 963.247 623.454 +S4 689.536 256.816 +S5 1301.482 474.258 +S5 1271.677 445.380 +S5 1232.340 393.835 +S5 1241.835 384.340 +S5 1222.844 366.706 +S5 1233.696 355.854 +S5 1026.159 66.931 +S5 1008.525 56.079 +S5 708.750 275.824 +S5 1023.446 704.462 +S5 1150.644 618.812 +S5 1251.203 640.809 +S5 1328.193 519.824 +S6 1334.478 519.824 +S6 1306.266 488.956 +S6 1293.380 474.205 +S6 1232.340 393.835 +S6 1241.835 381.627 +S6 1222.844 365.350 +S6 1232.340 353.142 +S6 1027.516 65.574 +S6 1012.595 56.079 +S6 707.393 273.111 +S6 688.403 254.121 +S6 739.948 218.853 +S6 788.780 159.169 +S6 806.414 106.268 +S6 813.197 1.821 +S6 994.961 12.673 +S6 1228.270 27.594 +S6 1222.844 115.763 +S6 1228.270 167.308 +S6 1241.835 229.705 +S6 1255.399 254.121 +S6 1279.815 302.953 +S6 1309.657 354.498 +S6 1335.430 401.974 +S6 1359.846 448.093 +S6 1370.616 475.830 +S6 1381.615 491.542 +S7 1122.467 968.970 +S7 1174.012 987.282 +S7 1225.557 1005.594 +S7 1377.480 675.977 +S7 1391.044 642.065 +S7 1396.470 598.659 +S7 1381.615 491.542 +S7 1331.336 519.824 +S7 1249.632 640.809 +S7 1150.644 617.241 +S7 1020.733 704.462 +S7 1054.645 772.285 +S7 1076.796 848.212 +S7 1056.370 900.062 +S7 1040.658 937.772 + +[SYMBOLS] +;;Gage X-Coord Y-Coord +;;-------------- ------------------ ------------------ +RainGage -175.841 1212.778 + +[LABELS] +;;X-Coord Y-Coord Label +145.274 1129.896 "S1" "" "Arial" 14 0 0 +758.404 969.723 "S2" "" "Arial" 14 0 0 +247.369 666.226 "S3" "" "Arial" 14 0 0 +628.971 458.688 "S4" "" "Arial" 14 0 0 +952.552 257.845 "S5" "" "Arial" 14 0 0 +827.947 56.930 "S6" "" "Arial" 14 0 0 +1073.058 780.037 "S7" "" "Arial" 14 0 0 +1385.481 454.225 "Outfall" "" "Arial" 10 1 0 + diff --git a/tests/solver/test_inlets_and_drains.cpp b/tests/solver/test_inlets_and_drains.cpp new file mode 100644 index 000000000..466140c46 --- /dev/null +++ b/tests/solver/test_inlets_and_drains.cpp @@ -0,0 +1,120 @@ +/* + ****************************************************************************** + Project: OWA SWMM + Version: 5.2.3 + Module: test_inlets_and_drains.cpp + Description: tests for SWMM inlets and drains API functions + Authors: see AUTHORS + Copyright: see AUTHORS + License: see LICENSE + Last Updated: 3/27/2023 + ****************************************************************************** +*/ + + #include + + #include "test_solver.hpp" + + +#define ERR_NONE 0 + +BOOST_AUTO_TEST_SUITE(test_toolkitapi_inlets_and_drains) + + +BOOST_FIXTURE_TEST_CASE(getset_inlet_params, FixtureBeforeStep_Inlets){ + int error, link_ind; + double value; + char id[] = "Street1"; + + error = swmm_getObjectIndex(SM_LINK, id, &link_ind); + BOOST_REQUIRE(error == ERR_NONE); + + // test num inlets getter + error = swmm_getInletParam(link_ind, SM_INLETNUMINLETS, &value); + BOOST_REQUIRE(error == ERR_NONE); + BOOST_CHECK_SMALL(value - 1.0, 0.0001); + + // test clogging factor getter + error = swmm_getInletParam(link_ind, SM_INLETCLOGFACTOR, &value); + BOOST_REQUIRE(error == ERR_NONE); + BOOST_CHECK_SMALL(value - 50.0, 0.0001); + + // test clogging factor setter + error = swmm_setInletParam(link_ind, SM_INLETCLOGFACTOR, 78.0); + BOOST_REQUIRE(error == ERR_NONE); + error = swmm_getInletParam(link_ind, SM_INLETCLOGFACTOR, &value); + BOOST_REQUIRE(error == ERR_NONE); + BOOST_CHECK_SMALL(value - 78.0, 0.0001); + + // test flow limit getter + error = swmm_getInletParam(link_ind, SM_INLETFLOWLIMIT, &value); + BOOST_REQUIRE(error == ERR_NONE); + BOOST_CHECK_SMALL(value - 2.2, 0.0001); + + // test flow limit setter + error = swmm_setInletParam(link_ind, SM_INLETFLOWLIMIT, 5.8); + BOOST_REQUIRE(error == ERR_NONE); + error = swmm_getInletParam(link_ind, SM_INLETFLOWLIMIT, &value); + BOOST_REQUIRE(error == ERR_NONE); + BOOST_CHECK_SMALL(value - 5.8, 0.0001); + + // test local depression height getter + error = swmm_getInletParam(link_ind, SM_INLETLOCALDEPRESS, &value); + BOOST_REQUIRE(error == ERR_NONE); + BOOST_CHECK_SMALL(value - 0.5, 0.0001); + + // test local depression width getter + error = swmm_getInletParam(link_ind, SM_INLETLOCALWIDTH, &value); + BOOST_REQUIRE(error == ERR_NONE); + BOOST_CHECK_SMALL(value - 2.0, 0.0001); + +} + +BOOST_FIXTURE_TEST_CASE(get_result_during_sim, FixtureBeforeStep_Inlets){ + int error, step_ind; + int lnk_ind; + double val; + double elapsedTime = 0.0; + + char lnkid[] = "Street1"; + + error = swmm_getObjectIndex(SM_LINK, lnkid, &lnk_ind); + BOOST_REQUIRE(error == ERR_NONE); + + step_ind = 0; + + do + { + error = swmm_step(&elapsedTime); + + if (step_ind == 250) // peak flow in Street1 + { + // test inlet flow factor getter + error = swmm_getInletResult(lnk_ind, SM_INLETFLOWFACTOR, &val); + BOOST_REQUIRE(error == ERR_NONE); + BOOST_CHECK_SMALL(val - 0.0118, 0.0001); + + // test inlet flow capture getter + error = swmm_getInletResult(lnk_ind, SM_INLETFLOWCAPTURE, &val); + BOOST_REQUIRE(error == ERR_NONE); + BOOST_CHECK_SMALL(val - 3.3864, 0.0001); + + // test inlet backflow getter + error = swmm_getInletResult(lnk_ind, SM_INLETBACKFLOW, &val); + BOOST_REQUIRE(error == ERR_NONE); + BOOST_CHECK_SMALL(val - 2.5670, 0.0001); + + // test inlet backflow ratio getter + error = swmm_getInletResult(lnk_ind, SM_INLETBACKFLOWRATIO, &val); + BOOST_REQUIRE(error == ERR_NONE); + BOOST_CHECK_SMALL(val - 1.0, 0.0001); + } + + step_ind+=1; + }while (elapsedTime != 0 && !error); + // BOOST_REQUIRE(error == 1); + swmm_end(); +} + + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/tests/solver/test_solver.hpp b/tests/solver/test_solver.hpp index c2617ae9b..e45e477b4 100644 --- a/tests/solver/test_solver.hpp +++ b/tests/solver/test_solver.hpp @@ -24,6 +24,7 @@ extern "C" { #define DATA_PATH_INP_POLLUT_NODE "node_constantinflow_constanteffluent.inp" #define DATA_PATH_INP_POLLUT_LINK "link_constantinflow.inp" #define DATA_PATH_INP_LINK_DIR "link_flow_dir.inp" +#define DATA_PATH_INP_INLETS_AND_DRAINS "test_inlet_drains.inp" #define DATA_PATH_RPT "tmp.rpt" #define DATA_PATH_OUT "tmp.out" @@ -103,6 +104,18 @@ struct FixtureBeforeStep_Flow_Dir{ }; +struct FixtureBeforeStep_Inlets{ + FixtureBeforeStep_Inlets() { + swmm_open(DATA_PATH_INP_INLETS_AND_DRAINS, DATA_PATH_RPT, DATA_PATH_OUT); + swmm_start(0); + } + ~FixtureBeforeStep_Inlets() { + swmm_close(); + } +}; + + + // Declare shared test predicates here boost::test_tools::predicate_result check_cdd_double(std::vector& test, std::vector& ref, long cdd_tol);