├── doc └── Images │ ├── Fig1.png │ ├── Fig3.png │ ├── Fig4.png │ ├── Fig5.png │ ├── Fig6.png │ ├── Fig2a.png │ └── Fig2b.png ├── tests ├── outfile │ ├── data │ │ └── Example1.out │ ├── CMakeLists.txt │ └── test_output.cpp ├── CMakeLists.txt └── Unit_Testing.md ├── .gitignore ├── extern └── boost.cmake ├── Build.md ├── src ├── solver │ ├── odesolve.h │ ├── headers.h │ ├── street.h │ ├── findroot.h │ ├── mempool.h │ ├── hash.h │ ├── inlet.h │ ├── exfil.h │ ├── mathexpr.h │ ├── error.c │ ├── macros.h │ ├── keywords.h │ ├── datetime.h │ ├── CMakeLists.txt │ ├── hash.c │ ├── consts.h │ ├── findroot.c │ ├── infil.h │ ├── include │ │ └── swmm5.h │ ├── mempool.c │ ├── forcmain.c │ ├── street.c │ ├── error.h │ ├── error.txt │ ├── roadway.c │ ├── Roadmap.txt │ ├── odesolve.c │ ├── exfil.c │ ├── globals.h │ ├── kinwave.c │ ├── keywords.c │ ├── lid.h │ ├── shape.c │ └── inputrpt.c ├── outfile │ ├── errormanager.h │ ├── messages.h │ ├── errormanager.c │ ├── CMakeLists.txt │ └── include │ │ ├── swmm_output_enums.h │ │ └── swmm_output.h └── run │ ├── CMakeLists.txt │ └── main.c ├── .github ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── workflows │ └── build-and-test.yml ├── bindings └── swmm5.def ├── README.md ├── CMakeLists.txt └── Readme.txt /doc/Images/Fig1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/USEPA/Stormwater-Management-Model/HEAD/doc/Images/Fig1.png -------------------------------------------------------------------------------- /doc/Images/Fig3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/USEPA/Stormwater-Management-Model/HEAD/doc/Images/Fig3.png -------------------------------------------------------------------------------- /doc/Images/Fig4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/USEPA/Stormwater-Management-Model/HEAD/doc/Images/Fig4.png -------------------------------------------------------------------------------- /doc/Images/Fig5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/USEPA/Stormwater-Management-Model/HEAD/doc/Images/Fig5.png -------------------------------------------------------------------------------- /doc/Images/Fig6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/USEPA/Stormwater-Management-Model/HEAD/doc/Images/Fig6.png -------------------------------------------------------------------------------- /doc/Images/Fig2a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/USEPA/Stormwater-Management-Model/HEAD/doc/Images/Fig2a.png -------------------------------------------------------------------------------- /doc/Images/Fig2b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/USEPA/Stormwater-Management-Model/HEAD/doc/Images/Fig2b.png -------------------------------------------------------------------------------- /tests/outfile/data/Example1.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/USEPA/Stormwater-Management-Model/HEAD/tests/outfile/data/Example1.out -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | 4 | # Eclipse Stuff 5 | .metadata/ 6 | .settings/ 7 | 8 | build/ 9 | nrtests/ 10 | upload/ 11 | 12 | *_export.h 13 | -------------------------------------------------------------------------------- /tests/outfile/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # CMakeLists.txt - CMake configuration file for tests/outfile 3 | # 4 | # Created: July 11, 2019 5 | # 6 | # Author: Michael E. Tryby 7 | # US EPA ORD/CESER 8 | # 9 | 10 | add_executable(test_output 11 | test_output.cpp 12 | ) 13 | target_include_directories(test_output 14 | PUBLIC ../../outfile/include 15 | ) 16 | target_link_libraries(test_output 17 | ${Boost_LIBRARIES} 18 | swmm-output 19 | ) 20 | 21 | set_target_properties(test_output 22 | PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 23 | -------------------------------------------------------------------------------- /extern/boost.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # CMakeLists.txt - CMake configuration file for swmm-solver/extern 3 | # 4 | # Created: March 16, 2020 5 | # Updated: Oct 19, 2022 6 | # 7 | # Author: Michael E. Tryby 8 | # US EPA - ORD/CESER 9 | # 10 | 11 | 12 | if(WIN32) 13 | set(Boost_USE_STATIC_LIBS ON) 14 | else() 15 | set(Boost_USE_STATIC_LIBS OFF) 16 | add_definitions(-DBOOST_ALL_DYN_LINK) 17 | endif() 18 | 19 | 20 | find_package( 21 | Boost 22 | COMPONENTS 23 | unit_test_framework 24 | ) 25 | 26 | include_directories( 27 | ${Boost_INCLUDE_DIRS} 28 | ) 29 | -------------------------------------------------------------------------------- /Build.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | ## Building SWMM Locally on Windows 13 | 14 | 15 | ### Dependencies 16 | 17 | Before the project can be built the required dependencies must be installed. 18 | 19 | **Summary of Build Dependencies: Windows** 20 | 21 | - Build 22 | - Build Tools for Visual Studio 2017 23 | - CMake 3.13 24 | 25 | 26 | ### Build 27 | 28 | SWMM can be built with one simple command. 29 | ``` 30 | \> cd swmm 31 | \swmm>tools\make.cmd 32 | ``` 33 | -------------------------------------------------------------------------------- /src/solver/odesolve.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // odesolve.h 3 | // 4 | // Header file for ODE solver contained in odesolve.c 5 | // 6 | //----------------------------------------------------------------------------- 7 | 8 | #ifndef ODESOLVE_H 9 | #define ODESOLVE_H 10 | 11 | 12 | // functions that open, close, and use the ODE solver 13 | int odesolve_open(int n); 14 | void odesolve_close(void); 15 | int odesolve_integrate(double ystart[], int n, double x1, double x2, 16 | double eps, double h1, void (*derivs)(double, double*, double*)); 17 | 18 | 19 | #endif //ODESOLVE_H 20 | -------------------------------------------------------------------------------- /src/solver/headers.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // headers.h 3 | // 4 | // Project: EPA SWMM5 5 | // Version: 5.2 6 | // Date: 11/01/21 (Build 5.2.0) 7 | // Author: L. Rossman 8 | // 9 | // Header files included in most SWMM5 modules. 10 | // 11 | // DO NOT CHANGE THE ORDER OF THE #INCLUDE STATEMENTS 12 | //----------------------------------------------------------------------------- 13 | #include "macros.h" 14 | #include "objects.h" 15 | #define EXTERN extern 16 | #include "globals.h" 17 | #include "funcs.h" 18 | #include "error.h" 19 | #include "text.h" 20 | #include "keywords.h" 21 | -------------------------------------------------------------------------------- /src/solver/street.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // street.h 3 | // 4 | // Project: EPA SWMM5 5 | // Version: 5.2 6 | // Date: 11/01/21 (Build 5.2.0) 7 | // Author: L. Rossman 8 | // 9 | // Definition of the Street Cross-Section Object 10 | // 11 | //----------------------------------------------------------------------------- 12 | #ifndef STREET_H 13 | #define STREET_H 14 | 15 | // Shared street functions 16 | int street_create(int nStreets); 17 | void street_delete(); 18 | int street_readParams(char* tok[], int ntoks); 19 | double street_getExtentFilled(int link); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /src/solver/findroot.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // findroot.h 3 | // 4 | // Header file for root finding method contained in findroot.c 5 | // 6 | // Last modified on 11/19/13. 7 | //----------------------------------------------------------------------------- 8 | 9 | #ifndef FINDROOT_H 10 | #define FINDROOT_H 11 | 12 | int findroot_Newton(double x1, double x2, double* rts, double xacc, 13 | void (*func) (double x, double* f, double* df, void* p), 14 | void* p); 15 | double findroot_Ridder(double x1, double x2, double xacc, 16 | double (*func)(double, void* p), void* p); 17 | 18 | #endif //FINDROOT_H 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[FEATURE]" 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # CMakeLists.txt - CMake configuration file for swmm-solver/tests 3 | # 4 | # Created: Mar 4, 2020 5 | # Updated: May 21, 2020 6 | # 7 | # Author: Michael E. Tryby 8 | # US EPA ORD/CESER 9 | # 10 | 11 | 12 | #Prep ourselves for compiling with boost 13 | include(../extern/boost.cmake) 14 | 15 | 16 | add_subdirectory(outfile) 17 | 18 | 19 | # Setting up tests to run from build tree 20 | set(TEST_BIN_DIRECTORY "${CMAKE_BINARY_DIR}/bin/$") 21 | 22 | 23 | # ctest doesn't like tests added in subdirectories so adding them here 24 | add_test(NAME test_output 25 | COMMAND "${TEST_BIN_DIRECTORY}/test_output" 26 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/outfile/data 27 | ) 28 | -------------------------------------------------------------------------------- /src/solver/mempool.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // mempool.h 3 | // 4 | // Header for mempool.c 5 | // 6 | // The type alloc_handle_t provides an opaque reference to the 7 | // alloc pool - only the alloc routines know its structure. 8 | //----------------------------------------------------------------------------- 9 | 10 | #ifndef MEMPOOL_H 11 | #define MEMPOOL_H 12 | 13 | 14 | typedef struct 15 | { 16 | long dummy; 17 | } alloc_handle_t; 18 | 19 | alloc_handle_t *AllocInit(void); 20 | char *Alloc(long); 21 | alloc_handle_t *AllocSetPool(alloc_handle_t *); 22 | void AllocReset(void); 23 | void AllocFreePool(void); 24 | 25 | 26 | #endif //MEMPOOL_H 27 | -------------------------------------------------------------------------------- /src/solver/hash.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // hash.h 3 | // 4 | // Header file for Hash Table module hash.c. 5 | //----------------------------------------------------------------------------- 6 | 7 | #ifndef HASH_H 8 | #define HASH_H 9 | 10 | 11 | #define HTMAXSIZE 1999 12 | #define NOTFOUND -1 13 | 14 | struct HTentry 15 | { 16 | char *key; 17 | int data; 18 | struct HTentry *next; 19 | }; 20 | 21 | typedef struct HTentry *HTtable; 22 | 23 | HTtable* HTcreate(void); 24 | int HTinsert(HTtable *, char *, int); 25 | int HTfind(HTtable *, const char *); 26 | char* HTfindKey(HTtable *, const char *); 27 | void HTfree(HTtable *); 28 | 29 | 30 | #endif //HASH_H 31 | -------------------------------------------------------------------------------- /src/outfile/errormanager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * errormanager.h 3 | * 4 | * Created on: Aug 25, 2017 5 | * 6 | * Author: Michael E. Tryby 7 | * US EPA - ORD/NRMRL 8 | */ 9 | 10 | #ifndef ERRORMANAGER_H_ 11 | #define ERRORMANAGER_H_ 12 | 13 | 14 | #define ERR_MAXMSG 256 15 | 16 | typedef struct error_s { 17 | int error_status; 18 | void (*p_msg_lookup)(int, char*, int); 19 | } error_handle_t; 20 | 21 | error_handle_t* new_errormanager(void (*p_error_message)(int, char*, int)); 22 | void dst_errormanager(error_handle_t* error_handle); 23 | 24 | int set_error(error_handle_t* error_handle, int errorcode); 25 | char* check_error(error_handle_t* error_handle); 26 | void clear_error(error_handle_t* error_handle); 27 | 28 | 29 | #endif /* ERRORMANAGER_H_ */ 30 | -------------------------------------------------------------------------------- /tests/Unit_Testing.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | ## Unit Testing SWMM locally on Windows 13 | 14 | ### Dependencies 15 | 16 | Before the project can be built and tested the required dependencies must be installed. 17 | 18 | **Summary of Build Dependencies: Windows** 19 | 20 | - Build 21 | - Build Tools for Visual Studio 2017 22 | - CMake 3.13 23 | 24 | - Unit Test 25 | - Boost 1.67.0 (installed in default location "C:\\local") 26 | 27 | 28 | 29 | ### Build and Unit Test 30 | 31 | SWMM can be built and unit tests run with one simple command. 32 | ``` 33 | \> cd swmm 34 | \swmm>tools\make.cmd /t 35 | ``` 36 | -------------------------------------------------------------------------------- /src/run/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # CMakeLists.txt - CMake configuration file for swmm-solver/run 3 | # 4 | # Created: July 11, 2019 5 | # 6 | # Modified by: Michael E. Tryby 7 | # US EPA ORD/NRMRL 8 | # 9 | 10 | 11 | # Creates the EPANET command line executable 12 | add_executable(runswmm 13 | main.c 14 | ) 15 | 16 | target_include_directories(runswmm 17 | PUBLIC 18 | include 19 | ) 20 | 21 | target_link_libraries(runswmm 22 | LINK_PUBLIC 23 | swmm5 24 | ) 25 | 26 | 27 | install(TARGETS runswmm 28 | DESTINATION "${TOOL_DIST}" 29 | ) 30 | 31 | 32 | # copy runswmm to build tree for testing 33 | add_custom_command(TARGET runswmm POST_BUILD 34 | COMMAND ${CMAKE_COMMAND} -E copy 35 | $ 36 | ${CMAKE_BINARY_DIR}/bin/$/$ 37 | ) 38 | -------------------------------------------------------------------------------- /src/solver/inlet.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // inlet.h 3 | // 4 | // Project: EPA SWMM5 5 | // Version: 5.2 6 | // Date: 11/01/21 (Build 5.2.0) 7 | // Author: L. Rossman 8 | // 9 | // Street/Channel Inlet Functions 10 | // 11 | //----------------------------------------------------------------------------- 12 | #ifndef INLET_H 13 | #define INLET_H 14 | 15 | typedef struct TInlet TInlet; 16 | 17 | int inlet_create(int nInlets); 18 | void inlet_delete(); 19 | int inlet_readDesignParams(char* tok[], int ntoks); 20 | int inlet_readUsageParams(char* tok[], int ntoks); 21 | void inlet_validate(); 22 | 23 | void inlet_findCapturedFlows(double tStep); 24 | void inlet_adjustQualInflows(); 25 | void inlet_adjustQualOutflows(); 26 | 27 | void inlet_writeStatsReport(); 28 | double inlet_capturedFlow(int link); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG]" 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **SWMM Version** 11 | Version for the SWMM model where the bug was discovered. 12 | 13 | **Desktop (please complete the following information):** 14 | - OS: [e.g. iOS] 15 | - Version [e.g. 22] 16 | 17 | **Describe the bug** 18 | A clear and concise description of what the bug is. 19 | 20 | **To Reproduce** 21 | Steps to reproduce the behavior: 22 | 1. Go to '...' 23 | 2. Click on '....' 24 | 3. Scroll down to '....' 25 | 4. See error 26 | 27 | **Expected behavior** 28 | A clear and concise description of what you expected to happen. 29 | 30 | **Screenshots** 31 | If applicable, add screenshots to help explain your problem. 32 | 33 | **SWMM Input File" 34 | If applicable add swmm input file that 35 | 36 | **Additional context** 37 | Add any other context about the problem here. 38 | -------------------------------------------------------------------------------- /src/outfile/messages.h: -------------------------------------------------------------------------------- 1 | /* 2 | * messages.h - SWMM 3 | * 4 | * Created on: Oct 20, 2017 5 | * 6 | * Author: Michael E. Tryby 7 | * US EPA - ORD/NRMRL 8 | */ 9 | 10 | #ifndef SRC_MESSAGES_H_ 11 | #define SRC_MESSAGES_H_ 12 | 13 | 14 | #define MAXMSG 56 15 | 16 | /*------------------- Error Messages --------------------*/ 17 | #define WARN10 "Warning: model run issued warnings" 18 | 19 | #define ERR411 "Error 411: memory allocation failure" 20 | 21 | #define ERR421 "Input Error 421: invalid parameter code" 22 | #define ERR422 "Input Error 422: reporting period index out of range" 23 | #define ERR423 "Input Error 423: element index out of range" 24 | #define ERR424 "Input Error 424: no memory allocated for results" 25 | 26 | #define ERR434 "File Error 434: unable to open binary output file" 27 | #define ERR435 "File Error 435: invalid file - not created by SWMM" 28 | #define ERR436 "File Error 436: invalid file - contains no results" 29 | 30 | #define ERR440 "ERROR 440: an unspecified error has occurred" 31 | 32 | 33 | #endif /* SRC_MESSAGES_H_ */ 34 | -------------------------------------------------------------------------------- /src/solver/exfil.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // exfil.h 3 | // 4 | // Project: EPA SWMM5 5 | // Version: 5.2 6 | // Date: 11/01/21 (Build 5.2.0) 7 | // Author: L. Rossman 8 | // 9 | // Public interface for exfiltration functions. 10 | //----------------------------------------------------------------------------- 11 | 12 | #ifndef EXFIL_H 13 | #define EXFIL_H 14 | 15 | //---------------------------- 16 | // EXFILTRATION OBJECT 17 | //---------------------------- 18 | typedef struct 19 | { 20 | TGrnAmpt* btmExfil; 21 | TGrnAmpt* bankExfil; 22 | double btmArea; 23 | double bankMinDepth; 24 | double bankMaxDepth; 25 | double bankMaxArea; 26 | } TExfil; 27 | 28 | //----------------------------------------------------------------------------- 29 | // Exfiltration Methods 30 | //----------------------------------------------------------------------------- 31 | int exfil_readStorageParams(int k, char* tok[], int ntoks, int n); 32 | void exfil_initState(int k); 33 | double exfil_getLoss(TExfil* exfil, double tStep, double depth, double area); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /bindings/swmm5.def: -------------------------------------------------------------------------------- 1 | LIBRARY SWMM5.DLL 2 | 3 | EXPORTS 4 | swmm_close = _swmm_close@0 5 | swmm_decodeDate = _swmm_decodeDate@36 6 | swmm_end = _swmm_end@0 7 | swmm_getCount = _swmm_getCount@4 8 | swmm_getError = _swmm_getError@8 9 | swmm_getIndex = _swmm_getIndex@8 10 | swmm_getMassBalErr = _swmm_getMassBalErr@12 11 | swmm_getName = _swmm_getName@16 12 | swmm_getSavedValue = _swmm_getSavedValue@12 13 | swmm_getValue = _swmm_getValue@8 14 | swmm_getVersion = _swmm_getVersion@0 15 | swmm_getWarnings = _swmm_getWarnings@0 16 | swmm_open = _swmm_open@12 17 | swmm_report = _swmm_report@0 18 | swmm_run = _swmm_run@12 19 | swmm_setValue = _swmm_setValue@16 20 | swmm_start = _swmm_start@4 21 | swmm_step = _swmm_step@4 22 | swmm_stride = _swmm_stride@8 23 | swmm_writeLine = _swmm_writeLine@4 24 | -------------------------------------------------------------------------------- /src/solver/mathexpr.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | ** MODULE: MATHEXPR.H 3 | ** PROJECT: SWMM5 4 | ** DESCRIPTION: header file for the math expression parser in mathexpr.c. 5 | ** AUTHORS: L. Rossman, US EPA - NRMRL 6 | ** F. Shang, University of Cincinnati 7 | ** VERSION: 5.1.001 8 | ** LAST UPDATE: 03/20/14 9 | ******************************************************************************/ 10 | 11 | #ifndef MATHEXPR_H 12 | #define MATHEXPR_H 13 | 14 | 15 | // Node in a tokenized math expression list 16 | struct ExprNode 17 | { 18 | int opcode; // operator code 19 | int ivar; // variable index 20 | double fvalue; // numerical value 21 | struct ExprNode *prev; // previous node 22 | struct ExprNode *next; // next node 23 | }; 24 | typedef struct ExprNode MathExpr; 25 | 26 | // Creates a tokenized math expression from a string 27 | MathExpr* mathexpr_create(char* s, int (*getVar) (char *)); 28 | 29 | // Evaluates a tokenized math expression 30 | double mathexpr_eval(MathExpr* expr, double (*getVal) (int)); 31 | 32 | // Deletes a tokenized math expression 33 | void mathexpr_delete(MathExpr* expr); 34 | 35 | 36 | #endif //MATHEXPR_H 37 | -------------------------------------------------------------------------------- /src/solver/error.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // error.c 3 | // 4 | // Project: EPA SWMM5 5 | // Version: 5.2 6 | // Date: 11/01/21 (Build 5.2.0) 7 | // Author: L. Rossman 8 | // 9 | // Error messages 10 | // 11 | // Update History 12 | // ============== 13 | // Build 5.1.008: 14 | // - Text of Error 217 for control rules modified. 15 | // Build 5.1.010: 16 | // - Text of Error 318 for rainfall data files modified. 17 | // Build 5.1.015: 18 | // - Added new Error 140 for storage nodes. 19 | // Build 5.2.0: 20 | // - Re-designed error message system. 21 | // - Added new Error 235 for invalid infiltration parameters. 22 | //----------------------------------------------------------------------------- 23 | #define _CRT_SECURE_NO_DEPRECATE 24 | 25 | #include 26 | #include "error.h" 27 | 28 | char ErrString[256]; 29 | 30 | char* error_getMsg(int errCode, char* msg) 31 | { 32 | switch (errCode) 33 | { 34 | 35 | #define ERR(code,string) case code: strcpy(msg, string); break; 36 | #include "error.txt" 37 | #undef ERR 38 | 39 | default: 40 | strcpy(msg, ""); 41 | } 42 | return (msg); 43 | }; 44 | 45 | int error_setInpError(int errcode, char* s) 46 | { 47 | strcpy(ErrString, s); 48 | return errcode; 49 | } 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ORD Stormwater-Management-Model Solver 2 | ================================== 3 | 4 | Stormwater Management Model (aka "SWMM") solver only 5 | 6 | 7 | ## Build Status 8 | [![Build and Test](../../actions/workflows/build-and-test.yml/badge.svg)](../../actions/workflows/build-and-test.yml) 9 | 10 | ## Disclaimer 11 | The United States Environmental Protection Agency (EPA) GitHub project code is provided on an "as is" basis and the user assumes responsibility for its use. EPA has relinquished control of the information and no longer has responsibility to protect the integrity, confidentiality, or availability of the information. Any reference to specific commercial products, processes, or services by service mark, trademark, manufacturer, or otherwise, does not constitute or imply their endorsement, recommendation or favoring by EPA. The EPA seal and logo shall not be used in any manner to imply endorsement of any commercial product or activity by EPA or the United States Government. 12 | 13 | 14 | ## Introduction 15 | This is the official SWMM source code repository maintained by US EPA Office of Research and Development, Center For Environmental Solutions & Emergency Response, Water Infrastructure Division located in Cincinnati, Ohio. 16 | 17 | SWMM is a dynamic hydrology-hydraulic water quality simulation model. It is used for single event or long-term (continuous) simulation of runoff quantity and quality from primarily urban areas. SWMM source code is written in the C Programming Language and released in the Public Domain. 18 | 19 | 20 | ## Find Out More 21 | The source code distributed here is identical to the code found at the official [SWMM Website](http://www.epa.gov/water-research/storm-water-management-model-swmm). 22 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # CMakeLists.txt - CMake configuration file for swmm-solver 3 | # 4 | # Created: July 11, 2019 5 | # Modified: Aug 16, 2022 6 | # 7 | # Author: Michael E. Tryby 8 | # US EPA ORD/CESER 9 | # 10 | 11 | 12 | cmake_minimum_required (VERSION 3.13) 13 | 14 | if("${CMAKE_BINARY_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}") 15 | message(FATAL_ERROR "In-source builds are disabled.") 16 | endif() 17 | 18 | 19 | project(swmm-solver 20 | VERSION 5.2.4 21 | LANGUAGES C CXX 22 | ) 23 | 24 | # Append local dir to module search path 25 | list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) 26 | 27 | # Sets the position independent code property for all targets 28 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) 29 | 30 | # Sets default install prefix when cmakecache is initialized for first time 31 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) 32 | set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "..." FORCE) 33 | endif() 34 | 35 | 36 | # Define install locations (will be prepended by install prefix) 37 | set(TOOL_DIST "bin") 38 | set(INCLUDE_DIST "include") 39 | set(LIBRARY_DIST "lib") 40 | set(CONFIG_DIST "cmake") 41 | 42 | 43 | # Define build options 44 | option(BUILD_TESTS "Builds component tests (requires Boost)" OFF) 45 | option(BUILD_DEF "Builds library with def file interface" OFF) 46 | 47 | 48 | # Add project subdirectories 49 | add_subdirectory(src/outfile) 50 | add_subdirectory(src/solver) 51 | add_subdirectory(src/run) 52 | 53 | if(BUILD_TESTS) 54 | enable_testing() 55 | add_subdirectory(tests) 56 | endif() 57 | 58 | 59 | # Create install rules for vcruntime.dll, msvcp.dll, vcomp.dll etc. 60 | set(CMAKE_INSTALL_OPENMP_LIBRARIES TRUE) 61 | include(InstallRequiredSystemLibraries) 62 | 63 | 64 | # Configure CPack driven installer package 65 | set(CPACK_GENERATOR "ZIP") 66 | set(CPACK_PACKAGE_VENDOR "US_EPA") 67 | set(CPACK_ARCHIVE_FILE_NAME "swmm") 68 | 69 | include(CPack) 70 | -------------------------------------------------------------------------------- /src/outfile/errormanager.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // 3 | // errormanager.c 4 | // 5 | // Purpose: Provides a simple interface for managing runtime error messages. 6 | // 7 | // Date 08/25/2017 8 | // 9 | // Author: Michael E. Tryby 10 | // US EPA - ORD/NRMRL 11 | //----------------------------------------------------------------------------- 12 | #include 13 | #include 14 | #include "errormanager.h" 15 | 16 | error_handle_t* new_errormanager(void (*p_error_message)(int, char*, int)) 17 | // 18 | // Purpose: Constructs a new error handle. 19 | // 20 | { 21 | error_handle_t* error_handle; 22 | error_handle = (error_handle_t*)calloc(1, sizeof(error_handle_t)); 23 | 24 | error_handle->p_msg_lookup = p_error_message; 25 | 26 | return error_handle; 27 | } 28 | 29 | void dst_errormanager(error_handle_t* error_handle) 30 | // 31 | // Purpose: Destroys the error handle. 32 | // 33 | { 34 | free(error_handle); 35 | } 36 | 37 | int set_error(error_handle_t* error_handle, int errorcode) 38 | // 39 | // Purpose: Sets an error code in the handle. 40 | // 41 | { 42 | // If the error code is 0 no action is taken and 0 is returned. 43 | // This is a feature not a bug. 44 | if (errorcode) 45 | error_handle->error_status = errorcode; 46 | 47 | return errorcode; 48 | } 49 | 50 | char* check_error(error_handle_t* error_handle) 51 | // 52 | // Purpose: Returns the error message or NULL. 53 | // 54 | // Note: Caller must free memory allocated by check_error 55 | // 56 | { 57 | char* temp = NULL; 58 | 59 | if (error_handle->error_status != 0) { 60 | temp = (char*) calloc(ERR_MAXMSG, sizeof(char)); 61 | 62 | if (temp) 63 | error_handle->p_msg_lookup(error_handle->error_status, temp, ERR_MAXMSG); 64 | } 65 | return temp; 66 | } 67 | 68 | void clear_error(error_handle_t* error_handle) 69 | // 70 | // Purpose: Clears the error from the handle. 71 | // 72 | { 73 | error_handle->error_status = 0; 74 | } 75 | -------------------------------------------------------------------------------- /Readme.txt: -------------------------------------------------------------------------------- 1 | CONTENTS OF SWMM522_ENGINE.ZIP 2 | ============================== 3 | 4 | The 'src' folder of this archive contains the C source code for 5 | version 5.2.2 of the Storm Water Management Model's computational 6 | engine. Consult the included 'Roadmap.txt' file for an overview of 7 | the various code modules. The code can be compiled into both a shared 8 | object library and a command line executable. Under Windows, the 9 | library file (swmm5.dll) is used to power SWMM's graphical user 10 | interface. 11 | 12 | The 'CMakeLists.txt' file is a script used by CMake (https://cmake.org/) 13 | to build the SWMM 5.2 binaries. CMake is a cross-platform build tool 14 | that generates platform native build systems for many compilers. To 15 | check if the required version is installed on your system, enter 16 | 17 | cmake --version 18 | 19 | from a console window and check that the version is 3.5 or higher. 20 | 21 | To build the SWMM 5.2 engine library and its command line executable 22 | using CMake and the Microsoft Visual Studio C compiler on Windows: 23 | 24 | 1. Open a console window and navigate to the directory where this 25 | Readme file resides (which should have 'src' as a sub-directory 26 | underneath it). 27 | 28 | 2. Issue the following commands: 29 | mkdir build 30 | cd build 31 | 32 | 3. Then enter the following CMake commands: 33 | cmake -G .. -A 34 | cmake --build . --config Release 35 | 36 | where is the name of the Visual Studio compiler being used 37 | in double quotes (e.g., "Visual Studio 15 2017" or "Visual Studio 16 2019") 38 | and is Win32 for a 32-bit build or x64 for a 64-bit build. 39 | The resulting engine DLL (swmm5.dll) and command line executable 40 | (runswmm.exe) will appear in the build\Release directory. 41 | 42 | For other platforms, such as Linux or MacOS, Step 3 can be replaced with: 43 | cmake .. 44 | cmake --build . 45 | 46 | The resulting shared object library (libswmm5.so) and command line executable 47 | (runswmm) will appear in the build directory. -------------------------------------------------------------------------------- /src/outfile/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # CMakeLists.txt - CMake configuration file for swmm/outfile 3 | # 4 | # Created: July 11, 2019 5 | # 6 | # Author: Michael E. Tryby 7 | # US EPA ORD/CESER 8 | # 9 | 10 | # configure file groups 11 | set(SWMM_OUT_PUBLIC_HEADERS 12 | include/swmm_output.h 13 | include/swmm_output_enums.h 14 | include/swmm_output_export.h 15 | ) 16 | 17 | 18 | # the binary output file API 19 | add_library(swmm-output 20 | SHARED 21 | swmm_output.c 22 | errormanager.c 23 | ) 24 | 25 | target_include_directories(swmm-output 26 | PUBLIC 27 | $ 28 | $ 29 | ) 30 | 31 | include(GenerateExportHeader) 32 | generate_export_header(swmm-output 33 | BASE_NAME swmm_output 34 | EXPORT_MACRO_NAME EXPORT_OUT_API 35 | EXPORT_FILE_NAME swmm_output_export.h 36 | STATIC_DEFINE SHARED_EXPORTS_BUILT_AS_STATIC 37 | ) 38 | 39 | file(COPY ${CMAKE_CURRENT_BINARY_DIR}/swmm_output_export.h 40 | DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/include 41 | ) 42 | 43 | 44 | install(TARGETS swmm-output 45 | EXPORT 46 | swmm-outputTargets 47 | RUNTIME 48 | DESTINATION "${TOOL_DIST}" 49 | LIBRARY 50 | DESTINATION "${TOOL_DIST}" 51 | ARCHIVE 52 | DESTINATION "${LIBRARY_DIST}" 53 | FRAMEWORK 54 | DESTINATION "${TOOL_DIST}" 55 | 56 | ) 57 | 58 | install( 59 | EXPORT 60 | swmm-outputTargets 61 | DESTINATION 62 | "${CONFIG_DIST}" 63 | FILE 64 | swmm-output-config.cmake 65 | ) 66 | 67 | install( 68 | FILES 69 | ${SWMM_OUT_PUBLIC_HEADERS} 70 | DESTINATION 71 | "${INCLUDE_DIST}" 72 | ) 73 | 74 | 75 | # copy epanet-output to build tree for testing 76 | if(BUILD_TESTS) 77 | add_custom_command(TARGET swmm-output POST_BUILD 78 | COMMAND ${CMAKE_COMMAND} -E copy 79 | $ 80 | ${CMAKE_BINARY_DIR}/bin/$/$ 81 | ) 82 | endif() 83 | -------------------------------------------------------------------------------- /src/solver/macros.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // macros.h 3 | // 4 | // Project: EPA SWMM5 5 | // Version: 5.2 6 | // Date: 11/01/21 (Build 5.2.0) 7 | // Author: L. Rossman 8 | //----------------------------------------------------------------------------- 9 | 10 | #ifndef MACROS_H 11 | #define MACROS_H 12 | 13 | 14 | //-------------------------------------------------- 15 | // Macro to test for successful allocation of memory 16 | //-------------------------------------------------- 17 | #define MEMCHECK(x) (((x) == NULL) ? 101 : 0 ) 18 | 19 | //-------------------------------------------------- 20 | // Macro to free a non-null pointer 21 | //-------------------------------------------------- 22 | #define FREE(x) { if (x) { free(x); x = NULL; } } 23 | 24 | //--------------------------------------------------- 25 | // Conversion macros to be used in place of functions 26 | //--------------------------------------------------- 27 | #define ABS(x) (((x)<0) ? -(x) : (x)) /* absolute value of x */ 28 | #define MIN(x,y) (((x)<=(y)) ? (x) : (y)) /* minimum of x and y */ 29 | #define MAX(x,y) (((x)>=(y)) ? (x) : (y)) /* maximum of x and y */ 30 | #define MOD(x,y) ((x)%(y)) /* x modulus y */ 31 | #define LOG10(x) ((x) > 0.0 ? log10((x)) : (x)) /* safe log10 of x */ 32 | #define SQR(x) ((x)*(x)) /* x-squared */ 33 | #define SGN(x) (((x)<0) ? (-1) : (1)) /* sign of x */ 34 | #define SIGN(x,y) ((y) >= 0.0 ? fabs(x) : -fabs(x)) 35 | #define UCHAR(x) (((x) >= 'a' && (x) <= 'z') ? ((x)&~32) : (x)) 36 | /* uppercase char of x */ 37 | #define ARRAY_LENGTH(x) (sizeof(x)/sizeof(x[0])) /* length of array x */ 38 | 39 | //------------------------------------------------- 40 | // Macro to evaluate function x with error checking 41 | //------------------------------------------------- 42 | #define CALL(x) (ErrorCode = ((ErrorCode>0) ? (ErrorCode) : (x))) 43 | 44 | 45 | #endif //MACROS_H 46 | -------------------------------------------------------------------------------- /src/solver/keywords.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // keywords.h 3 | // 4 | // Project: EPA SWMM5 5 | // Version: 5.2 6 | // Date: 11/01/21 (Build 5.2.0) 7 | // Author: L. Rossman 8 | // 9 | // Exportable keyword dictionary 10 | // 11 | // Update History 12 | // ============== 13 | // Build 5.1.008: 14 | // - Keyword arrays listed in alphabetical order. 15 | // Build 5.1.013: 16 | // - New keyword array defined for surcharge method. 17 | //----------------------------------------------------------------------------- 18 | 19 | #ifndef KEYWORDS_H 20 | #define KEYWORDS_H 21 | 22 | 23 | extern char* BuildupTypeWords[]; 24 | extern char* CurveTypeWords[]; 25 | extern char* DividerTypeWords[]; 26 | extern char* DynWaveMethodWords[]; 27 | extern char* EvapTypeWords[]; 28 | extern char* FileModeWords[]; 29 | extern char* FileTypeWords[]; 30 | extern char* FlowUnitWords[]; 31 | extern char* ForceMainEqnWords[]; 32 | extern char* GageDataWords[]; 33 | extern char* InertDampingWords[]; 34 | extern char* InfilModelWords[]; 35 | extern char* LinkOffsetWords[]; 36 | extern char* LinkTypeWords[]; 37 | extern char* LoadUnitsWords[]; 38 | extern char* NodeTypeWords[]; 39 | extern char* NoneAllWords[]; 40 | extern char* NormalFlowWords[]; 41 | extern char* NormalizerWords[]; 42 | extern char* NoYesWords[]; 43 | extern char* OldRouteModelWords[]; 44 | extern char* OffOnWords[]; 45 | extern char* OptionWords[]; 46 | extern char* OrificeTypeWords[]; 47 | extern char* OutfallTypeWords[]; 48 | extern char* PatternTypeWords[]; 49 | extern char* PondingUnitsWords[]; 50 | extern char* ProcessVarWords[]; 51 | extern char* PumpTypeWords[]; 52 | extern char* QualUnitsWords[]; 53 | extern char* RainTypeWords[]; 54 | extern char* RainUnitsWords[]; 55 | extern char* ReportWords[]; 56 | extern char* RelationWords[]; 57 | extern char* RouteModelWords[]; 58 | extern char* RuleKeyWords[]; 59 | extern char* SectWords[]; 60 | extern char* SnowmeltWords[]; 61 | extern char* SurchargeWords[]; 62 | extern char* TempKeyWords[]; 63 | extern char* TransectKeyWords[]; 64 | extern char* TreatTypeWords[]; 65 | extern char* UHTypeWords[]; 66 | extern char* VolUnitsWords[]; 67 | extern char* VolUnitsWords2[]; 68 | extern char* WashoffTypeWords[]; 69 | extern char* WeirTypeWords[]; 70 | extern char* XsectTypeWords[]; 71 | 72 | 73 | #endif //KEYWORDS_H 74 | -------------------------------------------------------------------------------- /src/solver/datetime.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // datetime.h 3 | // 4 | // Project: EPA SWMM5 5 | // Version: 5.2 6 | // Date: 11/01/21 (Build 5.2.0) 7 | // Author: L. Rossman 8 | // 9 | // The DateTime type is used to store date and time values. It is 10 | // equivalent to a double floating point type. 11 | // 12 | // The integral part of a DateTime value is the number of days that have 13 | // passed since 12/31/1899. The fractional part of a DateTime value is the 14 | // fraction of a 24 hour day that has elapsed. 15 | // 16 | // Update History 17 | // ============== 18 | // Build 5.1.011: 19 | // - New getTimeStamp function added. 20 | //----------------------------------------------------------------------------- 21 | 22 | #ifndef DATETIME_H 23 | #define DATETIME_H 24 | 25 | 26 | typedef double DateTime; 27 | 28 | #define Y_M_D 0 29 | #define M_D_Y 1 30 | #define D_M_Y 2 31 | #define NO_DATE -693594 // 1/1/0001 32 | #define DATE_STR_SIZE 12 33 | #define TIME_STR_SIZE 9 34 | #define TIME_STAMP_SIZE 21 35 | 36 | // Functions for encoding a date or time value to a DateTime value 37 | DateTime datetime_encodeDate(int year, int month, int day); 38 | DateTime datetime_encodeTime(int hour, int minute, int second); 39 | 40 | // Functions for decoding a DateTime value to a date and time 41 | void datetime_decodeDate(DateTime date, int* y, int* m, int* d); 42 | void datetime_decodeTime(DateTime time, int* h, int* m, int* s); 43 | 44 | // Function for finding day of week for a date (1 = Sunday) 45 | // month of year, days per month, and hour of day 46 | int datetime_monthOfYear(DateTime date); 47 | int datetime_dayOfYear(DateTime date); 48 | int datetime_dayOfWeek(DateTime date); 49 | int datetime_hourOfDay(DateTime date); 50 | int datetime_daysPerMonth(int year, int month); 51 | 52 | // Functions for converting a DateTime value to a string 53 | void datetime_dateToStr(DateTime date, char* s); 54 | void datetime_timeToStr(DateTime time, char* s); 55 | void datetime_getTimeStamp(int fmt, DateTime aDate, int stampSize, 56 | char* timeStamp); 57 | 58 | // Functions for converting a string date or time to a DateTime value 59 | int datetime_findMonth(char* s); 60 | int datetime_strToDate(char* s, DateTime* d); 61 | int datetime_strToTime(char* s, DateTime* t); 62 | 63 | // Function for setting date format 64 | void datetime_setDateFormat(int fmt); 65 | 66 | // Functions for adding and subtracting dates 67 | DateTime datetime_addSeconds(DateTime date1, double seconds); 68 | DateTime datetime_addDays(DateTime date1, DateTime date2); 69 | long datetime_timeDiff(DateTime date1, DateTime date2); 70 | 71 | 72 | #endif //DATETIME_H 73 | -------------------------------------------------------------------------------- /.github/workflows/build-and-test.yml: -------------------------------------------------------------------------------- 1 | name: Build and Test 2 | 3 | on: 4 | push: 5 | branches: [ master, develop, release ] 6 | pull_request: 7 | branches: [ master, develop, release ] 8 | 9 | env: 10 | OMP_NUM_THREADS: 1 11 | BUILD_HOME: build 12 | TEST_HOME: nrtests 13 | PACKAGE_NAME: vcpkg-export-20240724-151754.1.0.0 14 | PKG_NAME: vcpkg-export-20240724-151754 15 | 16 | jobs: 17 | unit_test: 18 | name: Build and unit test 19 | runs-on: windows-2019 20 | environment: testing 21 | defaults: 22 | run: 23 | shell: cmd 24 | 25 | steps: 26 | - name: Checkout repo 27 | uses: actions/checkout@v4 28 | 29 | - name: Install boost-test 30 | env: 31 | REMOTE_STORE: "https://nuget.pkg.github.com/USEPA/index.json" 32 | USERNAME: michaeltryby 33 | run: | 34 | nuget sources add -Name github -Source ${{ env.REMOTE_STORE }} -Username ${{ env.USERNAME }} -Password ${{ secrets.ACCESS_TOKEN }} 35 | nuget install ${{env.PKG_NAME}} -Source github 36 | 37 | - name: Build 38 | env: 39 | TOOL_CHAIN_PATH: \scripts\buildsystems\vcpkg.cmake 40 | run: | 41 | cmake -B.\build -DBUILD_TESTS=ON -DCMAKE_TOOLCHAIN_FILE=.\${{env.PACKAGE_NAME}}${{env.TOOL_CHAIN_PATH}} . 42 | cmake --build .\build --config DEBUG 43 | 44 | - name: Unit Test 45 | run: ctest --test-dir .\build -C Debug --output-on-failure 46 | 47 | 48 | reg_test: 49 | name: Build and reg test 50 | runs-on: windows-2019 51 | defaults: 52 | run: 53 | shell: cmd 54 | working-directory: ci-tools/windows 55 | 56 | steps: 57 | - name: Checkout swmm repo 58 | uses: actions/checkout@v4 59 | 60 | - name: Checkout ci-tools repo 61 | uses: actions/checkout@v4 62 | with: 63 | repository: USEPA/swmm-ci-tools 64 | ref: master 65 | path: ci-tools 66 | 67 | - name: Setup python 68 | uses: actions/setup-python@v5 69 | with: 70 | python-version: '3.11' 71 | 72 | - name: Install requirements 73 | run: | 74 | python -m pip install --upgrade pip 75 | python -m pip install -r requirements-swmm.txt 76 | 77 | - name: Build 78 | run: make.cmd /g "Visual Studio 16 2019" 79 | 80 | - name: Before reg test 81 | env: 82 | NRTESTS_URL: https://github.com/USEPA/swmm-nrtestsuite 83 | BENCHMARK_TAG: v2.5.0-dev 84 | run: before-nrtest.cmd ${{ env.BENCHMARK_TAG }} 85 | 86 | - name: Run reg test 87 | run: run-nrtests.cmd %GITHUB_RUN_ID%_%GITHUB_RUN_NUMBER% 88 | 89 | - name: Upload artifacts 90 | if: ${{ always() }} 91 | uses: actions/upload-artifact@v4 92 | with: 93 | name: build-test-artifacts 94 | path: upload/*.* 95 | -------------------------------------------------------------------------------- /src/solver/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # CMakeLists.txt - CMake configuration file for swmm-solver/library 3 | # 4 | # Created: Jul 11, 2019 5 | # Updated: Dec 1, 2021 6 | # 7 | # Author: Michael E. Tryby 8 | # US EPA ORD/CESER 9 | # 10 | 11 | if(APPLE) 12 | set( 13 | CMAKE_PREFIX_PATH 14 | ../../deps/openmp-16.0.0-Darwin/ 15 | ) 16 | endif() 17 | 18 | find_package( 19 | OpenMP 20 | COMPONENTS 21 | C REQUIRED 22 | ) 23 | 24 | 25 | # configure file groups 26 | set(SWMM_PUBLIC_HEADERS 27 | include/swmm5.h 28 | ) 29 | 30 | file(GLOB 31 | SWMM_SOURCES 32 | RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.c *.h 33 | ) 34 | 35 | if(BUILD_DEF) 36 | # Build library with def file interface for backward compatibility 37 | set_source_files_properties(${PROJECT_SOURCE_DIR}/bindings/swmm5.def 38 | PROPERTIES_HEADER_FILE_ONLY TRUE 39 | ) 40 | 41 | add_library(swmm5 42 | SHARED 43 | ${SWMM_SOURCES} 44 | ${PROJECT_SOURCE_DIR}/bindings/swmm5.def 45 | ) 46 | 47 | else() 48 | 49 | add_library(swmm5 50 | SHARED 51 | ${SWMM_SOURCES} 52 | ) 53 | 54 | endif() 55 | 56 | target_compile_options(swmm5 57 | PUBLIC 58 | $<$: 59 | $<$:/GL> 60 | $<$:/fp:fast> 61 | $<$:/Zi> 62 | > 63 | ) 64 | 65 | target_link_options(swmm5 66 | PUBLIC 67 | $<$: 68 | $<$:/LTCG:incremental> 69 | > 70 | ) 71 | 72 | target_link_libraries(swmm5 73 | PUBLIC 74 | $<$>>:m> 75 | $<$:OpenMP::OpenMP_C> 76 | ) 77 | 78 | target_include_directories(swmm5 79 | PUBLIC 80 | $ 81 | $ 82 | ) 83 | 84 | install(TARGETS swmm5 EXPORT swmm5Targets 85 | RUNTIME DESTINATION "${TOOL_DIST}" 86 | LIBRARY DESTINATION "${TOOL_DIST}" 87 | ARCHIVE DESTINATION "${LIBRARY_DIST}" 88 | FRAMEWORK DESTINATION "${TOOL_DIST}" 89 | ) 90 | 91 | # Create target import scripts so other cmake projects can use swmm libraries 92 | install( 93 | EXPORT 94 | swmm5Targets 95 | DESTINATION 96 | "${CONFIG_DIST}" 97 | FILE 98 | swmm5-config.cmake 99 | ) 100 | 101 | install( 102 | FILES 103 | ${SWMM_PUBLIC_HEADERS} 104 | DESTINATION 105 | "${INCLUDE_DIST}" 106 | ) 107 | 108 | 109 | # copy swmm5 to build tree for testing 110 | add_custom_command(TARGET swmm5 POST_BUILD 111 | COMMAND ${CMAKE_COMMAND} -E copy 112 | $ 113 | ${CMAKE_BINARY_DIR}/bin/$/$ 114 | ) 115 | -------------------------------------------------------------------------------- /src/outfile/include/swmm_output_enums.h: -------------------------------------------------------------------------------- 1 | /* 2 | * swmm_output_enums.h 3 | * 4 | * Created on: October 18, 2019 5 | * 6 | * Author: Michael E. Tryby 7 | * US EPA - ORD/CESER 8 | */ 9 | 10 | 11 | #ifndef SWMM_OUTPUT_ENUMS_H_ 12 | #define SWMM_OUTPUT_ENUMS_H_ 13 | 14 | 15 | typedef enum { 16 | SMO_US, 17 | SMO_SI 18 | } SMO_unitSystem; 19 | 20 | typedef enum { 21 | SMO_CFS, 22 | SMO_GPM, 23 | SMO_MGD, 24 | SMO_CMS, 25 | SMO_LPS, 26 | SMO_MLD 27 | } SMO_flowUnits; 28 | 29 | typedef enum { 30 | SMO_MG, 31 | SMO_UG, 32 | SMO_COUNT, 33 | SMO_NONE 34 | } SMO_concUnits; 35 | 36 | typedef enum { 37 | SMO_subcatch, 38 | SMO_node, 39 | SMO_link, 40 | SMO_sys, 41 | SMO_pollut 42 | } SMO_elementType; 43 | 44 | typedef enum { 45 | SMO_reportStep, 46 | SMO_numPeriods 47 | } SMO_time; 48 | 49 | typedef enum { 50 | SMO_rainfall_subcatch, // (in/hr or mm/hr), 51 | SMO_snow_depth_subcatch, // (in or mm), 52 | SMO_evap_loss, // (in/hr or mm/hr), 53 | SMO_infil_loss, // (in/hr or mm/hr), 54 | SMO_runoff_rate, // (flow units), 55 | SMO_gwoutflow_rate, // (flow units), 56 | SMO_gwtable_elev, // (ft or m), 57 | SMO_soil_moisture, // unsaturated zone moisture content (-), 58 | SMO_pollutant_conc_subcatch // first pollutant 59 | } SMO_subcatchAttribute; 60 | 61 | typedef enum { 62 | SMO_invert_depth, // (ft or m), 63 | SMO_hydraulic_head, // (ft or m), 64 | SMO_stored_ponded_volume, // (ft3 or m3), 65 | SMO_lateral_inflow, // (flow units), 66 | SMO_total_inflow, // lateral + upstream (flow units), 67 | SMO_flooding_losses, // (flow units), 68 | SMO_pollutant_conc_node // first pollutant, 69 | } SMO_nodeAttribute; 70 | 71 | typedef enum { 72 | SMO_flow_rate_link, // (flow units), 73 | SMO_flow_depth, // (ft or m), 74 | SMO_flow_velocity, // (ft/s or m/s), 75 | SMO_flow_volume, // (ft3 or m3), 76 | SMO_capacity, // (fraction of conduit filled), 77 | SMO_pollutant_conc_link // first pollutant, 78 | } SMO_linkAttribute; 79 | 80 | typedef enum { 81 | SMO_air_temp, // (deg. F or deg. C), 82 | SMO_rainfall_system, // (in/hr or mm/hr), 83 | SMO_snow_depth_system, // (in or mm), 84 | SMO_evap_infil_loss, // (in/hr or mm/hr), 85 | SMO_runoff_flow, // (flow units), 86 | SMO_dry_weather_inflow, // (flow units), 87 | SMO_groundwater_inflow, // (flow units), 88 | SMO_RDII_inflow, // (flow units), 89 | SMO_direct_inflow, // user defined (flow units), 90 | SMO_total_lateral_inflow, // (sum of variables 4 to 8) //(flow units), 91 | SMO_flood_losses, // (flow units), 92 | SMO_outfall_flows, // (flow units), 93 | SMO_volume_stored, // (ft3 or m3), 94 | SMO_evap_rate // (in/day or mm/day), 95 | //p_evap_rate // (in/day or mm/day) 96 | } SMO_systemAttribute; 97 | 98 | 99 | #endif /* SWMM_OUTPUT_ENUMS_H_ */ 100 | -------------------------------------------------------------------------------- /src/outfile/include/swmm_output.h: -------------------------------------------------------------------------------- 1 | /* 2 | * swmm_output.c - SWMM Output API 3 | * 4 | * Author: Colleen Barr 5 | * US EPA - ORD/NHEERL 6 | * 7 | * Modified by: Michael E. Tryby, 8 | * Bryant McDonnell 9 | * 10 | */ 11 | 12 | #ifndef SWMM_OUTPUT_H_ 13 | #define SWMM_OUTPUT_H_ 14 | 15 | #define MAXFILENAME 259 // Max characters in file path 16 | #define MAXELENAME 31 // Max characters in element name 17 | 18 | // This is an opaque pointer to struct. Do not access variables. 19 | typedef void *SMO_Handle; 20 | 21 | 22 | #include "swmm_output_enums.h" 23 | #include "swmm_output_export.h" 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif 28 | 29 | int EXPORT_OUT_API SMO_init(SMO_Handle *p_handle); 30 | int EXPORT_OUT_API SMO_close(SMO_Handle *p_handle); 31 | int EXPORT_OUT_API SMO_open(SMO_Handle p_handle, const char *path); 32 | int EXPORT_OUT_API SMO_getVersion(SMO_Handle p_handle, int *version); 33 | int EXPORT_OUT_API SMO_getProjectSize(SMO_Handle p_handle, int **elementCount, int *length); 34 | 35 | int EXPORT_OUT_API SMO_getUnits(SMO_Handle p_handle, int **unitFlag, int *length); 36 | int EXPORT_OUT_API SMO_getFlowUnits(SMO_Handle p_handle, int *unitFlag); 37 | int EXPORT_OUT_API SMO_getPollutantUnits(SMO_Handle p_handle, int **unitFlag, int *length); 38 | int EXPORT_OUT_API SMO_getStartDate(SMO_Handle p_handle, double *date); 39 | int EXPORT_OUT_API SMO_getTimes(SMO_Handle p_handle, SMO_time code, int *time); 40 | int EXPORT_OUT_API SMO_getElementName(SMO_Handle p_handle, SMO_elementType type, int elementIndex, char **elementName, int *size); 41 | 42 | int EXPORT_OUT_API SMO_getSubcatchSeries(SMO_Handle p_handle, int subcatchIndex, SMO_subcatchAttribute attr, int startPeriod, int endPeriod, float **outValueArray, int *length); 43 | int EXPORT_OUT_API SMO_getNodeSeries(SMO_Handle p_handle, int nodeIndex, SMO_nodeAttribute attr, int startPeriod, int endPeriod, float **outValueArray, int *length); 44 | int EXPORT_OUT_API SMO_getLinkSeries(SMO_Handle p_handle, int linkIndex, SMO_linkAttribute attr, int startPeriod, int endPeriod, float **outValueArray, int *length); 45 | int EXPORT_OUT_API SMO_getSystemSeries(SMO_Handle p_handle, SMO_systemAttribute attr, int startPeriod, int endPeriod, float **outValueArray, int *length); 46 | 47 | int EXPORT_OUT_API SMO_getSubcatchAttribute(SMO_Handle p_handle, int timeIndex, SMO_subcatchAttribute attr, float **outValueArray, int *length); 48 | int EXPORT_OUT_API SMO_getNodeAttribute(SMO_Handle p_handle, int timeIndex, SMO_nodeAttribute attr, float **outValueArray, int *length); 49 | int EXPORT_OUT_API SMO_getLinkAttribute(SMO_Handle p_handle, int timeIndex, SMO_linkAttribute attr, float **outValueArray, int *length); 50 | int EXPORT_OUT_API SMO_getSystemAttribute(SMO_Handle p_handle, int timeIndex, SMO_systemAttribute attr, float **outValueArray, int *length); 51 | 52 | int EXPORT_OUT_API SMO_getSubcatchResult(SMO_Handle p_handle, int timeIndex, int subcatchIndex, float **outValueArray, int *length); 53 | int EXPORT_OUT_API SMO_getNodeResult(SMO_Handle p_handle, int timeIndex, int nodeIndex, float **outValueArray, int *length); 54 | int EXPORT_OUT_API SMO_getLinkResult(SMO_Handle p_handle, int timeIndex, int linkIndex, float **outValueArray, int *length); 55 | int EXPORT_OUT_API SMO_getSystemResult(SMO_Handle p_handle, int timeIndex, int dummyIndex, float **outValueArray, int *length); 56 | 57 | void EXPORT_OUT_API SMO_free(void **array); 58 | void EXPORT_OUT_API SMO_clearError(SMO_Handle p_handle_in); 59 | int EXPORT_OUT_API SMO_checkError(SMO_Handle p_handle_in, char **msg_buffer); 60 | 61 | #ifdef __cplusplus 62 | } 63 | #endif 64 | 65 | #endif /* SWMM_OUTPUT_H_ */ 66 | -------------------------------------------------------------------------------- /src/run/main.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // main.c 3 | // 4 | // Project: EPA SWMM5 5 | // Version: 5.2 6 | // Date: 03/24/2021 7 | // Author: L. Rossman 8 | 9 | // Main stub for the command line version of EPA SWMM 5.2 10 | // to be run with swmm5.dll. 11 | 12 | #include 13 | #include 14 | #include 15 | #include "swmm5.h" 16 | 17 | int main(int argc, char *argv[]) 18 | // 19 | // Input: argc = number of command line arguments 20 | // argv = array of command line arguments 21 | // Output: returns error status 22 | // Purpose: runs the command line version of EPA SWMM 5.2. 23 | // 24 | // Command line is: runswmm f1 f2 f3 25 | // where f1 = name of input file, f2 = name of report file, and 26 | // f3 = name of binary output file if saved (or blank if not saved). 27 | // 28 | { 29 | char *inputFile; 30 | char *reportFile; 31 | char *binaryFile; 32 | char *arg1; 33 | char blank[] = ""; 34 | int version, vMajor, vMinor, vRelease; 35 | char errMsg[128]; 36 | int msgLen = 127; 37 | time_t start; 38 | double runTime; 39 | 40 | version = swmm_getVersion(); 41 | vMajor = version / 10000; 42 | vMinor = (version - 10000 * vMajor) / 1000; 43 | vRelease = (version - 10000 * vMajor - 1000 * vMinor); 44 | start = time(0); 45 | 46 | // --- check for proper number of command line arguments 47 | if (argc == 1) 48 | { 49 | printf("\nNot Enough Arguments (See Help --help)\n\n"); 50 | } 51 | else if (argc == 2) 52 | { 53 | // --- extract first argument 54 | arg1 = argv[1]; 55 | 56 | if (strcmp(arg1, "--help") == 0 || strcmp(arg1, "-h") == 0) 57 | { 58 | // Help 59 | printf("\n\nSTORMWATER MANAGEMENT MODEL (SWMM) HELP\n\n"); 60 | printf("COMMANDS:\n"); 61 | printf("\t--help (-h) SWMM Help\n"); 62 | printf("\t--version (-v) Build Version\n"); 63 | printf("\nRUNNING A SIMULATION:\n"); 64 | printf("\t runswmm \n\n"); 65 | } 66 | else if (strcmp(arg1, "--version") == 0 || strcmp(arg1, "-v") == 0) 67 | { 68 | // Output version number 69 | printf("\n%d.%d.%0d\n\n", vMajor, vMinor, vRelease); 70 | } 71 | else 72 | { 73 | printf("\nUnknown Argument (See Help --help)\n\n"); 74 | } 75 | } 76 | else 77 | { 78 | // --- extract file names from command line arguments 79 | inputFile = argv[1]; 80 | reportFile = argv[2]; 81 | if (argc > 3) binaryFile = argv[3]; 82 | else binaryFile = blank; 83 | printf("\n... EPA SWMM %d.%d (Build %d.%d.%0d)\n", vMajor, vMinor, 84 | vMajor, vMinor, vRelease); 85 | 86 | // --- run SWMM 87 | swmm_run(inputFile, reportFile, binaryFile); 88 | 89 | // Display closing status on console 90 | runTime = difftime(time(0), start); 91 | printf("\n\n... EPA SWMM completed in %.2f seconds.", runTime); 92 | if ( swmm_getError(errMsg, msgLen) > 0 ) printf(" There are errors.\n"); 93 | else if ( swmm_getWarnings() > 0 ) printf(" There are warnings.\n"); 94 | else printf("\n"); 95 | } 96 | 97 | // --- Use the code below if you need to keep the console window visible 98 | /* 99 | printf(" Press Enter to continue..."); 100 | getchar(); 101 | */ 102 | 103 | return 0; 104 | } -------------------------------------------------------------------------------- /src/solver/hash.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // hash.c 3 | // 4 | // Implementation of a simple Hash Table for string storage & retrieval 5 | // CASE INSENSITIVE 6 | // 7 | // Written by L. Rossman 8 | // Last Updated on 6/19/03 9 | // 10 | // The hash table data structure (HTable) is defined in "hash.h". 11 | // Interface Functions: 12 | // HTcreate() - creates a hash table 13 | // HTinsert() - inserts a string & its index value into a hash table 14 | // HTfind() - retrieves the index value of a string from a table 15 | // HTfree() - frees a hash table 16 | //----------------------------------------------------------------------------- 17 | 18 | #include 19 | #include 20 | #include "hash.h" 21 | #define UCHAR(x) (((x) >= 'a' && (x) <= 'z') ? ((x)&~32) : (x)) 22 | 23 | /* Case-insensitive comparison of strings s1 and s2 */ 24 | int samestr(const char *s1, const char *s2) 25 | { 26 | int i; 27 | for (i=0; UCHAR(s1[i]) == UCHAR(s2[i]); i++) 28 | if (!s1[i+1] && !s2[i+1]) return(1); 29 | return(0); 30 | } /* End of samestr */ 31 | 32 | /* Use Fletcher's checksum to compute 2-byte hash of string */ 33 | unsigned int hash(const char *str) 34 | { 35 | unsigned int sum1= 0, check1; 36 | unsigned long sum2= 0L; 37 | while( '\0' != *str ) 38 | { 39 | sum1 += UCHAR(*str); 40 | str++; 41 | if ( 255 <= sum1 ) sum1 -= 255; 42 | sum2 += sum1; 43 | } 44 | check1= sum2; 45 | check1 %= 255; 46 | check1= 255 - (sum1+check1) % 255; 47 | sum1= 255 - (sum1+check1) % 255; 48 | return( ( ( check1 << 8 ) | sum1 ) % HTMAXSIZE); 49 | } 50 | 51 | HTtable *HTcreate() 52 | { 53 | int i; 54 | HTtable *ht = (HTtable *) calloc(HTMAXSIZE, sizeof(HTtable)); 55 | if (ht != NULL) for (i=0; i= HTMAXSIZE ) return(0); 64 | entry = (struct HTentry *) malloc(sizeof(struct HTentry)); 65 | if (entry == NULL) return(0); 66 | entry->key = key; 67 | entry->data = data; 68 | entry->next = ht[i]; 69 | ht[i] = entry; 70 | return(1); 71 | } 72 | 73 | int HTfind(HTtable *ht, const char *key) 74 | { 75 | unsigned int i = hash(key); 76 | struct HTentry *entry; 77 | if ( i >= HTMAXSIZE ) return(NOTFOUND); 78 | entry = ht[i]; 79 | while (entry != NULL) 80 | { 81 | if ( samestr(entry->key,key) ) return(entry->data); 82 | entry = entry->next; 83 | } 84 | return(NOTFOUND); 85 | } 86 | 87 | char *HTfindKey(HTtable *ht, const char *key) 88 | { 89 | unsigned int i = hash(key); 90 | struct HTentry *entry; 91 | if ( i >= HTMAXSIZE ) return(NULL); 92 | entry = ht[i]; 93 | while (entry != NULL) 94 | { 95 | if ( samestr(entry->key,key) ) return(entry->key); 96 | entry = entry->next; 97 | } 98 | return(NULL); 99 | } 100 | 101 | void HTfree(HTtable *ht) 102 | { 103 | struct HTentry *entry, 104 | *nextentry; 105 | int i; 106 | for (i=0; inext; 112 | free(entry); 113 | entry = nextentry; 114 | } 115 | } 116 | free(ht); 117 | } 118 | -------------------------------------------------------------------------------- /src/solver/consts.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // consts.h 3 | // 4 | // Project: EPA SWMM5 5 | // Version: 5.2 6 | // Date: 07/15/23 (Build 5.2.4) 7 | // Author: L. Rossman 8 | // 9 | // Various Constants 10 | //----------------------------------------------------------------------------- 11 | 12 | #ifndef CONSTS_H 13 | #define CONSTS_H 14 | 15 | //------------------ 16 | // General Constants 17 | //------------------ 18 | 19 | #define VERSION 52004 20 | #define MAGICNUMBER 516114522 21 | #define EOFMARK 0x1A // Use 0x04 for UNIX systems 22 | #define MAXTITLE 3 // Max. # title lines 23 | #define MAXMSG 1024 // Max. # characters in message text 24 | #define MAXLINE 1024 // Max. # characters per input line 25 | #define MAXFNAME 259 // Max. # characters in file name 26 | #define MAXTOKS 40 // Max. items per line of input 27 | #define MAXSTATES 10 // Max. # computed hyd. variables 28 | #define MAXODES 4 // Max. # ODE's to be solved 29 | #define NA -1 // NOT APPLICABLE code 30 | #define TRUE 1 // Value for TRUE state 31 | #define FALSE 0 // Value for FALSE state 32 | #define BIG 1.E10 // Generic large value 33 | #define TINY 1.E-6 // Generic small value 34 | #define ZERO 1.E-10 // Effective zero value 35 | #define MISSING -1.E10 // Missing value code 36 | #define PI 3.141592654 // Value of pi 37 | #define GRAVITY 32.2 // accel. of gravity in US units 38 | #define SI_GRAVITY 9.81 // accel of gravity in SI units 39 | /* DEPRECATED 40 | #define MAXFILESIZE 2147483647L // largest file size in bytes 41 | */ 42 | 43 | //----------------------------- 44 | // Units factor in Manning Eqn. 45 | //----------------------------- 46 | #define PHI 1.486 47 | 48 | //---------------------------------------------- 49 | // Definition of measureable runoff flow & depth 50 | //---------------------------------------------- 51 | #define MIN_RUNOFF_FLOW 0.001 // cfs 52 | #define MIN_EXCESS_DEPTH 0.0001 // ft, = 0.03 mm 53 | #define MIN_TOTAL_DEPTH 0.004167 // ft, = 0.05 inches 54 | #define MIN_RUNOFF 2.31481e-8 // ft/sec = 0.001 in/hr 55 | 56 | //---------------------------------------------------------------------- 57 | // Minimum flow, depth & volume used to evaluate steady state conditions 58 | //---------------------------------------------------------------------- 59 | #define FLOW_TOL 0.00001 // cfs 60 | #define DEPTH_TOL 0.00001 // ft 61 | #define VOLUME_TOL 0.01 // ft3 62 | 63 | //--------------------------------------------------- 64 | // Minimum depth for reporting non-zero water quality 65 | //--------------------------------------------------- 66 | //#define MIN_WQ_DEPTH 0.01 // ft (= 3 mm) 67 | //#define MIN_WQ_FLOW 0.001 // cfs 68 | 69 | //----------------------------------------------------- 70 | // Minimum flow depth and area for dynamic wave routing 71 | //----------------------------------------------------- 72 | #define FUDGE 0.0001 // ft or ft2 73 | 74 | //--------------------------- 75 | // Various conversion factors 76 | //--------------------------- 77 | #define GPMperCFS 448.831 78 | #define AFDperCFS 1.9837 79 | #define MGDperCFS 0.64632 80 | #define IMGDperCFS 0.5382 81 | #define LPSperCFS 28.317 82 | #define LPMperCFS 1699.0 83 | #define CMHperCFS 101.94 84 | #define CMDperCFS 2446.6 85 | #define MLDperCFS 2.4466 86 | #define M3perFT3 0.028317 87 | #define LperFT3 28.317 88 | #define MperFT 0.3048 89 | #define PSIperFT 0.4333 90 | #define KPAperPSI 6.895 91 | #define KWperHP 0.7457 92 | #define SECperDAY 86400 93 | #define MSECperDAY 8.64e7 94 | #define MMperINCH 25.40 95 | 96 | //--------------------------- 97 | // Token separator characters 98 | //--------------------------- 99 | #define SEPSTR " \t\n\r" 100 | 101 | 102 | #endif //CONSTS_H 103 | -------------------------------------------------------------------------------- /src/solver/findroot.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // findroot.c 3 | // 4 | // Finds solution of func(x) = 0 using either the Newton-Raphson 5 | // method or Ridder's Method. 6 | // Based on code from Numerical Recipes in C (Cambridge University 7 | // Press, 1992). 8 | // 9 | // Date: 11/19/13 10 | // Author: L. Rossman 11 | //----------------------------------------------------------------------------- 12 | 13 | #include 14 | #include "findroot.h" 15 | 16 | #define SIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a)) 17 | #define MAXIT 60 18 | 19 | 20 | int findroot_Newton(double x1, double x2, double* rts, double xacc, 21 | void (*func) (double x, double* f, double* df, void* p), 22 | void* p) 23 | // 24 | // Using a combination of Newton-Raphson and bisection, find the root of a 25 | // function func bracketed between x1 and x2. The root, returned in rts, 26 | // will be refined until its accuracy is known within +/-xacc. func is a 27 | // user-supplied routine, that returns both the function value and the first 28 | // derivative of the function. p is a pointer to any auxilary data structure 29 | // that func may require. It can be NULL if not needed. The function returns 30 | // the number of function evaluations used or 0 if the maximum allowed 31 | // iterations were exceeded. 32 | // 33 | // NOTES: 34 | // 1. The calling program must insure that the signs of func(x1) and func(x2) 35 | // are not the same, otherwise x1 and x2 do not bracket the root. 36 | // 2. If func(x1) > func(x2) then the order of x1 and x2 should be 37 | // switched in the call to Newton. 38 | // 39 | { 40 | int j, n = 0; 41 | double df, dx, dxold, f, x; 42 | double temp, xhi, xlo; 43 | 44 | // Initialize the "stepsize before last" and the last step. 45 | x = *rts; 46 | xlo = x1; 47 | xhi = x2; 48 | dxold = fabs(x2-x1); 49 | dx = dxold; 50 | func(x, &f, &df, p); 51 | n++; 52 | 53 | // Loop over allowed iterations. 54 | for (j=1; j<=MAXIT; j++) 55 | { 56 | // Bisect if Newton out of range or not decreasing fast enough. 57 | if ( ( ( (x-xhi)*df-f)*((x-xlo)*df-f) >= 0.0 58 | || (fabs(2.0*f) > fabs(dxold*df) ) ) ) 59 | { 60 | dxold = dx; 61 | dx = 0.5*(xhi-xlo); 62 | x = xlo + dx; 63 | if ( xlo == x ) break; 64 | } 65 | 66 | // Newton step acceptable. Take it. 67 | else 68 | { 69 | dxold = dx; 70 | dx = f/df; 71 | temp = x; 72 | x -= dx; 73 | if ( temp == x ) break; 74 | } 75 | 76 | // Convergence criterion. 77 | if ( fabs(dx) < xacc ) break; 78 | 79 | // Evaluate function. Maintain bracket on the root. 80 | func(x, &f, &df, p); 81 | n++; 82 | if ( f < 0.0 ) xlo = x; 83 | else xhi = x; 84 | } 85 | *rts = x; 86 | if ( n <= MAXIT) return n; 87 | else return 0; 88 | }; 89 | 90 | 91 | double findroot_Ridder(double x1, double x2, double xacc, 92 | double (*func)(double, void* p), void* p) 93 | { 94 | int j; 95 | double ans, fhi, flo, fm, fnew, s, xhi, xlo, xm, xnew; 96 | 97 | flo = func(x1, p); 98 | fhi = func(x2, p); 99 | if ( flo == 0.0 ) return x1; 100 | if ( fhi == 0.0 ) return x2; 101 | ans = 0.5*(x1+x2); 102 | if ( (flo > 0.0 && fhi < 0.0) || (flo < 0.0 && fhi > 0.0) ) 103 | { 104 | xlo = x1; 105 | xhi = x2; 106 | for (j=1; j<=MAXIT; j++) { 107 | xm = 0.5*(xlo + xhi); 108 | fm = func(xm, p); 109 | s = sqrt( fm*fm - flo*fhi ); 110 | if (s == 0.0) return ans; 111 | xnew = xm + (xm-xlo)*( (flo >= fhi ? 1.0 : -1.0)*fm/s ); 112 | if ( fabs(xnew - ans) <= xacc ) break; 113 | ans = xnew; 114 | fnew = func(ans, p); 115 | if ( SIGN(fm, fnew) != fm) 116 | { 117 | xlo = xm; 118 | flo = fm; 119 | xhi = ans; 120 | fhi = fnew; 121 | } 122 | else if ( SIGN(flo, fnew) != flo ) 123 | { 124 | xhi = ans; 125 | fhi = fnew; 126 | } 127 | else if ( SIGN(fhi, fnew) != fhi) 128 | { 129 | xlo = ans; 130 | flo = fnew; 131 | } 132 | else return ans; 133 | if ( fabs(xhi - xlo) <= xacc ) return ans; 134 | } 135 | return ans; 136 | } 137 | return -1.e20; 138 | } 139 | -------------------------------------------------------------------------------- /src/solver/infil.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // infil.h 3 | // 4 | // Project: EPA SWMM5 5 | // Version: 5.2 6 | // Date: 11/01/21 (Build 5.2.0) 7 | // Author: L. Rossman 8 | // 9 | // Public interface for infiltration functions. 10 | // 11 | // Update History 12 | // ============== 13 | // Build 5.1.010: 14 | // - New Modified Green Ampt infiltration option added. 15 | // Build 5.1.013: 16 | // - New function infil_setInfilFactor() added. 17 | // Build 5.1.015: 18 | // - Support added for multiple infiltration methods within a project. 19 | //----------------------------------------------------------------------------- 20 | 21 | #ifndef INFIL_H 22 | #define INFIL_H 23 | 24 | //--------------------- 25 | // Enumerated Constants 26 | //--------------------- 27 | enum InfilType { 28 | HORTON, // Horton infiltration 29 | MOD_HORTON, // Modified Horton infiltration 30 | GREEN_AMPT, // Green-Ampt infiltration 31 | MOD_GREEN_AMPT, // Modified Green-Ampt infiltration 32 | CURVE_NUMBER}; // SCS Curve Number infiltration 33 | 34 | //--------------------- 35 | // Horton Infiltration 36 | //--------------------- 37 | typedef struct 38 | { 39 | double f0; // initial infil. rate (ft/sec) 40 | double fmin; // minimum infil. rate (ft/sec) 41 | double Fmax; // maximum total infiltration (ft); 42 | double decay; // decay coeff. of infil. rate (1/sec) 43 | double regen; // regeneration coeff. of infil. rate (1/sec) 44 | //----------------------------- 45 | double tp; // present time on infiltration curve (sec) 46 | double Fe; // cumulative infiltration (ft) 47 | } THorton; 48 | 49 | 50 | //------------------------- 51 | // Green-Ampt Infiltration 52 | //------------------------- 53 | typedef struct 54 | { 55 | double S; // avg. capillary suction (ft) 56 | double Ks; // saturated conductivity (ft/sec) 57 | double IMDmax; // max. soil moisture deficit (ft/ft) 58 | //----------------------------- 59 | double IMD; // current initial soil moisture deficit 60 | double F; // current cumulative infiltrated volume (ft) 61 | double Fu; // current upper zone infiltrated volume (ft) 62 | double Lu; // depth of upper soil zone (ft) 63 | double T; // time until start of next rain event (sec) 64 | char Sat; // saturation flag 65 | } TGrnAmpt; 66 | 67 | 68 | //-------------------------- 69 | // Curve Number Infiltration 70 | //-------------------------- 71 | typedef struct 72 | { 73 | double Smax; // max. infiltration capacity (ft) 74 | double regen; // infil. capacity regeneration constant (1/sec) 75 | double Tmax; // maximum inter-event time (sec) 76 | //----------------------------- 77 | double S; // current infiltration capacity (ft) 78 | double F; // current cumulative infiltration (ft) 79 | double P; // current cumulative precipitation (ft) 80 | double T; // current inter-event time (sec) 81 | double Se; // current event infiltration capacity (ft) 82 | double f; // previous infiltration rate (ft/sec) 83 | 84 | } TCurveNum; 85 | 86 | //----------------------------------------------------------------------------- 87 | // Exported Variables 88 | //----------------------------------------------------------------------------- 89 | extern THorton* HortInfil; 90 | extern TGrnAmpt* GAInfil; 91 | extern TCurveNum* CNInfil; 92 | 93 | //----------------------------------------------------------------------------- 94 | // Infiltration Methods 95 | //----------------------------------------------------------------------------- 96 | void infil_create(int n); 97 | void infil_delete(void); 98 | int infil_readParams(int m, char* tok[], int ntoks); 99 | void infil_initState(int j); 100 | void infil_getState(int j, double x[]); 101 | void infil_setState(int j, double x[]); 102 | void infil_setInfilFactor(int j); 103 | double infil_getInfil(int area, double tstep, double rainfall, double runon, 104 | double depth); 105 | 106 | void grnampt_getParams(int j, double p[]); 107 | int grnampt_setParams(TGrnAmpt *infil, double p[]); 108 | void grnampt_initState(TGrnAmpt *infil); 109 | double grnampt_getInfil(TGrnAmpt *infil, double tstep, double irate, 110 | double depth, int modelType); 111 | 112 | #endif 113 | -------------------------------------------------------------------------------- /src/solver/include/swmm5.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // swmm5.h 3 | // 4 | // Project: EPA SWMM5 5 | // Version: 5.2 6 | // Date: 11/01/21 (Build 5.2.0) 7 | // Author: L. Rossman 8 | // 9 | // Prototypes for SWMM5 API functions. 10 | // 11 | //----------------------------------------------------------------------------- 12 | 13 | #ifndef SWMM5_H 14 | #define SWMM5_H 15 | 16 | // --- define WINDOWS 17 | 18 | #undef WINDOWS 19 | #ifdef _WIN32 20 | #define WINDOWS 21 | #endif 22 | #ifdef __WIN32__ 23 | #define WINDOWS 24 | #endif 25 | 26 | // --- define DLLEXPORT 27 | 28 | #ifdef WINDOWS 29 | #define DLLEXPORT __declspec(dllexport) __stdcall 30 | #else 31 | #define DLLEXPORT 32 | #endif 33 | 34 | // --- use "C" linkage for C++ programs 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | typedef enum { 41 | swmm_GAGE = 0, 42 | swmm_SUBCATCH = 1, 43 | swmm_NODE = 2, 44 | swmm_LINK = 3, 45 | swmm_SYSTEM = 100 46 | } swmm_Object; 47 | 48 | typedef enum { 49 | swmm_JUNCTION = 0, 50 | swmm_OUTFALL = 1, 51 | swmm_STORAGE = 2, 52 | swmm_DIVIDER = 3 53 | } swmm_NodeType; 54 | 55 | typedef enum { 56 | swmm_CONDUIT = 0, 57 | swmm_PUMP = 1, 58 | swmm_ORIFICE = 2, 59 | swmm_WEIR = 3, 60 | swmm_OUTLET = 4 61 | } swmm_LinkType; 62 | 63 | typedef enum { 64 | swmm_GAGE_RAINFALL = 100 65 | } swmm_GageProperty; 66 | 67 | typedef enum { 68 | swmm_SUBCATCH_AREA = 200, 69 | swmm_SUBCATCH_RAINGAGE = 201, 70 | swmm_SUBCATCH_RAINFALL = 202, 71 | swmm_SUBCATCH_EVAP = 203, 72 | swmm_SUBCATCH_INFIL = 204, 73 | swmm_SUBCATCH_RUNOFF = 205, 74 | swmm_SUBCATCH_RPTFLAG = 206 75 | } swmm_SubcatchProperty; 76 | 77 | typedef enum { 78 | swmm_NODE_TYPE = 300, 79 | swmm_NODE_ELEV = 301, 80 | swmm_NODE_MAXDEPTH = 302, 81 | swmm_NODE_DEPTH = 303, 82 | swmm_NODE_HEAD = 304, 83 | swmm_NODE_VOLUME = 305, 84 | swmm_NODE_LATFLOW = 306, 85 | swmm_NODE_INFLOW = 307, 86 | swmm_NODE_OVERFLOW = 308, 87 | swmm_NODE_RPTFLAG = 309 88 | } swmm_NodeProperty; 89 | 90 | typedef enum { 91 | swmm_LINK_TYPE = 400, 92 | swmm_LINK_NODE1 = 401, 93 | swmm_LINK_NODE2 = 402, 94 | swmm_LINK_LENGTH = 403, 95 | swmm_LINK_SLOPE = 404, 96 | swmm_LINK_FULLDEPTH = 405, 97 | swmm_LINK_FULLFLOW = 406, 98 | swmm_LINK_SETTING = 407, 99 | swmm_LINK_TIMEOPEN = 408, 100 | swmm_LINK_TIMECLOSED = 409, 101 | swmm_LINK_FLOW = 410, 102 | swmm_LINK_DEPTH = 411, 103 | swmm_LINK_VELOCITY = 412, 104 | swmm_LINK_TOPWIDTH = 413, 105 | swmm_LINK_RPTFLAG = 414 106 | } swmm_LinkProperty; 107 | 108 | typedef enum { 109 | swmm_STARTDATE = 0, 110 | swmm_CURRENTDATE = 1, 111 | swmm_ELAPSEDTIME = 2, 112 | swmm_ROUTESTEP = 3, 113 | swmm_MAXROUTESTEP = 4, 114 | swmm_REPORTSTEP = 5, 115 | swmm_TOTALSTEPS = 6, 116 | swmm_NOREPORT = 7, 117 | swmm_FLOWUNITS = 8 118 | } swmm_SystemProperty; 119 | 120 | typedef enum { 121 | swmm_CFS = 0, // cubic feet per second 122 | swmm_GPM = 1, // gallons per minute 123 | swmm_MGD = 2, // million gallons per day 124 | swmm_CMS = 3, // cubic meters per second 125 | swmm_LPS = 4, // liters per second 126 | swmm_MLD = 5 // million liters per day 127 | } swmm_FlowUnitsProperty; 128 | 129 | int DLLEXPORT swmm_run(const char *f1, const char *f2, const char *f3); 130 | int DLLEXPORT swmm_open(const char *f1, const char *f2, const char *f3); 131 | int DLLEXPORT swmm_start(int saveFlag); 132 | int DLLEXPORT swmm_step(double *elapsedTime); 133 | int DLLEXPORT swmm_stride(int strideStep, double *elapsedTime); 134 | int DLLEXPORT swmm_end(void); 135 | int DLLEXPORT swmm_report(void); 136 | int DLLEXPORT swmm_close(void); 137 | 138 | int DLLEXPORT swmm_getMassBalErr(float *runoffErr, float *flowErr, float *qualErr); 139 | int DLLEXPORT swmm_getVersion(void); 140 | int DLLEXPORT swmm_getError(char *errMsg, int msgLen); 141 | int DLLEXPORT swmm_getWarnings(void); 142 | 143 | int DLLEXPORT swmm_getCount(int objType); 144 | void DLLEXPORT swmm_getName(int objType, int index, char *name, int size); 145 | int DLLEXPORT swmm_getIndex(int objType, const char *name); 146 | double DLLEXPORT swmm_getValue(int property, int index); 147 | void DLLEXPORT swmm_setValue(int property, int index, double value); 148 | double DLLEXPORT swmm_getSavedValue(int property, int index, int period); 149 | void DLLEXPORT swmm_writeLine(const char *line); 150 | void DLLEXPORT swmm_decodeDate(double date, int *year, int *month, int *day, 151 | int *hour, int *minute, int *second, int *dayOfWeek); 152 | 153 | #ifdef __cplusplus 154 | } // matches the linkage specification from above */ 155 | #endif 156 | 157 | #endif //SWMM5_H 158 | -------------------------------------------------------------------------------- /src/solver/mempool.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // mempool.c 3 | // 4 | // A simple fast memory allocation package. 5 | // 6 | // By Steve Hill in Graphics Gems III, David Kirk (ed.), 7 | // Academic Press, Boston, MA, 1992 8 | // 9 | // Modified by L. Rossman, 8/13/94. 10 | // 11 | // AllocInit() - create an alloc pool, returns the old pool handle 12 | // Alloc() - allocate memory 13 | // AllocReset() - reset the current pool 14 | // AllocSetPool() - set the current pool 15 | // AllocFree() - free the memory used by the current pool. 16 | //----------------------------------------------------------------------------- 17 | 18 | 19 | #include 20 | #include "mempool.h" 21 | 22 | /* 23 | ** ALLOC_BLOCK_SIZE - adjust this size to suit your installation - it 24 | ** should be reasonably large otherwise you will be mallocing a lot. 25 | */ 26 | 27 | #define ALLOC_BLOCK_SIZE 64000 /*(62*1024)*/ 28 | 29 | /* 30 | ** alloc_hdr_t - Header for each block of memory. 31 | */ 32 | 33 | typedef struct alloc_hdr_s 34 | { 35 | struct alloc_hdr_s *next; /* Next Block */ 36 | char *block, /* Start of block */ 37 | *free, /* Next free in block */ 38 | *end; /* block + block size */ 39 | } alloc_hdr_t; 40 | 41 | /* 42 | ** alloc_root_t - Header for the whole pool. 43 | */ 44 | 45 | typedef struct alloc_root_s 46 | { 47 | alloc_hdr_t *first, /* First header in pool */ 48 | *current; /* Current header */ 49 | } alloc_root_t; 50 | 51 | /* 52 | ** root - Pointer to the current pool. 53 | */ 54 | 55 | static alloc_root_t *root; 56 | 57 | 58 | /* 59 | ** AllocHdr() 60 | ** 61 | ** Private routine to allocate a header and memory block. 62 | */ 63 | 64 | static alloc_hdr_t *AllocHdr(void); 65 | 66 | static alloc_hdr_t * AllocHdr() 67 | { 68 | alloc_hdr_t *hdr; 69 | char *block; 70 | 71 | block = (char *) malloc(ALLOC_BLOCK_SIZE); 72 | hdr = (alloc_hdr_t *) malloc(sizeof(alloc_hdr_t)); 73 | 74 | if (hdr == NULL || block == NULL) return(NULL); 75 | hdr->block = block; 76 | hdr->free = block; 77 | hdr->next = NULL; 78 | hdr->end = block + ALLOC_BLOCK_SIZE; 79 | 80 | return(hdr); 81 | } 82 | 83 | 84 | /* 85 | ** AllocInit() 86 | ** 87 | ** Create a new memory pool with one block. 88 | ** Returns pointer to the new pool. 89 | */ 90 | 91 | alloc_handle_t * AllocInit() 92 | { 93 | alloc_handle_t *newpool; 94 | 95 | root = (alloc_root_t *) malloc(sizeof(alloc_root_t)); 96 | if (root == NULL) return(NULL); 97 | if ( (root->first = AllocHdr()) == NULL) return(NULL); 98 | root->current = root->first; 99 | newpool = (alloc_handle_t *) root; 100 | return(newpool); 101 | } 102 | 103 | 104 | /* 105 | ** Alloc() 106 | ** 107 | ** Use as a direct replacement for malloc(). Allocates 108 | ** memory from the current pool. 109 | */ 110 | 111 | char * Alloc(long size) 112 | { 113 | alloc_hdr_t *hdr = root->current; 114 | char *ptr; 115 | 116 | /* 117 | ** Align to 4 byte boundary - should be ok for most machines. 118 | ** Change this if your machine has weird alignment requirements. 119 | */ 120 | size = (size + 3) & 0xfffffffc; 121 | 122 | ptr = hdr->free; 123 | hdr->free += size; 124 | 125 | /* Check if the current block is exhausted. */ 126 | 127 | if (hdr->free >= hdr->end) 128 | { 129 | /* Is the next block already allocated? */ 130 | 131 | if (hdr->next != NULL) 132 | { 133 | /* re-use block */ 134 | hdr->next->free = hdr->next->block; 135 | root->current = hdr->next; 136 | } 137 | else 138 | { 139 | /* extend the pool with a new block */ 140 | if ( (hdr->next = AllocHdr()) == NULL) return(NULL); 141 | root->current = hdr->next; 142 | } 143 | 144 | /* set ptr to the first location in the next block */ 145 | ptr = root->current->free; 146 | root->current->free += size; 147 | } 148 | 149 | /* Return pointer to allocated memory. */ 150 | 151 | return(ptr); 152 | } 153 | 154 | 155 | /* 156 | ** AllocSetPool() 157 | ** 158 | ** Change the current pool. Return the old pool. 159 | */ 160 | 161 | alloc_handle_t * AllocSetPool(alloc_handle_t *newpool) 162 | { 163 | alloc_handle_t *old = (alloc_handle_t *) root; 164 | root = (alloc_root_t *) newpool; 165 | return(old); 166 | } 167 | 168 | 169 | /* 170 | ** AllocReset() 171 | ** 172 | ** Reset the current pool for re-use. No memory is freed, 173 | ** so this is very fast. 174 | */ 175 | 176 | void AllocReset() 177 | { 178 | root->current = root->first; 179 | root->current->free = root->current->block; 180 | } 181 | 182 | 183 | /* 184 | ** AllocFreePool() 185 | ** 186 | ** Free the memory used by the current pool. 187 | ** Don't use where AllocReset() could be used. 188 | */ 189 | 190 | void AllocFreePool() 191 | { 192 | alloc_hdr_t *tmp, 193 | *hdr = root->first; 194 | 195 | while (hdr != NULL) 196 | { 197 | tmp = hdr->next; 198 | free((char *) hdr->block); 199 | free((char *) hdr); 200 | hdr = tmp; 201 | } 202 | free((char *) root); 203 | root = NULL; 204 | } 205 | -------------------------------------------------------------------------------- /src/solver/forcmain.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // forcemain.c 3 | // 4 | // Project: EPA SWMM5 5 | // Version: 5.2 6 | // Date: 11/01/21 (Build 5.2.0) 7 | // Author: L. Rossman 8 | // 9 | // Special Non-Manning Force Main functions 10 | //----------------------------------------------------------------------------- 11 | #define _CRT_SECURE_NO_DEPRECATE 12 | 13 | #include 14 | #include "headers.h" 15 | 16 | //----------------------------------------------------------------------------- 17 | // Constants 18 | //----------------------------------------------------------------------------- 19 | static const double VISCOS = 1.1E-5; // Kinematic viscosity of water 20 | // @ 20 deg C (sq ft/sec) 21 | 22 | //----------------------------------------------------------------------------- 23 | // External functions (declared in funcs.h) 24 | //----------------------------------------------------------------------------- 25 | // forcemain_getEquivN 26 | // forcemain_getRoughFactor 27 | // forcemain_getFricSlope 28 | 29 | //----------------------------------------------------------------------------- 30 | // Local functions 31 | //----------------------------------------------------------------------------- 32 | static double forcemain_getFricFactor(double e, double hrad, double re); 33 | static double forcemain_getReynolds(double v, double hrad); 34 | 35 | //============================================================================= 36 | 37 | double forcemain_getEquivN(int j, int k) 38 | // 39 | // Input: j = link index 40 | // k = conduit index 41 | // Output: returns an equivalent Manning's n for a force main 42 | // Purpose: computes a Mannng's n that results in the same normal flow 43 | // value for a force main flowing full under fully turbulent 44 | // conditions using either the Hazen-Williams or Dary-Weisbach 45 | // flow equations. 46 | // 47 | { 48 | TXsect xsect = Link[j].xsect; 49 | double f; 50 | double d = xsect.yFull; 51 | switch ( ForceMainEqn ) 52 | { 53 | case H_W: 54 | return 1.067 / xsect.rBot * pow(d/Conduit[k].slope, 0.04); 55 | case D_W: 56 | f = forcemain_getFricFactor(xsect.rBot, d/4.0, 1.0e12); 57 | return sqrt(f/185.0) * pow(d, (1./6.)); 58 | } 59 | return Conduit[k].roughness; 60 | } 61 | 62 | //============================================================================= 63 | 64 | double forcemain_getRoughFactor(int j, double lengthFactor) 65 | // 66 | // Input: j = link index 67 | // lengthFactor = factor by which a pipe will be artifically lengthened 68 | // Output: returns a roughness adjustment factor for a force main 69 | // Purpose: computes an adjustment factor for a force main that compensates for 70 | // any artificial lengthening the pipe may have received. 71 | // 72 | { 73 | TXsect xsect = Link[j].xsect; 74 | double r; 75 | switch ( ForceMainEqn ) 76 | { 77 | case H_W: 78 | r = 1.318*xsect.rBot*pow(lengthFactor, 0.54); 79 | return GRAVITY / pow(r, 1.852); 80 | case D_W: 81 | return 1.0/8.0/lengthFactor; 82 | } 83 | return 0.0; 84 | } 85 | 86 | //============================================================================= 87 | 88 | double forcemain_getFricSlope(int j, double v, double hrad) 89 | // 90 | // Input: j = link index 91 | // v = flow velocity (ft/sec) 92 | // hrad = hydraulic radius (ft) 93 | // Output: returns a force main pipe's friction slope 94 | // Purpose: computes the headloss per unit length used in dynamic wave 95 | // flow routing for a pressurized force main using either the 96 | // Hazen-Williams or Darcy-Weisbach flow equations. 97 | // Note: the pipe's roughness factor was saved in xsect.sBot in 98 | // conduit_validate() in LINK.C. 99 | // 100 | { 101 | double re, f; 102 | TXsect xsect = Link[j].xsect; 103 | switch ( ForceMainEqn ) 104 | { 105 | case H_W: 106 | return xsect.sBot * pow(v, 0.852) / pow(hrad, 1.1667); 107 | case D_W: 108 | re = forcemain_getReynolds(v, hrad); 109 | f = forcemain_getFricFactor(xsect.rBot, hrad, re); 110 | return f * xsect.sBot * v / hrad; 111 | } 112 | return 0.0; 113 | } 114 | 115 | //============================================================================= 116 | 117 | double forcemain_getReynolds(double v, double hrad) 118 | // 119 | // Input: v = flow velocity (ft/sec) 120 | // hrad = hydraulic radius (ft) 121 | // Output: returns a flow's Reynolds Number 122 | // Purpose: computes a flow's Reynolds Number 123 | // 124 | { 125 | return 4.0 * hrad * v / VISCOS; 126 | } 127 | 128 | //============================================================================= 129 | 130 | double forcemain_getFricFactor(double e, double hrad, double re) 131 | // 132 | // Input: e = roughness height (ft) 133 | // hrad = hydraulic radius (ft) 134 | // re = Reynolds number 135 | // Output: returns a Darcy-Weisbach friction factor 136 | // Purpose: computes the Darcy-Weisbach friction factor for a force main 137 | // using the Swamee and Jain approximation to the Colebrook-White 138 | // equation. 139 | // 140 | { 141 | double f; 142 | if ( re < 10.0 ) re = 10.0; 143 | if ( re <= 2000.0 ) f = 64.0 / re; 144 | else if ( re < 4000.0 ) 145 | { 146 | f = forcemain_getFricFactor(e, hrad, 4000.0); 147 | f = 0.032 + (f - 0.032) * ( re - 2000.0) / 2000.0; 148 | } 149 | else 150 | { 151 | f = e/3.7/(4.0*hrad); 152 | if ( re < 1.0e10 ) f += 5.74/pow(re, 0.9); 153 | f = log10(f); 154 | f = 0.25 / f / f; 155 | } 156 | return f; 157 | } 158 | -------------------------------------------------------------------------------- /src/solver/street.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // street.c 3 | // 4 | // Project: EPA SWMM5 5 | // Version: 5.2 6 | // Date: 07/13/23 (Build 5.2.4) 7 | // Author: L. Rossman 8 | // 9 | // Street Cross-Section Functions 10 | // 11 | // Build 5.2.4: 12 | // - Fixed incorrect index used to retrieve street backing parameters 13 | // in street_readParams. 14 | //----------------------------------------------------------------------------- 15 | #define _CRT_SECURE_NO_DEPRECATE 16 | 17 | #include 18 | #include "headers.h" 19 | 20 | //----------------------------------------------------------------------------- 21 | // External functions (declared in street.h) 22 | //----------------------------------------------------------------------------- 23 | // street_create called by createObjects in project.c 24 | // street_delete called by deleteObjects in project.c 25 | // street_readParams called by parseLine in input.c 26 | 27 | //============================================================================= 28 | 29 | int street_create(int nStreets) 30 | // 31 | // Input: nStreets = number of Street objects to create 32 | // Output: none 33 | // Purpose: creats a collection of Street objects. 34 | // 35 | { 36 | Street = NULL; 37 | Nobjects[STREET] = 0; 38 | Street = (TStreet *)calloc(nStreets, sizeof(TStreet)); 39 | if (Street == NULL) return ERR_MEMORY; 40 | Nobjects[STREET] = nStreets; 41 | return 0; 42 | } 43 | 44 | //============================================================================= 45 | 46 | void street_delete() 47 | // 48 | // Input: none 49 | // Output: none 50 | // Purpose: deletes the collection of Street objects. 51 | // 52 | { 53 | FREE(Street) 54 | } 55 | 56 | //============================================================================= 57 | 58 | int street_readParams(char* tok[], int ntoks) 59 | // 60 | // Format is: 61 | // ID Tcrown Hcurb Sx nRoad (Hdep Wg Sides Tback Sback nBack) 62 | // where 63 | // ID = name assigned to street cross section 64 | // Tcrown = distance from curb to street crown (ft or m) 65 | // Hcurb = curb height (ft or m) 66 | // Sx = roadway cross slope (%) 67 | // nRoad = roadway Manning's n 68 | // Hdep = depressed gutter height (ft or m) 69 | // Wg = depressed gutter width (ft or m) 70 | // Sides = 1 or 2 sided 71 | // Tback = width of street backing (ft or m) 72 | // Sback = slope of street backing (ft or m) 73 | // nBack = Manning's n of street backing 74 | { 75 | int i, k, sides; 76 | double x[11]; 77 | TStreet *street; 78 | 79 | // --- check for minimum number of tokens 80 | if (ntoks < 5) return error_setInpError(ERR_ITEMS, ""); 81 | 82 | // --- check that street exists in project 83 | i = project_findObject(STREET, tok[0]); 84 | if (i < 0) return error_setInpError(ERR_NAME, tok[0]); 85 | Street[i].ID = project_findID(STREET, tok[0]); 86 | 87 | // --- parse required data 88 | for (k = 0; k <= 9; k++) x[k] = 0.0; 89 | for (k = 1; k <= 4; k++) 90 | if (!getDouble(tok[k], &x[k]) || x[k] <= 0.0) 91 | return error_setInpError(ERR_NUMBER, tok[k]); 92 | 93 | // --- read gutter depression 94 | if (ntoks > 5) 95 | if (!getDouble(tok[5], &x[5]) || x[5] < 0.0) 96 | return error_setInpError(ERR_NUMBER, tok[5]); 97 | 98 | // --- read gutter width 99 | if (ntoks > 6) 100 | if (!getDouble(tok[6], &x[6]) || x[6] < 0.0) 101 | return error_setInpError(ERR_NUMBER, tok[6]); 102 | 103 | // --- read if 1- or 2-sided 104 | sides = 2; 105 | if (ntoks > 7) 106 | if (!getInt(tok[7], &sides) || sides < 1 || sides > 2) 107 | return error_setInpError(ERR_NUMBER, tok[7]); 108 | 109 | // --- read street backing parameters 110 | if (ntoks > 8) 111 | { 112 | if (!getDouble(tok[8], &x[8]) || x[8] < 0.0) 113 | return error_setInpError(ERR_NUMBER, tok[8]); 114 | if (x[8] > 0.0) 115 | { 116 | if (ntoks < 11) return error_setInpError(ERR_ITEMS, ""); 117 | for (k = 9; k <= 10; k++) 118 | if (!getDouble(tok[k], &x[k]) || x[k] <= 0.0) 119 | return error_setInpError(ERR_NUMBER, tok[k]); 120 | } 121 | } 122 | 123 | // --- assign input values to street object 124 | street = &Street[i]; 125 | street->width = x[1] / UCF(LENGTH); 126 | street->curbHeight = x[2] / UCF(LENGTH); 127 | street->slope = x[3] / 100.0; 128 | street->roughness = x[4]; 129 | street->gutterDepression = x[5] / UCF(LENGTH); 130 | street->gutterWidth = x[6] / UCF(LENGTH); 131 | street->sides = sides; 132 | street->backWidth = x[8] / UCF(LENGTH); 133 | street->backSlope = x[9] / 100.0; 134 | street->backRoughness = x[10]; 135 | transect_createStreetTransect(street); 136 | return 0; 137 | } 138 | 139 | //============================================================================= 140 | 141 | double street_getExtentFilled(int link) 142 | // 143 | // Input: link = a link index 144 | // Output: degree to which street is filled 145 | // Purpose: finds the degree to which a street link is filled based on the 146 | // depth (for DW routing) or cross section area at the higher end. 147 | // 148 | { 149 | int k, t; 150 | double filled; 151 | 152 | t = Link[link].xsect.transect; 153 | if (t < 0) return 0.0; 154 | if (RouteModel == DW) 155 | { 156 | filled = MAX(Node[Link[link].node1].newDepth, 157 | Node[Link[link].node2].newDepth); 158 | } 159 | else 160 | { 161 | k = Link[link].subIndex; 162 | filled = MAX(Conduit[k].a1, Conduit[k].a2); 163 | } 164 | return filled; 165 | } 166 | -------------------------------------------------------------------------------- /src/solver/error.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // error.h 3 | // 4 | // Project: EPA SWMM5 5 | // Version: 5.2 6 | // Date: 11/01/21 (Build 5.2.0) 7 | // Author: L. Rossman 8 | // 9 | // Error codes 10 | // 11 | //----------------------------------------------------------------------------- 12 | 13 | #ifndef ERROR_H 14 | #define ERROR_H 15 | 16 | enum ErrorType { 17 | 18 | // ... Runtime Errors 19 | ERR_NONE = 0, 20 | ERR_MEMORY = 101, 21 | ERR_KINWAVE = 103, 22 | ERR_ODE_SOLVER = 105, 23 | ERR_TIMESTEP = 107, 24 | 25 | // ... Subcatchment/Aquifer Errors 26 | ERR_SUBCATCH_OUTLET = 108, 27 | ERR_AQUIFER_PARAMS = 109, 28 | ERR_GROUND_ELEV = 110, 29 | 30 | // ... Conduit/Pump Errors 31 | ERR_LENGTH = 111, 32 | ERR_ELEV_DROP = 112, 33 | ERR_ROUGHNESS = 113, 34 | ERR_BARRELS = 114, 35 | ERR_SLOPE = 115, 36 | ERR_NO_XSECT = 117, 37 | ERR_XSECT = 119, 38 | ERR_NO_CURVE = 121, 39 | ERR_PUMP_LIMITS = 122, 40 | 41 | // ... Topology Errors 42 | ERR_LOOP = 131, 43 | ERR_MULTI_OUTLET = 133, 44 | ERR_DUMMY_LINK = 134, 45 | 46 | // ... Node Errors 47 | ERR_DIVIDER = 135, 48 | ERR_DIVIDER_LINK = 136, 49 | ERR_WEIR_DIVIDER = 137, 50 | ERR_NODE_DEPTH = 138, 51 | ERR_REGULATOR = 139, 52 | ERR_STORAGE_VOLUME = 140, 53 | ERR_OUTFALL = 141, 54 | ERR_REGULATOR_SHAPE = 143, 55 | ERR_NO_OUTLETS = 145, 56 | 57 | // ... RDII Errors 58 | ERR_UNITHYD_TIMES = 151, 59 | ERR_UNITHYD_RATIOS = 153, 60 | ERR_RDII_AREA = 155, 61 | 62 | // ... Rain Gage Errors 63 | ERR_RAIN_FILE_CONFLICT = 156, 64 | ERR_RAIN_GAGE_FORMAT = 157, 65 | ERR_RAIN_GAGE_TSERIES = 158, 66 | ERR_RAIN_GAGE_INTERVAL = 159, 67 | 68 | // ... Treatment Function Error 69 | ERR_CYCLIC_TREATMENT = 161, 70 | 71 | // ... Curve/Time Series Errors 72 | ERR_CURVE_SEQUENCE = 171, 73 | ERR_TIMESERIES_SEQUENCE = 173, 74 | 75 | // ... Snowmelt Errors 76 | ERR_SNOWMELT_PARAMS = 181, 77 | ERR_SNOWPACK_PARAMS = 182, 78 | 79 | // ... LID Errors 80 | ERR_LID_TYPE = 183, 81 | ERR_LID_LAYER = 184, 82 | ERR_LID_PARAMS = 185, 83 | ERR_LID_AREAS = 187, 84 | ERR_LID_CAPTURE_AREA = 188, 85 | 86 | // ... Simulation Date/Time Errors 87 | ERR_START_DATE = 191, 88 | ERR_REPORT_DATE = 193, 89 | ERR_REPORT_STEP = 195, 90 | 91 | // ... Input Parser Errors 92 | ERR_INPUT = 200, 93 | ERR_LINE_LENGTH = 201, 94 | ERR_ITEMS = 203, 95 | ERR_KEYWORD = 205, 96 | ERR_DUP_NAME = 207, 97 | ERR_NAME = 209, 98 | ERR_NUMBER = 211, 99 | ERR_DATETIME = 213, 100 | ERR_RULE = 217, 101 | ERR_TRANSECT_UNKNOWN = 219, 102 | ERR_TRANSECT_SEQUENCE = 221, 103 | ERR_TRANSECT_TOO_FEW = 223, 104 | ERR_TRANSECT_TOO_MANY = 225, 105 | ERR_TRANSECT_MANNING = 227, 106 | ERR_TRANSECT_OVERBANK = 229, 107 | ERR_TRANSECT_NO_DEPTH = 231, 108 | ERR_MATH_EXPR = 233, 109 | ERR_INFIL_PARAMS = 235, 110 | 111 | // ... File Name/Opening Errors 112 | ERR_FILE_NAME = 301, 113 | ERR_INP_FILE = 303, 114 | ERR_RPT_FILE = 305, 115 | ERR_OUT_FILE = 307, 116 | ERR_OUT_SIZE = 308, 117 | ERR_OUT_WRITE = 309, 118 | ERR_OUT_READ = 311, 119 | 120 | // ... Rain File Errors 121 | ERR_RAIN_FILE_SCRATCH = 313, 122 | ERR_RAIN_FILE_OPEN = 315, 123 | ERR_RAIN_FILE_DATA = 317, 124 | ERR_RAIN_FILE_SEQUENCE = 318, 125 | ERR_RAIN_FILE_FORMAT = 319, 126 | ERR_RAIN_IFACE_FORMAT = 320, 127 | ERR_RAIN_FILE_GAGE = 321, 128 | 129 | // ... Runoff File Errors 130 | ERR_RUNOFF_FILE_OPEN = 323, 131 | ERR_RUNOFF_FILE_FORMAT = 325, 132 | ERR_RUNOFF_FILE_END = 327, 133 | ERR_RUNOFF_FILE_READ = 329, 134 | 135 | // ... Hotstart File Errors 136 | ERR_HOTSTART_FILE_OPEN = 331, 137 | ERR_HOTSTART_FILE_FORMAT = 333, 138 | ERR_HOTSTART_FILE_READ = 335, 139 | 140 | // ... Climate File Errors 141 | ERR_NO_CLIMATE_FILE = 336, 142 | ERR_CLIMATE_FILE_OPEN = 337, 143 | ERR_CLIMATE_FILE_READ = 338, 144 | ERR_CLIMATE_END_OF_FILE = 339, 145 | 146 | // ... RDII File Errors 147 | ERR_RDII_FILE_SCRATCH = 341, 148 | ERR_RDII_FILE_OPEN = 343, 149 | ERR_RDII_FILE_FORMAT = 345, 150 | 151 | // ... Routing File Errors 152 | ERR_ROUTING_FILE_OPEN = 351, 153 | ERR_ROUTING_FILE_FORMAT = 353, 154 | ERR_ROUTING_FILE_NOMATCH = 355, 155 | ERR_ROUTING_FILE_NAMES = 357, 156 | 157 | // ... Time Series File Errors 158 | ERR_TABLE_FILE_OPEN = 361, 159 | ERR_TABLE_FILE_READ = 363, 160 | 161 | // ... Runtime Errors 162 | ERR_SYSTEM = 500, 163 | 164 | // ... API Errors 165 | ERR_API_NOT_OPEN = 501, 166 | ERR_API_NOT_STARTED = 502, 167 | ERR_API_NOT_ENDED = 503, 168 | ERR_API_OBJECT_TYPE = 504, 169 | ERR_API_OBJECT_INDEX = 505, 170 | ERR_API_OBJECT_NAME = 506, 171 | ERR_API_PROPERTY_TYPE = 507, 172 | ERR_API_PROPERTY_VALUE = 508, 173 | ERR_API_TIME_PERIOD = 509, 174 | 175 | // ... Additional Errors 176 | MAXERRMSG = 1000 177 | }; 178 | 179 | char* error_getMsg(int i, char* msg); 180 | int error_setInpError(int errcode, char* s); 181 | 182 | #endif //ERROR_H 183 | -------------------------------------------------------------------------------- /src/solver/error.txt: -------------------------------------------------------------------------------- 1 | // SWMM 5.2 Error Messages 2 | 3 | ERR(101,"\n ERROR 101: memory allocation error.") 4 | ERR(103,"\n ERROR 103: cannot solve KW equations for Link %s.") 5 | ERR(105,"\n ERROR 105: cannot open ODE solver.") 6 | ERR(107,"\n ERROR 107: cannot compute a valid time step.") 7 | 8 | ERR(108,"\n ERROR 108: ambiguous outlet ID name for Subcatchment %s.") 9 | ERR(109,"\n ERROR 109: invalid parameter values for Aquifer %s.") 10 | ERR(110,"\n ERROR 110: ground elevation is below water table for Subcatchment %s.") 11 | 12 | ERR(111,"\n ERROR 111: invalid length for Conduit %s.") 13 | ERR(112,"\n ERROR 112: elevation drop exceeds length for Conduit %s.") 14 | ERR(113,"\n ERROR 113: invalid roughness for Conduit %s.") 15 | ERR(114,"\n ERROR 114: invalid number of barrels for Conduit %s.") 16 | ERR(115,"\n ERROR 115: adverse slope for Conduit %s.") 17 | ERR(117,"\n ERROR 117: no cross section defined for Link %s.") 18 | ERR(119,"\n ERROR 119: invalid cross section for Link %s.") 19 | ERR(121,"\n ERROR 121: missing or invalid pump curve assigned to Pump %s.") 20 | ERR(122,"\n ERROR 122: startup depth not higher than shutoff depth for Pump %s.") 21 | 22 | ERR(131,"\n ERROR 131: the following links form cyclic loops in the drainage system:") 23 | ERR(133,"\n ERROR 133: Node %s has more than one outlet link.") 24 | ERR(134,"\n ERROR 134: Node %s has illegal DUMMY link connections.") 25 | 26 | ERR(135,"\n ERROR 135: Divider %s does not have two outlet links.") 27 | ERR(136,"\n ERROR 136: Divider %s has invalid diversion link.") 28 | ERR(137,"\n ERROR 137: Weir Divider %s has invalid parameters.") 29 | ERR(138,"\n ERROR 138: Node %s has initial depth greater than maximum depth.") 30 | ERR(139,"\n ERROR 139: Regulator %s is the outlet of a non-storage node.") 31 | ERR(140,"\n ERROR 140: Storage node %s has negative volume at full depth.") 32 | ERR(141,"\n ERROR 141: Outfall %s has more than 1 inlet link or an outlet link.") 33 | ERR(143,"\n ERROR 143: Regulator %s has invalid cross-section shape.") 34 | ERR(145,"\n ERROR 145: Drainage system has no acceptable outlet nodes.") 35 | 36 | ERR(151,"\n ERROR 151: a Unit Hydrograph in set %s has invalid time base.") 37 | ERR(153,"\n ERROR 153: a Unit Hydrograph in set %s has invalid response ratios.") 38 | ERR(155,"\n ERROR 155: invalid sewer area for RDII at node %s.") 39 | 40 | ERR(156,"\n ERROR 156: ambiguous station ID for Rain Gage %s.") 41 | ERR(157,"\n ERROR 157: inconsistent rainfall format for Rain Gage %s.") 42 | ERR(158,"\n ERROR 158: time series for Rain Gage %s is also used by another object.") 43 | ERR(159,"\n ERROR 159: recording interval greater than time series interval for Rain Gage %s.") 44 | 45 | ERR(161,"\n ERROR 161: cyclic dependency in treatment functions at node %s.") 46 | 47 | ERR(171,"\n ERROR 171: Curve %s has invalid or out of sequence data.") 48 | ERR(173,"\n ERROR 173: Time Series %s has its data out of sequence.") 49 | 50 | ERR(181,"\n ERROR 181: invalid Snow Melt Climatology parameters.") 51 | ERR(182,"\n ERROR 182: invalid parameters for Snow Pack %s.") 52 | 53 | ERR(183,"\n ERROR 183: no type specified for LID %s.") 54 | ERR(184,"\n ERROR 184: missing layer for LID %s.") 55 | ERR(185,"\n ERROR 185: invalid parameter value for LID %s.") 56 | ERR(187,"\n ERROR 187: LID area exceeds total area for Subcatchment %s.") 57 | ERR(188,"\n ERROR 188: LID capture area exceeds total impervious area for Subcatchment %s.") 58 | 59 | ERR(191,"\n ERROR 191: simulation start date comes after ending date.") 60 | ERR(193,"\n ERROR 193: report start date comes after ending date.") 61 | ERR(195,"\n ERROR 195: reporting time step or duration is less than routing time step.") 62 | 63 | ERR(200,"\n ERROR 200: one or more errors in input file.") 64 | ERR(201,"\n ERROR 201: too many characters in input line ") 65 | ERR(203,"\n ERROR 203: too few items ") 66 | ERR(205,"\n ERROR 205: invalid keyword %s ") 67 | ERR(207,"\n ERROR 207: duplicate ID name %s ") 68 | ERR(209,"\n ERROR 209: undefined object %s ") 69 | ERR(211,"\n ERROR 211: invalid number %s ") 70 | ERR(213,"\n ERROR 213: invalid date/time %s ") 71 | ERR(217,"\n ERROR 217: control rule clause invalid or out of sequence ") 72 | ERR(219,"\n ERROR 219: data provided for unidentified transect ") 73 | ERR(221,"\n ERROR 221: transect station out of sequence ") 74 | ERR(223,"\n ERROR 223: Transect %s has too few stations.") 75 | ERR(225,"\n ERROR 225: Transect %s has too many stations.") 76 | ERR(227,"\n ERROR 227: Transect %s has no Manning's N.") 77 | ERR(229,"\n ERROR 229: Transect %s has invalid overbank locations.") 78 | ERR(231,"\n ERROR 231: Transect %s has no depth.") 79 | ERR(233,"\n ERROR 233: invalid math expression ") 80 | ERR(235,"\n ERROR 235: invalid infiltration parameters ") 81 | 82 | ERR(301,"\n ERROR 301: files share same names.") 83 | ERR(303,"\n ERROR 303: cannot open input file.") 84 | ERR(305,"\n ERROR 305: cannot open report file.") 85 | ERR(307,"\n ERROR 307: cannot open binary results file.") 86 | ERR(308,"\n ERROR 308: amount of output produced will exceed maximum file size.") 87 | 88 | ERR(309,"\n ERROR 309: error writing to binary results file.") 89 | ERR(311,"\n ERROR 311: error reading from binary results file.") 90 | 91 | ERR(313,"\n ERROR 313: cannot open scratch rainfall interface file.") 92 | ERR(315,"\n ERROR 315: cannot open rainfall interface file %s.") 93 | ERR(317,"\n ERROR 317: cannot open rainfall data file %s.") 94 | ERR(318,"\n ERROR 318: the following line is out of sequence in rainfall data file %s.") 95 | ERR(319,"\n ERROR 319: unknown format for rainfall data file %s.") 96 | ERR(320,"\n ERROR 320: invalid format for rainfall interface file.") 97 | ERR(321,"\n ERROR 321: no data in rainfall interface file for gage %s.") 98 | 99 | ERR(323,"\n ERROR 323: cannot open runoff interface file %s.") 100 | ERR(325,"\n ERROR 325: incompatible data found in runoff interface file.") 101 | ERR(327,"\n ERROR 327: attempting to read beyond end of runoff interface file.") 102 | ERR(329,"\n ERROR 329: error in reading from runoff interface file.") 103 | 104 | ERR(331,"\n ERROR 331: cannot open hot start interface file %s.") 105 | ERR(333,"\n ERROR 333: incompatible data found in hot start interface file.") 106 | ERR(335,"\n ERROR 335: error in reading from hot start interface file.") 107 | 108 | ERR(336,"\n ERROR 336: no climate file specified for evaporation and/or wind speed.") 109 | ERR(337,"\n ERROR 337: cannot open climate file %s.") 110 | ERR(338,"\n ERROR 338: error in reading from climate file %s.") 111 | ERR(339,"\n ERROR 339: attempt to read beyond end of climate file %s.") 112 | 113 | ERR(341,"\n ERROR 341: cannot open scratch RDII interface file.") 114 | ERR(343,"\n ERROR 343: cannot open RDII interface file %s.") 115 | ERR(345,"\n ERROR 345: invalid format for RDII interface file.") 116 | 117 | ERR(351,"\n ERROR 351: cannot open routing interface file %s.") 118 | ERR(353,"\n ERROR 353: invalid format for routing interface file %s.") 119 | ERR(355,"\n ERROR 355: mis-matched names in routing interface file %s.") 120 | ERR(357,"\n ERROR 357: inflows and outflows interface files have same name.") 121 | 122 | ERR(361,"\n ERROR 361: could not open external file used for Time Series %s.") 123 | ERR(363,"\n ERROR 363: invalid data in external file used for Time Series %s.") 124 | 125 | // API Error Keys 126 | ERR(500,"\n ERROR 500: System exception thrown.") 127 | ERR(501,"\n API Error 501: project not opened.") 128 | ERR(502,"\n API Error 502: simulation not started.") 129 | ERR(503,"\n API Error 503: simulation not ended.") 130 | ERR(504,"\n API Error 504: invalid object type.") 131 | ERR(505,"\n API Error 505: invalid object index.") 132 | ERR(506,"\n API Error 506: invalid object name.") 133 | ERR(507,"\n API Error 507: invalid property type.") 134 | ERR(508,"\n API Error 508: invalid property value.") 135 | ERR(509,"\n API Error 509: invalid time period.") 136 | -------------------------------------------------------------------------------- /src/solver/roadway.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // roadway.c 3 | // 4 | // Project: EPA SWMM5 5 | // Version: 5.2 6 | // Date: 11/01/21 (Build 5.2.0) 7 | // Author: L. Rossman 8 | // 9 | // Roadway Weir module for SWMM5 10 | // 11 | // Computes flow overtopping a roadway (with a ROADWAY_WEIR object) using 12 | // the FWHA HDS-5 methodology. 13 | // 14 | // Typically used in conjuction with a culvert crossing where the culvert 15 | // conduit is placed at zero offset at the upstream node and the Roadway 16 | // weir has the same upstream node but with an offset equal to the height 17 | // of the roadway. 18 | // 19 | // Update History 20 | // ============== 21 | // Build 5.1.012: 22 | // - Entries in discharge coeff. table for gravel roadways corrected. 23 | //----------------------------------------------------------------------------- 24 | #define _CRT_SECURE_NO_DEPRECATE 25 | 26 | #include 27 | #include "headers.h" 28 | 29 | enum RoadSurface { 30 | PAVED = 1, 31 | GRAVEL = 2 32 | }; 33 | 34 | //----------------------------------------------------------------------------- 35 | // Constants 36 | //----------------------------------------------------------------------------- 37 | 38 | // The discharge coefficients and submergence factors listed below were 39 | // derived from Figure 10 in "Bridge Waterways Analysis Model: Research 40 | // Report", U.S. Dept. of Transportation Federal Highway Administration 41 | // Report No. FHWA/RD-86/108, McLean, VA, July 1986. 42 | 43 | // Discharge Coefficients for (head / road width) <= 0.15 44 | static const int N_Cr_Low_Paved = 4; 45 | static const double Cr_Low_Paved[4][2] = { 46 | {0.0, 2.85}, {0.2, 2.95}, {0.7, 3.03}, {4.0, 3.05}}; 47 | 48 | static const int N_Cr_Low_Gravel = 8; 49 | static const double Cr_Low_Gravel[8][2] = { 50 | {0.0, 2.5}, {0.5, 2.7}, {1.0, 2.8}, {1.5, 2.9}, {2.0, 2.98}, 51 | {2.5, 3.02}, {3.0, 3.03}, {4.0, 3.05} }; 52 | 53 | // Discharge Coefficients for (head / road width) > 0.15 54 | static const int N_Cr_High_Paved = 2; 55 | static const double Cr_High_Paved[2][2] = {{0.15,3.05}, {0.25,3.10}}; 56 | 57 | static const int N_Cr_High_Gravel = 2; 58 | static const double Cr_High_Gravel[2][2] = {{0.15,2.95}, {0.30,3.10}}; 59 | 60 | // Submergence Factors 61 | static const int N_Kt_Paved = 9; 62 | static const double Kt_Paved[9][2] = { 63 | {0.8, 1.0}, {0.85, 0.98}, {0.90, 0.92}, {0.93, 0.85}, {0.95, 0.80}, 64 | {0.97, 0.70}, {0.98, 0.60}, {0.99, 0.50}, {1.00, 0.40}}; 65 | 66 | static const int N_Kt_Gravel = 12; 67 | static const double Kt_Gravel[12][2] = { 68 | {0.75, 1.00}, {0.80, 0.985}, {0.83, 0.97}, {0.86, 0.93}, {0.89, 0.90}, 69 | {0.90, 0.87}, {0.92, 0.80}, {0.94, 0.70}, {0.96, 0.60}, {0.98, 0.50}, 70 | {0.99, 0.40}, {1.00, 0.24}}; 71 | 72 | //----------------------------------------------------------------------------- 73 | // External functions (declared in funcs.h) 74 | //----------------------------------------------------------------------------- 75 | // double roadway_getInflow (called by weir_getInflow in link.c) 76 | 77 | //----------------------------------------------------------------------------- 78 | // Local functions 79 | //----------------------------------------------------------------------------- 80 | static double getCd(double hWr, double ht, double roadWidth, int roadSurf); 81 | static double getY(double x, const double table[][2], const int n); 82 | 83 | //============================================================================= 84 | 85 | double roadway_getInflow(int j, // link index 86 | double dir, // flow direction (+1 or -1) 87 | double hRoad, // road elev. (ft) 88 | double h1, // upstream head (ft) 89 | double h2) // downstream head (ft) 90 | { 91 | int k; // weir array index 92 | int roadSurf; // type of road surface 93 | int useVariableCd; // true if HDS-5 coeff. curves used 94 | double length, // length of roadway segment transverse to flow (ft) 95 | roadWidth, // width of roadway which receives flow (ft) 96 | hWr, // water elevation on upstream side of roadway (ft) 97 | ht, // water elevation on downstream side of roadway (ft) 98 | cD, // discharge coefficient for cfs flow units 99 | q = 0.0, // flow across roadway (cfs) 100 | dqdh = 0.0; // derivative of flow w.r.t. head (ft2/sec) 101 | 102 | // --- get road width & surface type 103 | if ( Link[j].type != WEIR ) return 0.0; 104 | k = Link[j].subIndex; 105 | roadWidth = Weir[k].roadWidth; 106 | roadSurf = Weir[k].roadSurface; 107 | 108 | // --- user-supplied discharge coeff. 109 | cD = Weir[k].cDisch1; 110 | if ( UnitSystem == SI ) cD = cD / 0.552; 111 | 112 | // --- check if there's enough info to use a variable cD value 113 | useVariableCd = FALSE; 114 | if ( roadWidth > 0.0 && roadSurf >= 1 ) useVariableCd = TRUE; 115 | 116 | // --- upstream and downstream heads 117 | hWr = h1 - hRoad; 118 | ht = h2 - hRoad; 119 | if ( hWr > FUDGE ) 120 | { 121 | // --- get discharge coeff. as function of heads 122 | if ( useVariableCd ) cD = getCd(hWr, ht, roadWidth, roadSurf); 123 | 124 | // --- use user-supplied weir length 125 | length = Link[j].xsect.wMax; 126 | 127 | // --- weir eqn. for discharge across roadway 128 | q = cD * length * pow(hWr, 1.5); 129 | dqdh = 1.5 * q / hWr; 130 | } 131 | 132 | // --- assign output values 133 | Link[j].dqdh = dqdh; 134 | Link[j].newDepth = MAX(h1 - hRoad, 0.0); 135 | Link[j].flowClass = SUBCRITICAL; 136 | if ( hRoad > h2 ) 137 | { 138 | if ( dir == 1.0 ) Link[j].flowClass = DN_CRITICAL; 139 | else Link[j].flowClass = UP_CRITICAL; 140 | } 141 | return dir * q; 142 | } 143 | 144 | //============================================================================= 145 | 146 | double getCd(double hWr, double ht, double roadWidth, int roadSurf) 147 | { 148 | double kT = 1.0; // submergence factor 149 | double hL, // ratio of water elevation to road width 150 | htH, // ratio of downstream to upstream water depth 151 | cR; // roadway discharge coeff. 152 | 153 | if ( hWr <= 0.0 ) return 0.0; 154 | hL = hWr / roadWidth; 155 | if ( hL <= 0.15 ) 156 | { 157 | if ( roadSurf == PAVED ) cR = getY(hWr, Cr_Low_Paved, N_Cr_Low_Paved); 158 | else cR = getY(hWr, Cr_Low_Gravel, N_Cr_Low_Gravel); 159 | } 160 | else 161 | { 162 | if ( roadSurf == PAVED ) cR = getY(hL, Cr_High_Paved, N_Cr_High_Paved); 163 | else cR = getY(hL, Cr_High_Gravel, N_Cr_High_Gravel); 164 | } 165 | if ( ht > 0.0 ) 166 | { 167 | htH = ht / hWr; 168 | if ( roadSurf == PAVED ) kT = getY(htH, Kt_Paved, N_Kt_Paved); 169 | else kT = getY(htH, Kt_Gravel, N_Kt_Gravel); 170 | } 171 | return cR * kT; 172 | } 173 | 174 | //============================================================================= 175 | 176 | double getY(double x, const double table[][2], const int n) 177 | { 178 | int i; 179 | double x1, y1,dx, dy; 180 | if ( x <= table[0][0] ) return table[0][1]; 181 | if ( x >= table[n-1][0] ) return table[n-1][1]; 182 | for (i = 1; i < n; i++) 183 | { 184 | if ( x <= table[i][0] ) 185 | { 186 | x1 = table[i-1][0]; 187 | dx = table[i][0] - x1; 188 | y1 = table[i-1][1]; 189 | dy = table[i][1] - y1; 190 | return y1 + (x - x1) * dy / dx; 191 | } 192 | } 193 | return table[n-1][1]; 194 | } 195 | -------------------------------------------------------------------------------- /src/solver/Roadmap.txt: -------------------------------------------------------------------------------- 1 | A Roadmap to the SWMM 5 Engine Source Code 2 | ========================================== 3 | 4 | The SWMM 5 computational engine consists of 55 C-code files plus 22 5 | header files. The engine should be compiled into a Dynamic Link Library 6 | (DLL) under Windows or to a shared object library under Linux or MacOS. 7 | A main.c file is also provided to build an executable that uses the engine 8 | library to run a complete SWMM simulation from the command line. 9 | 10 | The following header files contain definitions that are used throughout the 11 | code and should be consulted if the meaning of a variable, a data structure, 12 | or a constant is unclear: 13 | 14 | enums.h defines various enumerated (symbolic) constants. 15 | 16 | objects.h defines the major classes of data objects used by SWMM 5. 17 | 18 | consts.h defines useful numerical constants. 19 | 20 | text.h defines various text strings used throughout the code. 21 | 22 | macros.h defines several macros used throughout the code. 23 | 24 | globals.h declares global variables that are referenced in many 25 | SWMM 5 code modules. 26 | 27 | funcs.h contains prototypes of functions that can be called from any 28 | module of SWMM 5 that #includes funcs.h. 29 | 30 | -------------------------------------------------------------------------- 31 | 32 | The following modules form the main core of the SWMM 5 engine: 33 | 34 | swmm5.c contains a small API with functions that provide supervisory 35 | control over the program. 36 | 37 | project.c contains functions that create and destroy all project data, 38 | establish default values, and look up objects by ID name. 39 | 40 | input.c reads a project's data from an input file. 41 | 42 | runoff.c computes runoff quantity and quality from the project's 43 | subcatchments. 44 | 45 | routing.c routes runoff and external inflows through the project's 46 | drainage system network of nodes and links. 47 | 48 | massbal.c performs mass balance calculations for runoff and routing. 49 | 50 | stats.c collects summary statistics on flow rates, water depths, 51 | solution iterations, and variable time steps for a simulation. 52 | 53 | statsrpt.c writes summary simulation results to a status report. 54 | 55 | output.c writes/reads runoff and routing results to/from a binary 56 | output file. 57 | 58 | report.c prepares a status report of simulation results and, for the 59 | command line version of SWMM 5, reports complete results for 60 | selected subcatchments, nodes, and links. 61 | 62 | inputrpt.c writes a summary of a project's input data to the status report. 63 | 64 | ------------------------------------------------------------------------------- 65 | 66 | The following collection of modules are used to perform runoff calculations: 67 | 68 | rain.c places data from external rainfall files into a single rainfall 69 | interface file. 70 | 71 | gage.c provides rainfall data, either from an interface file or from an 72 | internal time series, for runoff calculations. 73 | 74 | climate.c provides temperature, evaporation, and wind speed data to the 75 | simulation. 76 | 77 | snow.c computes snow fall accumulation, snow removal operations, and 78 | snow melt for a project's subcatchments. 79 | 80 | infil.c performs infiltration calculations on a project's subcatchments. 81 | 82 | gwater.c computes groundwater fluxes and updates groundwater depths over 83 | the project's study area. 84 | 85 | subcatch.c computes rainfall runoff, pollutant buildup and washoff, and 86 | street sweeping over individual subcatchments. 87 | 88 | landuse.c evaluates pollutant buildup and washoff functions for a project's 89 | various types of land uses. 90 | 91 | lid.c evaluates the hydrologic performance of Low Impact Development 92 | practices utilized within subcatchment areas. 93 | 94 | lidproc.c computes the hydrologic performance of individual LID units. 95 | 96 | ------------------------------------------------------------------------------- 97 | 98 | These modules are used for flow and water quality routing: 99 | 100 | flowrout.c implements top-level control of flow routing through a project's 101 | drainage network. 102 | 103 | inflow.c provides direct time series inflows and recurring dry weather 104 | inflows to the drainage system's nodes at each step of the 105 | simulation. 106 | 107 | rdii.c computes rainfall dependent infiltration/inflow at selected nodes 108 | of the drainage network. 109 | 110 | inlet.c computes flow captured by street inlet drains that is diverted to 111 | sewer nodes using methods from the FHWA HEC-22 manual. 112 | 113 | kinwave.c performs kinematic wave flow routing calculations at each time 114 | step of the simulation. 115 | 116 | dynwave.c performs dynamic wave flow routing calculations at each time 117 | step of the simulation 118 | 119 | dwflow.c solves the dynamic wave flow continuity and momentum equations in 120 | a single conduit over a single time step. 121 | 122 | controls.c implements rule-based control actions on pumps and regulators 123 | as the simulation unfolds. 124 | 125 | qualrout.c performs routing of water quality constituents through the 126 | study area's drainage system. 127 | 128 | treatmnt.c computes pollutant removal at specific nodes of the drainage 129 | system where user-defined treatment functions have been 130 | assigned. 131 | 132 | node.c contains functions used to compute the properties and behavior 133 | of the drainage system's nodes which include junctions, flow 134 | dividers, storage units, and outfalls. 135 | 136 | link.c contains functions used to compute the properties and behavior 137 | of the drainage system's links which include conduits, pumps, 138 | orifices, weirs, and outlets. 139 | 140 | forcmain.c computes friction losses in force mains that use either the 141 | Hazen-Williams or Darcy-Weisbach equations in place of the 142 | Manning equation for pressurized flow. 143 | 144 | culvert.c computes flow reduction in culvert-type conduits due to 145 | inlet control using equations from the FHWA HEC-5 circular. 146 | 147 | ------------------------------------------------------------------------------- 148 | 149 | The following modules provide various support functions for SWMM 5: 150 | 151 | datetime.c functions for manipulating dates and times. 152 | 153 | error.c error reporting functions. 154 | 155 | findroot.c equation root finding functions. 156 | 157 | hash.c functions that implement hash tables for fast object retrieval. 158 | 159 | hotstart.c saves or reads the state of the drainage system to or from a 160 | hot start file. 161 | 162 | iface.c functions for reading from and writing to routing interface 163 | files. 164 | 165 | keywords.c defines lists of keywords that appear as part of a SWMM 5 166 | input file. 167 | 168 | mathexpr.c functions that parse and evaluate user-supplied mathematical 169 | expressions. 170 | 171 | mempool.c functions that provide a memory pool used to store object 172 | ID names. 173 | 174 | odesolve.c implementation of a fifth-order Runge-Kutta ordinary 175 | differential equation solver. 176 | 177 | shape.c functions that compute the geometric cross-section properties 178 | of closed conduits with user-defined shapes. 179 | 180 | street.c reads the geometric properties of a street cross section. 181 | 182 | table.c functions used for accessing lookup tables that contain 183 | SWMM 5's curve data and time series data. 184 | 185 | toposort.c functions used to topologically sort the links of a drainage 186 | network and detect any closed cyclic loops. 187 | 188 | transect.c functions that create geometric tables for irregular shaped 189 | cross section transects. 190 | 191 | xsect.c functions that compute geometric properties of conduit cross 192 | sections. 193 | -------------------------------------------------------------------------------- /src/solver/odesolve.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // odesolve.c 3 | // 4 | // Fifth-order Runge-Kutta integration with adaptive step size control 5 | // based on code from Numerical Recipes in C (Cambridge University 6 | // Press, 1992). 7 | // 8 | // Date: 11/15/06 9 | // Author: L. Rossman 10 | //----------------------------------------------------------------------------- 11 | 12 | #include 13 | #include 14 | #include "odesolve.h" 15 | 16 | #define MAXSTP 10000 17 | #define TINY 1.0e-30 18 | #define SAFETY 0.9 19 | #define PGROW -0.2 20 | #define PSHRNK -0.25 21 | #define ERRCON 1.89e-4 // = (5/SAFETY)^(1/PGROW) 22 | 23 | 24 | //----------------------------------------------------------------------------- 25 | // Local declarations 26 | //----------------------------------------------------------------------------- 27 | int nmax; // max. number of equations 28 | double* y; // dependent variable 29 | double* yscal; // scaling factors 30 | double* yerr; // integration errors 31 | double* ytemp; // temporary values of y 32 | double* dydx; // derivatives of y 33 | double* ak; // derivatives at intermediate points 34 | 35 | 36 | // function that integrates over an error-controlled stepsize 37 | int rkqs(double* x, int n, double htry, double eps, double* hdid, 38 | double* hnext, void (*derivs)(double, double*, double*)); 39 | 40 | // function that performs the Runge-Kutta integration step 41 | void rkck(double x, int n, double h, void (*derivs)(double, double*, double*)); 42 | 43 | 44 | //----------------------------------------------------------------------------- 45 | // open the ODE solver to solve system of n equations 46 | // (return 1 if successful, 0 if not) 47 | //----------------------------------------------------------------------------- 48 | int odesolve_open(int n) 49 | { 50 | int n5 = n*5; 51 | nmax = 0; 52 | y = (double *) calloc(n, sizeof(double)); 53 | yscal = (double *) calloc(n, sizeof(double)); 54 | dydx = (double *) calloc(n, sizeof(double)); 55 | yerr = (double *) calloc(n, sizeof(double)); 56 | ytemp = (double *) calloc(n, sizeof(double)); 57 | ak = (double *) calloc(n5, sizeof(double)); 58 | if ( !y || !yscal || !dydx || !yerr || !ytemp || !ak ) return 0; 59 | nmax = n; 60 | return 1; 61 | } 62 | 63 | 64 | //----------------------------------------------------------------------------- 65 | // close the ODE solver 66 | //----------------------------------------------------------------------------- 67 | void odesolve_close() 68 | { 69 | if ( y ) free(y); 70 | y = NULL; 71 | if ( yscal ) free(yscal); 72 | yscal = NULL; 73 | if ( dydx ) free(dydx); 74 | dydx = NULL; 75 | if ( yerr ) free(yerr); 76 | yerr = NULL; 77 | if ( ytemp ) free(ytemp); 78 | ytemp = NULL; 79 | if ( ak ) free(ak); 80 | ak = NULL; 81 | nmax = 0; 82 | } 83 | 84 | 85 | int odesolve_integrate(double ystart[], int n, double x1, double x2, 86 | double eps, double h1, void (*derivs)(double, double*, double*)) 87 | //--------------------------------------------------------------- 88 | // Driver function for Runge-Kutta integration with adaptive 89 | // stepsize control. Integrates starting n values in ystart[] 90 | // from x1 to x2 with accuracy eps. h1 is the initial stepsize 91 | // guess and derivs is a user-supplied function that computes 92 | // derivatives dy/dx of y. On completion, ystart[] contains the 93 | // new values of y at the end of the integration interval. 94 | //--------------------------------------------------------------- 95 | { 96 | int i, errcode, nstp; 97 | double hdid, hnext; 98 | double x = x1; 99 | double h = h1; 100 | if (nmax < n) return 1; 101 | for (i=0; i 0.0) h = x2 - x; 108 | errcode = rkqs(&x,n,h,eps,&hdid,&hnext,derivs); 109 | if (errcode) break; 110 | if ((x-x2)*(x2-x1) >= 0.0) 111 | { 112 | for (i=0; i errmax) errmax = err; 148 | } 149 | errmax /= eps; 150 | 151 | // --- error too large; reduce stepsize & repeat 152 | if (errmax > 1.0) 153 | { 154 | htemp = SAFETY*h*pow(errmax,PSHRNK); 155 | if (h >= 0) 156 | { 157 | if (htemp > 0.1*h) h = htemp; 158 | else h = 0.1*h; 159 | } 160 | else 161 | { 162 | if (htemp < 0.1*h) h = htemp; 163 | else h = 0.1*h; 164 | } 165 | xnew = xold + h; 166 | if (xnew == xold) return 2; 167 | continue; 168 | } 169 | 170 | // --- step succeeded; compute size of next step 171 | else 172 | { 173 | if (errmax > ERRCON) *hnext = SAFETY*h*pow(errmax,PGROW); 174 | else *hnext = 5.0*h; 175 | *x += (*hdid=h); 176 | for (i=0; i 25 | #include 26 | #include "headers.h" 27 | #include "infil.h" 28 | #include "exfil.h" 29 | 30 | static int createStorageExfil(int k, double x[]); 31 | 32 | //============================================================================= 33 | 34 | int exfil_readStorageParams(int k, char* tok[], int ntoks, int n) 35 | // 36 | // Input: k = storage unit index 37 | // tok[] = array of string tokens 38 | // ntoks = number of tokens 39 | // n = last token processed 40 | // Output: returns an error code 41 | // Purpose: reads a storage unit's exfiltration parameters from a 42 | // tokenized line of input. 43 | // 44 | { 45 | int i; 46 | double x[3]; //suction head, Ksat, IMDmax 47 | 48 | // --- read Ksat if it's the only remaining token 49 | if ( ntoks == n+1 ) 50 | { 51 | if ( ! getDouble(tok[n], &x[1]) ) 52 | return error_setInpError(ERR_NUMBER, tok[n]); 53 | x[0] = 0.0; 54 | x[2] = 0.0; 55 | } 56 | 57 | // --- otherwise read Green-Ampt infiltration parameters from input tokens 58 | else if ( ntoks < n + 3 ) return error_setInpError(ERR_ITEMS, ""); 59 | else for (i = 0; i < 3; i++) 60 | { 61 | if ( ! getDouble(tok[n+i], &x[i]) ) 62 | return error_setInpError(ERR_NUMBER, tok[n+i]); 63 | } 64 | 65 | // --- no exfiltration if Ksat is 0 66 | if ( x[1] == 0.0 ) return 0; 67 | 68 | // --- create an exfiltration object 69 | return createStorageExfil(k, x); 70 | } 71 | 72 | //============================================================================= 73 | 74 | void exfil_initState(int k) 75 | // 76 | // Input: k = storage unit index 77 | // Output: none 78 | // Purpose: initializes the state of a storage unit's exfiltration object. 79 | // 80 | { 81 | int i; 82 | double a, alast, d; 83 | TTable* aCurve; 84 | TExfil* exfil = Storage[k].exfil; 85 | 86 | // --- initialize exfiltration object 87 | if ( exfil != NULL ) 88 | { 89 | // --- initialize the Green-Ampt infil. parameters 90 | grnampt_initState(exfil->btmExfil); 91 | grnampt_initState(exfil->bankExfil); 92 | 93 | switch (Storage[k].shape) 94 | { 95 | // --- shape given by a Storage Curve 96 | case TABULAR: 97 | i = Storage[k].aCurve; 98 | exfil->btmArea = 0.0; 99 | exfil->bankMinDepth = 0.0; 100 | exfil->bankMaxDepth = 0.0; 101 | exfil->bankMaxArea = 0.0; 102 | if ( i >= 0 ) 103 | { 104 | // --- get bottom area 105 | aCurve = &Curve[i]; 106 | Storage[k].exfil->btmArea = table_lookupEx(aCurve, 0.0); 107 | 108 | // --- find min/max bank depths and max. bank area 109 | table_getFirstEntry(aCurve, &d, &a); 110 | alast = a; 111 | while ( table_getNextEntry(aCurve, &d, &a) ) 112 | { 113 | if ( a < alast ) break; 114 | else if ( a > alast ) 115 | { 116 | exfil->bankMaxArea = a; 117 | exfil->bankMaxDepth = d; 118 | } 119 | else if ( exfil->bankMaxArea == 0.0 ) 120 | exfil->bankMinDepth = d; 121 | else break; 122 | alast = a; 123 | } 124 | 125 | // --- convert from user units to internal units 126 | exfil->btmArea /= UCF(LENGTH) * UCF(LENGTH); 127 | exfil->bankMaxArea /= UCF(LENGTH) * UCF(LENGTH); 128 | exfil->bankMinDepth /= UCF(LENGTH); 129 | exfil->bankMaxDepth /= UCF(LENGTH); 130 | } 131 | break; 132 | 133 | // --- functional storage shape curve 134 | case FUNCTIONAL: 135 | exfil->btmArea = Storage[k].a0; 136 | if ( Storage[k].a2 == 0.0 ) 137 | exfil->btmArea +=Storage[k].a1; 138 | exfil->bankMinDepth = 0.0; 139 | exfil->bankMaxDepth = BIG; 140 | exfil->bankMaxArea = BIG; 141 | break; 142 | 143 | // --- cylindrical, conical & prismatic shapes 144 | case CYLINDRICAL: 145 | case CONICAL: 146 | case PYRAMIDAL: 147 | exfil->btmArea = Storage[k].a0; 148 | exfil->bankMinDepth = 0.0; 149 | exfil->bankMaxDepth = BIG; 150 | exfil->bankMaxArea = BIG; 151 | break; 152 | } 153 | } 154 | } 155 | 156 | //============================================================================= 157 | 158 | double exfil_getLoss(TExfil* exfil, double tStep, double depth, double area) 159 | // 160 | // Input: exfil = ptr. to a storage exfiltration object 161 | // tStep = time step (sec) 162 | // depth = water depth (ft) 163 | // area = surface area (ft2) 164 | // Output: returns exfiltration rate out of storage unit (cfs) 165 | // Purpose: computes rate of water exfiltrated from a storage node into 166 | // the soil beneath it. 167 | // 168 | { 169 | double exfilRate = 0.0; 170 | 171 | // --- find infiltration through bottom of unit 172 | if ( exfil->btmExfil->IMDmax == 0.0 ) 173 | { 174 | exfilRate = exfil->btmExfil->Ks * Adjust.hydconFactor; 175 | } 176 | else exfilRate = grnampt_getInfil(exfil->btmExfil, tStep, 0.0, depth, 177 | MOD_GREEN_AMPT); 178 | exfilRate *= exfil->btmArea; 179 | 180 | // --- find infiltration through sloped banks 181 | if ( depth > exfil->bankMinDepth ) 182 | { 183 | // --- get area of banks 184 | area = MIN(area, exfil->bankMaxArea) - exfil->btmArea; 185 | if ( area > 0.0 ) 186 | { 187 | // --- if infil. rate not a function of depth 188 | if ( exfil->btmExfil->IMDmax == 0.0 ) 189 | { 190 | exfilRate += area * exfil->btmExfil->Ks * Adjust.hydconFactor; 191 | } 192 | 193 | // --- infil. rate depends on depth above bank 194 | else 195 | { 196 | // --- case where water depth is above the point where the 197 | // storage curve no longer has increasing area with depth 198 | if ( depth > exfil->bankMaxDepth ) 199 | { 200 | depth = depth - exfil->bankMaxDepth + 201 | (exfil->bankMaxDepth - exfil->bankMinDepth) / 2.0; 202 | } 203 | 204 | // --- case where water depth is below top of bank 205 | else depth = (depth - exfil->bankMinDepth) / 2.0; 206 | 207 | // --- use Green-Ampt function for bank infiltration 208 | exfilRate += area * grnampt_getInfil(exfil->bankExfil, 209 | tStep, 0.0, depth, MOD_GREEN_AMPT); 210 | } 211 | } 212 | } 213 | return exfilRate; 214 | } 215 | 216 | //============================================================================= 217 | 218 | int createStorageExfil(int k, double x[]) 219 | // 220 | // Input: k = index of storage unit node 221 | // x = array of Green-Ampt infiltration parameters 222 | // Output: returns an error code. 223 | // Purpose: creates an exfiltration object for a storage node. 224 | // 225 | // Note: the exfiltration object is freed in project.c. 226 | // 227 | { 228 | TExfil* exfil; 229 | 230 | // --- create an exfiltration object for the storage node 231 | exfil = Storage[k].exfil; 232 | if ( exfil == NULL ) 233 | { 234 | exfil = (TExfil *) malloc(sizeof(TExfil)); 235 | if ( exfil == NULL ) return error_setInpError(ERR_MEMORY, ""); 236 | Storage[k].exfil = exfil; 237 | 238 | // --- create Green-Ampt infiltration objects for the bottom & banks 239 | exfil->btmExfil = NULL; 240 | exfil->bankExfil = NULL; 241 | exfil->btmExfil = (TGrnAmpt *) malloc(sizeof(TGrnAmpt)); 242 | if ( exfil->btmExfil == NULL ) return error_setInpError(ERR_MEMORY, ""); 243 | exfil->bankExfil = (TGrnAmpt *) malloc(sizeof(TGrnAmpt)); 244 | if ( exfil->bankExfil == NULL ) return error_setInpError(ERR_MEMORY, ""); 245 | } 246 | 247 | // --- initialize the Green-Ampt parameters 248 | if ( !grnampt_setParams(exfil->btmExfil, x) ) 249 | return error_setInpError(ERR_NUMBER, ""); 250 | grnampt_setParams(exfil->bankExfil, x); 251 | return 0; 252 | } 253 | -------------------------------------------------------------------------------- /src/solver/globals.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // globals.h 3 | // 4 | // Project: EPA SWMM5 5 | // Version: 5.2 6 | // Date: 11/01/21 (Build 5.2.0) 7 | // Author: L. Rossman 8 | // 9 | // Global Variables 10 | // 11 | // Update History 12 | // ============== 13 | // Build 5.1.004: 14 | // - Ignore RDII option added. 15 | // Build 5.1.007: 16 | // - Monthly climate variable adjustments added. 17 | // Build 5.1.008: 18 | // - Number of parallel threads for dynamic wave routing added. 19 | // - Minimum dynamic wave routing variable time step added. 20 | // Build 5.1.011: 21 | // - Changed WarningCode to Warnings (# warnings issued) 22 | // - Added error message text as a variable. 23 | // - Added elapsed simulation time (in decimal days) variable. 24 | // - Added variables associated with detailed routing events. 25 | // Build 5.1.012: 26 | // - InSteadyState variable made local to routing_execute in routing.c. 27 | // Build 5.1.013: 28 | // - CrownCutoff and RuleStep added as analysis option variables. 29 | // Build 5.1.015: 30 | // - Fixes bug in summary statistics when Report Start date > Start Date. 31 | // Build 5.2.0: 32 | // - Support for relative file names added. 33 | //----------------------------------------------------------------------------- 34 | 35 | #ifndef GLOBALS_H 36 | #define GLOBALS_H 37 | 38 | 39 | EXTERN TFile 40 | Finp, // Input file 41 | Fout, // Output file 42 | Frpt, // Report file 43 | Fclimate, // Climate file 44 | Frain, // Rainfall file 45 | Frunoff, // Runoff file 46 | Frdii, // RDII inflow file 47 | Fhotstart1, // Hot start input file 48 | Fhotstart2, // Hot start output file 49 | Finflows, // Inflows routing file 50 | Foutflows; // Outflows routing file 51 | 52 | EXTERN long 53 | Nperiods, // Number of reporting periods 54 | TotalStepCount, // Total routing steps used 55 | ReportStepCount, // Reporting routing steps used 56 | NonConvergeCount; // Number of non-converging steps 57 | 58 | EXTERN char 59 | Msg[MAXMSG+1], // Text of output message 60 | ErrorMsg[MAXMSG+1], // Text of error message 61 | Title[MAXTITLE][MAXMSG+1],// Project title 62 | TempDir[MAXFNAME+1], // Temporary file directory 63 | InpDir[MAXFNAME+1]; // Input file directory 64 | 65 | EXTERN TRptFlags 66 | RptFlags; // Reporting options 67 | 68 | EXTERN int 69 | Nobjects[MAX_OBJ_TYPES], // Number of each object type 70 | Nnodes[MAX_NODE_TYPES], // Number of each node sub-type 71 | Nlinks[MAX_LINK_TYPES], // Number of each link sub-type 72 | UnitSystem, // Unit system 73 | FlowUnits, // Flow units 74 | InfilModel, // Infiltration method 75 | RouteModel, // Flow routing method 76 | ForceMainEqn, // Flow equation for force mains 77 | LinkOffsets, // Link offset convention 78 | SurchargeMethod, // EXTRAN or SLOT method 79 | AllowPonding, // Allow water to pond at nodes 80 | InertDamping, // Degree of inertial damping 81 | NormalFlowLtd, // Normal flow limited 82 | SlopeWeighting, // Use slope weighting 83 | Compatibility, // SWMM 5/3/4 compatibility 84 | SkipSteadyState, // Skip over steady state periods 85 | IgnoreRainfall, // Ignore rainfall/runoff 86 | IgnoreRDII, // Ignore RDII 87 | IgnoreSnowmelt, // Ignore snowmelt 88 | IgnoreGwater, // Ignore groundwater 89 | IgnoreRouting, // Ignore flow routing 90 | IgnoreQuality, // Ignore water quality 91 | ErrorCode, // Error code number 92 | Warnings, // Number of warning messages 93 | WetStep, // Runoff wet time step (sec) 94 | DryStep, // Runoff dry time step (sec) 95 | ReportStep, // Reporting time step (sec) 96 | RuleStep, // Rule evaluation time step (sec) 97 | SweepStart, // Day of year when sweeping starts 98 | SweepEnd, // Day of year when sweeping ends 99 | MaxTrials, // Max. trials for DW routing 100 | NumThreads, // Number of parallel threads used 101 | NumEvents; // Number of detailed events 102 | 103 | EXTERN double 104 | RouteStep, // Routing time step (sec) 105 | MinRouteStep, // Minimum variable time step (sec) 106 | LengtheningStep, // Time step for lengthening (sec) 107 | StartDryDays, // Antecedent dry days 108 | CourantFactor, // Courant time step factor 109 | MinSurfArea, // Minimum nodal surface area 110 | MinSlope, // Minimum conduit slope 111 | RunoffError, // Runoff continuity error 112 | GwaterError, // Groundwater continuity error 113 | FlowError, // Flow routing error 114 | QualError, // Quality routing error 115 | HeadTol, // DW routing head tolerance (ft) 116 | SysFlowTol, // Tolerance for steady system flow 117 | LatFlowTol, // Tolerance for steady nodal inflow 118 | CrownCutoff; // Fractional pipe crown cutoff 119 | 120 | EXTERN DateTime 121 | StartDate, // Starting date 122 | StartTime, // Starting time 123 | StartDateTime, // Starting Date+Time 124 | EndDate, // Ending date 125 | EndTime, // Ending time 126 | EndDateTime, // Ending Date+Time 127 | ReportStartDate, // Report start date 128 | ReportStartTime, // Report start time 129 | ReportStart; // Report start Date+Time 130 | 131 | EXTERN double 132 | ReportTime, // Current reporting time (msec) 133 | OldRunoffTime, // Previous runoff time (msec) 134 | NewRunoffTime, // Current runoff time (msec) 135 | OldRoutingTime, // Previous routing time (msec) 136 | NewRoutingTime, // Current routing time (msec) 137 | TotalDuration, // Simulation duration (msec) 138 | ElapsedTime; // Current elapsed time (days) 139 | 140 | EXTERN TTemp Temp; // Temperature data 141 | EXTERN TEvap Evap; // Evaporation data 142 | EXTERN TWind Wind; // Wind speed data 143 | EXTERN TSnow Snow; // Snow melt data 144 | EXTERN TAdjust Adjust; // Climate adjustments 145 | 146 | EXTERN TSnowmelt* Snowmelt; // Array of snow melt objects 147 | EXTERN TGage* Gage; // Array of rain gages 148 | EXTERN TSubcatch* Subcatch; // Array of subcatchments 149 | EXTERN TAquifer* Aquifer; // Array of groundwater aquifers 150 | EXTERN TUnitHyd* UnitHyd; // Array of unit hydrographs 151 | EXTERN TNode* Node; // Array of nodes 152 | EXTERN TOutfall* Outfall; // Array of outfall nodes 153 | EXTERN TDivider* Divider; // Array of divider nodes 154 | EXTERN TStorage* Storage; // Array of storage nodes 155 | EXTERN TLink* Link; // Array of links 156 | EXTERN TConduit* Conduit; // Array of conduit links 157 | EXTERN TPump* Pump; // Array of pump links 158 | EXTERN TOrifice* Orifice; // Array of orifice links 159 | EXTERN TWeir* Weir; // Array of weir links 160 | EXTERN TOutlet* Outlet; // Array of outlet device links 161 | EXTERN TPollut* Pollut; // Array of pollutants 162 | EXTERN TLanduse* Landuse; // Array of landuses 163 | EXTERN TPattern* Pattern; // Array of time patterns 164 | EXTERN TTable* Curve; // Array of curve tables 165 | EXTERN TTable* Tseries; // Array of time series tables 166 | EXTERN TTransect* Transect; // Array of transect data 167 | EXTERN TStreet* Street; // Array of defined Street cross-sections 168 | EXTERN TShape* Shape; // Array of custom conduit shapes 169 | EXTERN TEvent* Event; // Array of routing events 170 | 171 | 172 | #endif //GLOBALS_H 173 | -------------------------------------------------------------------------------- /src/solver/kinwave.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // kinwave.c 3 | // 4 | // Project: EPA SWMM5 5 | // Version: 5.2 6 | // Date: 06/12/23 (Build 5.2.4) 7 | // Author: L. Rossman 8 | // M. Tryby (EPA) 9 | // 10 | // Kinematic wave flow routing functions. 11 | // 12 | // Update History 13 | // ============== 14 | // Build 5.1.008: 15 | // - Conduit inflow passed to function that computes conduit losses. 16 | // Build 5.1.014: 17 | // - Arguments to function link_getLossRate changed. 18 | // Build 5.2.4: 19 | // - Arguments to function link_getLossRate changed again. 20 | //----------------------------------------------------------------------------- 21 | #define _CRT_SECURE_NO_DEPRECATE 22 | 23 | #include 24 | #include "headers.h" 25 | #include "findroot.h" 26 | 27 | //----------------------------------------------------------------------------- 28 | // Constants 29 | //----------------------------------------------------------------------------- 30 | static const double WX = 0.6; // distance weighting 31 | static const double WT = 0.6; // time weighting 32 | static const double EPSIL = 0.001; // convergence criterion 33 | 34 | //----------------------------------------------------------------------------- 35 | // Shared variables 36 | //----------------------------------------------------------------------------- 37 | static double Beta1; 38 | static double C1; 39 | static double C2; 40 | static double Afull; 41 | static double Qfull; 42 | static TXsect* pXsect; 43 | 44 | //----------------------------------------------------------------------------- 45 | // External functions (declared in funcs.h) 46 | //----------------------------------------------------------------------------- 47 | // kinwave_execute (called by flowrout_execute) 48 | 49 | //----------------------------------------------------------------------------- 50 | // Local functions 51 | //----------------------------------------------------------------------------- 52 | static int solveContinuity(double qin, double ain, double* aout); 53 | static void evalContinuity(double a, double* f, double* df, void* p); 54 | 55 | //============================================================================= 56 | 57 | int kinwave_execute(int j, double* qinflow, double* qoutflow, double tStep) 58 | // 59 | // Input: j = link index 60 | // qinflow = inflow at current time (cfs) 61 | // tStep = time step (sec) 62 | // Output: qoutflow = outflow at current time (cfs), 63 | // returns number of iterations used 64 | // Purpose: finds outflow over time step tStep given flow entering a 65 | // conduit using Kinematic Wave flow routing. 66 | // 67 | // 68 | // ^ q3 69 | // t | 70 | // | qin, ain |-------------------| qout, aout 71 | // | | Flow ---> | 72 | // |----> x q1, a1 |-------------------| q2, a2 73 | // 74 | // 75 | { 76 | int k; 77 | int result = 1; 78 | double dxdt, dq; 79 | double ain, aout; 80 | double qin, qout; 81 | double a1, a2, q1, q2, q3; 82 | 83 | // --- no routing for non-conduit link 84 | (*qoutflow) = (*qinflow); 85 | if ( Link[j].type != CONDUIT ) return result; 86 | 87 | // --- no routing for dummy xsection 88 | if ( Link[j].xsect.type == DUMMY ) return result; 89 | 90 | // --- assign module-level variables 91 | pXsect = &Link[j].xsect; 92 | Qfull = Link[j].qFull; 93 | Afull = Link[j].xsect.aFull; 94 | k = Link[j].subIndex; 95 | Beta1 = Conduit[k].beta / Qfull; 96 | 97 | // --- normalize previous flows 98 | q1 = Conduit[k].q1 / Qfull; 99 | q2 = Conduit[k].q2 / Qfull; 100 | 101 | // --- normalize inflow 102 | qin = (*qinflow) / Conduit[k].barrels / Qfull; 103 | 104 | // --- compute evaporation and infiltration loss rate 105 | q3 = link_getLossRate(j, KW, qin*Qfull, tStep) / Qfull; 106 | 107 | // --- normalize previous areas 108 | a1 = Conduit[k].a1 / Afull; 109 | a2 = Conduit[k].a2 / Afull; 110 | 111 | // --- use full area when inlet flow >= full flow 112 | if ( qin >= 1.0 ) ain = 1.0; 113 | 114 | // --- get normalized inlet area corresponding to inlet flow 115 | else ain = xsect_getAofS(pXsect, qin/Beta1) / Afull; 116 | 117 | // --- check for no flow 118 | if ( qin <= TINY && q2 <= TINY ) 119 | { 120 | qout = 0.0; 121 | aout = 0.0; 122 | } 123 | 124 | // --- otherwise solve finite difference form of continuity eqn. 125 | else 126 | { 127 | // --- compute constant factors 128 | dxdt = link_getLength(j) / tStep * Afull / Qfull; 129 | dq = q2 - q1; 130 | C1 = dxdt * WT / WX; 131 | C2 = (1.0 - WT) * (ain - a1); 132 | C2 = C2 - WT * a2; 133 | C2 = C2 * dxdt / WX; 134 | C2 = C2 + (1.0 - WX) / WX * dq - qin; 135 | C2 = C2 + q3 / WX; 136 | 137 | // --- starting guess for aout is value from previous time step 138 | aout = a2; 139 | 140 | // --- solve continuity equation for aout 141 | result = solveContinuity(qin, ain, &aout); 142 | 143 | // --- report error if continuity eqn. not solved 144 | if ( result == -1 ) 145 | { 146 | report_writeErrorMsg(ERR_KINWAVE, Link[j].ID); 147 | return 1; 148 | } 149 | if ( result <= 0 ) result = 1; 150 | 151 | // --- compute normalized outlet flow from outlet area 152 | qout = Beta1 * xsect_getSofA(pXsect, aout*Afull); 153 | if ( qin > 1.0 ) qin = 1.0; 154 | } 155 | 156 | // --- save new flows and areas 157 | Conduit[k].q1 = qin * Qfull; 158 | Conduit[k].a1 = ain * Afull; 159 | Conduit[k].q2 = qout * Qfull; 160 | Conduit[k].a2 = aout * Afull; 161 | Conduit[k].fullState = 162 | link_getFullState(Conduit[k].a1, Conduit[k].a2, Afull); 163 | (*qinflow) = Conduit[k].q1 * Conduit[k].barrels; 164 | (*qoutflow) = Conduit[k].q2 * Conduit[k].barrels; 165 | return result; 166 | } 167 | 168 | //============================================================================= 169 | 170 | int solveContinuity(double qin, double ain, double* aout) 171 | // 172 | // Input: qin = upstream normalized flow 173 | // ain = upstream normalized area 174 | // aout = downstream normalized area 175 | // Output: new value for aout; returns an error code 176 | // Purpose: solves continuity equation f(a) = Beta1*S(a) + C1*a + C2 = 0 177 | // for 'a' using the Newton-Raphson root finder function. 178 | // Return code has the following meanings: 179 | // >= 0 number of function evaluations used 180 | // -1 Newton function failed 181 | // -2 flow always above max. flow 182 | // -3 flow always below zero 183 | // 184 | // Note: pXsect (pointer to conduit's cross-section), and constants Beta1, 185 | // C1, and C2 are module-level shared variables assigned values 186 | // in kinwave_execute(). 187 | // 188 | { 189 | int n; // # evaluations or error code 190 | double aLo, aHi, aTmp; // lower/upper bounds on a 191 | double fLo, fHi; // lower/upper bounds on f 192 | double tol = EPSIL; // absolute convergence tol. 193 | 194 | // --- first determine bounds on 'a' so that f(a) passes through 0. 195 | 196 | // --- set upper bound to area at full flow 197 | aHi = 1.0; 198 | fHi = 1.0 + C1 + C2; 199 | 200 | // --- try setting lower bound to area where section factor is maximum 201 | aLo = xsect_getAmax(pXsect) / Afull; 202 | if ( aLo < aHi ) 203 | { 204 | fLo = ( Beta1 * pXsect->sMax ) + (C1 * aLo) + C2; 205 | } 206 | else fLo = fHi; 207 | 208 | // --- if fLo and fHi have same sign then set lower bound to 0 209 | if ( fHi*fLo > 0.0 ) 210 | { 211 | aHi = aLo; 212 | fHi = fLo; 213 | aLo = 0.0; 214 | fLo = C2; 215 | } 216 | 217 | // --- proceed with search for root if fLo and fHi have different signs 218 | if ( fHi*fLo <= 0.0 ) 219 | { 220 | // --- start search at midpoint of lower/upper bounds 221 | // if initial value outside of these bounds 222 | if ( *aout < aLo || *aout > aHi ) *aout = 0.5*(aLo + aHi); 223 | 224 | // --- if fLo > fHi then switch aLo and aHi 225 | if ( fLo > fHi ) 226 | { 227 | aTmp = aLo; 228 | aLo = aHi; 229 | aHi = aTmp; 230 | } 231 | 232 | // --- call the Newton root finder method passing it the 233 | // evalContinuity function to evaluate the function 234 | // and its derivatives 235 | n = findroot_Newton(aLo, aHi, aout, tol, evalContinuity, NULL); 236 | 237 | // --- check if root finder succeeded 238 | if ( n <= 0 ) n = -1; 239 | } 240 | 241 | // --- if lower/upper bound functions both negative then use full flow 242 | else if ( fLo < 0.0 ) 243 | { 244 | if ( qin > 1.0 ) *aout = ain; 245 | else *aout = 1.0; 246 | n = -2; 247 | } 248 | 249 | // --- if lower/upper bound functions both positive then use no flow 250 | else if ( fLo > 0 ) 251 | { 252 | *aout = 0.0; 253 | n = -3; 254 | } 255 | else n = -1; 256 | return n; 257 | } 258 | 259 | //============================================================================= 260 | 261 | void evalContinuity(double a, double* f, double* df, void* p) 262 | // 263 | // Input: a = outlet normalized area 264 | // Output: f = value of continuity eqn. 265 | // df = derivative of continuity eqn. 266 | // Purpose: computes value of continuity equation (f) and its derivative (df) 267 | // w.r.t. normalized area for link with normalized outlet area 'a'. 268 | // 269 | { 270 | *f = (Beta1 * xsect_getSofA(pXsect, a*Afull)) + (C1 * a) + C2; 271 | *df = (Beta1 * Afull * xsect_getdSdA(pXsect, a*Afull)) + C1; 272 | } 273 | 274 | //============================================================================= 275 | -------------------------------------------------------------------------------- /src/solver/keywords.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // keywords.c 3 | // 4 | // Project: EPA SWMM5 5 | // Version: 5.2 6 | // Date: 06/01/22 (Build 5.2.1) 7 | // Author: L. Rossman 8 | // 9 | // Exportable keyword dictionary 10 | // 11 | // NOTE: the keywords in each list must appear in same order used 12 | // by its complementary enumerated variable in enums.h and 13 | // must be terminated by NULL. The actual text of each keyword 14 | // is defined in text.h. 15 | // 16 | // Update History 17 | // ============== 18 | // Build 5.1.007: 19 | // - Keywords for Ignore RDII option and groundwater flow equation 20 | // and climate adjustment input sections added. 21 | // Build 5.1.008: 22 | // - Keyword arrays placed in alphabetical order for better readability. 23 | // - Keywords added for Minimum Routing Step and Number of Threads options. 24 | // Build 5.1.010: 25 | // - New Modified Green Ampt keyword added to InfilModelWords. 26 | // - New Roadway weir keyword added to WeirTypeWords. 27 | // Build 5.1.011: 28 | // - New section keyword for [EVENTS] added. 29 | // Build 5.1.013: 30 | // - New option keywords w_SURCHARGE_METHOD, w_RULE_STEP, w_AVERAGES 31 | // and w_WEIR added. 32 | // Build 5.2.0: 33 | // - Support added for Streets and Inlets. 34 | // - Support added for variable speed pumps. 35 | // - Support added for analytical storage shapes. 36 | // - Support added for RptFlags.disabled option. 37 | // Build 5.2.1: 38 | // - Adds NONE to the list of NormalFlowWords. 39 | //----------------------------------------------------------------------------- 40 | #define _CRT_SECURE_NO_DEPRECATE 41 | 42 | #include // need this to define NULL 43 | #include "text.h" 44 | 45 | char* BuildupTypeWords[] = { w_NONE, w_POW, w_EXP, w_SAT, w_EXT, NULL}; 46 | char* CurveTypeWords[] = { w_STORAGE, w_DIVERSION, w_TIDAL, w_RATING, 47 | w_CONTROLS, w_SHAPE, w_WEIR, 48 | w_PUMP1, w_PUMP2, w_PUMP3, w_PUMP4, 49 | w_PUMP5, NULL}; 50 | char* DividerTypeWords[] = { w_CUTOFF, w_TABULAR, w_WEIR, w_OVERFLOW, NULL}; 51 | char* EvapTypeWords[] = { w_CONSTANT, w_MONTHLY, w_TIMESERIES, 52 | w_TEMPERATURE, w_FILE, w_RECOVERY, 53 | w_DRYONLY, NULL}; 54 | char* FileTypeWords[] = { w_RAINFALL, w_RUNOFF, w_HOTSTART, w_RDII, 55 | w_INFLOWS, w_OUTFLOWS, NULL}; 56 | char* FileModeWords[] = { w_NO, w_SCRATCH, w_USE, w_SAVE, NULL}; 57 | char* FlowUnitWords[] = { w_CFS, w_GPM, w_MGD, w_CMS, w_LPS, w_MLD, NULL}; 58 | char* ForceMainEqnWords[] = { w_H_W, w_D_W, NULL}; 59 | char* GageDataWords[] = { w_TIMESERIES, w_FILE, NULL}; 60 | char* InfilModelWords[] = { w_HORTON, w_MOD_HORTON, w_GREEN_AMPT, 61 | w_MOD_GREEN_AMPT, w_CURVE_NUMEBR, NULL}; 62 | char* InertDampingWords[] = { w_NONE, w_PARTIAL, w_FULL, NULL}; 63 | char* LinkOffsetWords[] = { w_DEPTH, w_ELEVATION, NULL}; 64 | char* LinkTypeWords[] = { w_CONDUIT, w_PUMP, w_ORIFICE, 65 | w_WEIR, w_OUTLET }; 66 | char* LoadUnitsWords[] = { w_LBS, w_KG, w_LOGN }; 67 | char* NodeTypeWords[] = { w_JUNCTION, w_OUTFALL, 68 | w_STORAGE, w_DIVIDER }; 69 | char* NoneAllWords[] = { w_NONE, w_ALL, NULL}; 70 | char* NormalFlowWords[] = { w_SLOPE, w_FROUDE, w_BOTH, w_NONE, NULL}; 71 | char* NormalizerWords[] = { w_PER_AREA, w_PER_CURB, NULL}; 72 | char* NoYesWords[] = { w_NO, w_YES, NULL}; 73 | char* OffOnWords[] = { w_OFF, w_ON, NULL}; 74 | char* OldRouteModelWords[] = { w_NONE, w_NF, w_KW, w_EKW, w_DW, NULL}; 75 | char* OptionWords[] = { w_FLOW_UNITS, w_INFIL_MODEL, 76 | w_ROUTE_MODEL, w_START_DATE, 77 | w_START_TIME, w_END_DATE, 78 | w_END_TIME, w_REPORT_START_DATE, 79 | w_REPORT_START_TIME, w_SWEEP_START, 80 | w_SWEEP_END, w_START_DRY_DAYS, 81 | w_WET_STEP, w_DRY_STEP, 82 | w_ROUTE_STEP, w_RULE_STEP, 83 | w_REPORT_STEP, 84 | w_ALLOW_PONDING, w_INERT_DAMPING, 85 | w_SLOPE_WEIGHTING, w_VARIABLE_STEP, 86 | w_NORMAL_FLOW_LTD, w_LENGTHENING_STEP, 87 | w_MIN_SURFAREA, w_COMPATIBILITY, 88 | w_SKIP_STEADY_STATE, w_TEMPDIR, 89 | w_IGNORE_RAINFALL, w_FORCE_MAIN_EQN, 90 | w_LINK_OFFSETS, w_MIN_SLOPE, 91 | w_IGNORE_SNOWMELT, w_IGNORE_GWATER, 92 | w_IGNORE_ROUTING, w_IGNORE_QUALITY, 93 | w_MAX_TRIALS, w_HEAD_TOL, 94 | w_SYS_FLOW_TOL, w_LAT_FLOW_TOL, 95 | w_IGNORE_RDII, w_MIN_ROUTE_STEP, 96 | w_NUM_THREADS, w_SURCHARGE_METHOD, 97 | NULL }; 98 | char* OrificeTypeWords[] = { w_SIDE, w_BOTTOM, NULL}; 99 | char* OutfallTypeWords[] = { w_FREE, w_NORMAL, w_FIXED, w_TIDAL, 100 | w_TIMESERIES, NULL}; 101 | char* PatternTypeWords[] = { w_MONTHLY, w_DAILY, w_HOURLY, w_WEEKEND, NULL}; 102 | char* PondingUnitsWords[] = { w_PONDED_FEET, w_PONDED_METERS }; 103 | char* ProcessVarWords[] = { w_HRT, w_DT, w_FLOW, w_DEPTH, w_AREA, NULL}; 104 | char* PumpTypeWords[] = { w_TYPE1, w_TYPE2, w_TYPE3, w_TYPE4, w_TYPE5, w_IDEAL }; 105 | char* QualUnitsWords[] = { w_MGperL, w_UGperL, w_COUNTperL, NULL}; 106 | char* RainTypeWords[] = { w_INTENSITY, w_VOLUME, w_CUMULATIVE, NULL}; 107 | char* RainUnitsWords[] = { w_INCHES, w_MMETER, NULL}; 108 | char* RelationWords[] = { w_TABULAR, w_FUNCTIONAL, 109 | w_CYLINDRICAL, w_CONICAL, w_PARABOLIC, 110 | w_PYRAMIDAL, NULL}; 111 | char* ReportWords[] = { w_DISABLED, w_INPUT, w_SUBCATCH, w_NODE, w_LINK, 112 | w_CONTINUITY, w_FLOWSTATS,w_CONTROLS, 113 | w_AVERAGES, w_NODESTATS, NULL}; 114 | char* RouteModelWords[] = { w_NONE, w_STEADY, w_KINWAVE, w_XKINWAVE, 115 | w_DYNWAVE, NULL}; 116 | char* RuleKeyWords[] = { w_RULE, w_IF, w_AND, w_OR, w_THEN, w_ELSE, 117 | w_PRIORITY, NULL}; 118 | char* SectWords[] = { ws_TITLE, ws_OPTION, 119 | ws_FILE, ws_RAINGAGE, 120 | ws_TEMP, ws_EVAP, 121 | ws_SUBCATCH, ws_SUBAREA, 122 | ws_INFIL, ws_AQUIFER, 123 | ws_GROUNDWATER, ws_SNOWMELT, 124 | ws_JUNCTION, ws_OUTFALL, 125 | ws_STORAGE, ws_DIVIDER, 126 | ws_CONDUIT, ws_PUMP, 127 | ws_ORIFICE, ws_WEIR, 128 | ws_OUTLET, ws_XSECTION, 129 | ws_TRANSECT, ws_LOSS, 130 | ws_CONTROL, ws_POLLUTANT, 131 | ws_LANDUSE, ws_BUILDUP, 132 | ws_WASHOFF, ws_COVERAGE, 133 | ws_INFLOW, ws_DWF, 134 | ws_PATTERN, ws_RDII, 135 | ws_UNITHYD, ws_LOADING, 136 | ws_TREATMENT, ws_CURVE, 137 | ws_TIMESERIES, ws_REPORT, 138 | ws_COORDINATE, ws_VERTICES, 139 | ws_POLYGON, ws_LABEL, 140 | ws_SYMBOL, ws_BACKDROP, 141 | ws_TAG, ws_PROFILE, 142 | ws_MAP, ws_LID_CONTROL, 143 | ws_LID_USAGE, ws_GWF, 144 | ws_ADJUST, ws_EVENT, 145 | ws_STREET, ws_INLET_USAGE, 146 | ws_INLET, NULL}; 147 | char* SnowmeltWords[] = { w_PLOWABLE, w_IMPERV, w_PERV, w_REMOVAL, NULL}; 148 | char* SurchargeWords[] = { w_EXTRAN, w_SLOT, NULL}; 149 | char* TempKeyWords[] = { w_TIMESERIES, w_FILE, w_WINDSPEED, w_SNOWMELT, 150 | w_ADC, NULL}; 151 | char* TransectKeyWords[] = { w_NC, w_X1, w_GR, NULL}; 152 | char* TreatTypeWords[] = { w_REMOVAL, w_CONCEN, NULL}; 153 | char* UHTypeWords[] = { w_SHORT, w_MEDIUM, w_LONG, NULL}; 154 | char* VolUnitsWords[] = { w_MGAL, w_MLTRS }; 155 | char* VolUnitsWords2[] = { w_GAL, w_LTR }; 156 | char* WashoffTypeWords[] = { w_NONE, w_EXP, w_RC, w_EMC, NULL}; 157 | char* WeirTypeWords[] = { w_TRANSVERSE, w_SIDEFLOW, w_VNOTCH, 158 | w_TRAPEZOIDAL, w_ROADWAY, NULL}; 159 | char* XsectTypeWords[] = { w_DUMMY, w_CIRCULAR, 160 | w_FILLED_CIRCULAR, w_RECT_CLOSED, 161 | w_RECT_OPEN, w_TRAPEZOIDAL, 162 | w_TRIANGULAR, w_PARABOLIC, 163 | w_POWERFUNC, w_RECT_TRIANG, 164 | w_RECT_ROUND, w_MOD_BASKET, 165 | w_HORIZELLIPSE, w_VERTELLIPSE, 166 | w_ARCH, w_EGGSHAPED, 167 | w_HORSESHOE, w_GOTHIC, 168 | w_CATENARY, w_SEMIELLIPTICAL, 169 | w_BASKETHANDLE, w_SEMICIRCULAR, 170 | w_IRREGULAR, w_CUSTOM, 171 | w_FORCE_MAIN, w_STREET, 172 | NULL}; 173 | -------------------------------------------------------------------------------- /src/solver/lid.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // lid.h 3 | // 4 | // Project: EPA SWMM5 5 | // Version: 5.2 6 | // Date: 11/01/21 (Build 5.2.0) 7 | // Author: L. Rossman 8 | // 9 | // Public interface for LID functions. 10 | // 11 | // Update History 12 | // ============== 13 | // Build 5.1.008: 14 | // - Support added for Roof Disconnection LID. 15 | // - Support added for separate routing of LID drain flows. 16 | // - Detailed LID reporting modified. 17 | // Build 5.1.011: 18 | // - Water depth replaces moisture content for LID's pavement layer. 19 | // - Arguments for lidproc_saveResults() modified. 20 | // Build 5.1.012: 21 | // - Redefined meaning of wasDry in TLidRptFile structure. 22 | // Build 5.1.013: 23 | // - New member fromPerv added to TLidUnit structure to allow LID 24 | // units to also treat pervious area runoff. 25 | // - New members hOpen and hClose addded to TDrainLayer to open/close 26 | // drain when certain heads are reached. 27 | // - New member qCurve added to TDrainLayer to allow underdrain flow to 28 | // be adjusted by a curve of multiplier v. head. 29 | // - New array drainRmvl added to TLidProc to allow for underdrain 30 | // pollutant removal values. 31 | // - New members added to TPavementLayer and TLidUnit to support 32 | // unclogging permeable pavement at fixed intervals. 33 | // Build 5.2.0: 34 | // - Covered property added to RAIN_BARREL parameters 35 | //----------------------------------------------------------------------------- 36 | 37 | #ifndef LID_H 38 | #define LID_H 39 | 40 | #include 41 | #include 42 | #include 43 | #include "infil.h" 44 | 45 | //----------------------------------------------------------------------------- 46 | // Enumerations 47 | //----------------------------------------------------------------------------- 48 | enum LidTypes { 49 | BIO_CELL, // bio-retention cell 50 | RAIN_GARDEN, // rain garden 51 | GREEN_ROOF, // green roof 52 | INFIL_TRENCH, // infiltration trench 53 | POROUS_PAVEMENT, // porous pavement 54 | RAIN_BARREL, // rain barrel 55 | VEG_SWALE, // vegetative swale 56 | ROOF_DISCON}; // roof disconnection 57 | 58 | enum TimePeriod { 59 | PREVIOUS, // previous time period 60 | CURRENT}; // current time period 61 | 62 | //----------------------------------------------------------------------------- 63 | // Data Structures 64 | //----------------------------------------------------------------------------- 65 | #define MAX_LAYERS 4 66 | 67 | // LID Surface Layer 68 | typedef struct 69 | { 70 | double thickness; // depression storage or berm ht. (ft) 71 | double voidFrac; // available fraction of storage volume 72 | double roughness; // surface Mannings n 73 | double surfSlope; // land surface slope (fraction) 74 | double sideSlope; // swale side slope (run/rise) 75 | double alpha; // slope/roughness term in Manning eqn. 76 | char canOverflow; // 1 if immediate outflow of excess water 77 | } TSurfaceLayer; 78 | 79 | // LID Pavement Layer 80 | typedef struct 81 | { 82 | double thickness; // layer thickness (ft) 83 | double voidFrac; // void volume / total volume 84 | double impervFrac; // impervious area fraction 85 | double kSat; // permeability (ft/sec) 86 | double clogFactor; // clogging factor 87 | double regenDays; // clogging regeneration interval (days) 88 | double regenDegree; // degree of clogging regeneration 89 | } TPavementLayer; 90 | 91 | // LID Soil Layer 92 | typedef struct 93 | { 94 | double thickness; // layer thickness (ft) 95 | double porosity; // void volume / total volume 96 | double fieldCap; // field capacity 97 | double wiltPoint; // wilting point 98 | double suction; // suction head at wetting front (ft) 99 | double kSat; // saturated hydraulic conductivity (ft/sec) 100 | double kSlope; // slope of log(K) v. moisture content curve 101 | } TSoilLayer; 102 | 103 | // LID Storage Layer 104 | typedef struct 105 | { 106 | double thickness; // layer thickness (ft) 107 | double voidFrac; // void volume / total volume 108 | double kSat; // saturated hydraulic conductivity (ft/sec) 109 | double clogFactor; // clogging factor 110 | int covered; // TRUE if rain barrel is covered 111 | } TStorageLayer; 112 | 113 | // Underdrain System (part of Storage Layer) 114 | typedef struct 115 | { 116 | double coeff; // underdrain flow coeff. (in/hr or mm/hr) 117 | double expon; // underdrain head exponent (for in or mm) 118 | double offset; // offset height of underdrain (ft) 119 | double delay; // rain barrel drain delay time (sec) 120 | double hOpen; // head when drain opens (ft) 121 | double hClose; // head when drain closes (ft) 122 | int qCurve; // curve controlling flow rate (optional) 123 | } TDrainLayer; 124 | 125 | // Drainage Mat Layer (for green roofs) 126 | typedef struct 127 | { 128 | double thickness; // layer thickness (ft) 129 | double voidFrac; // void volume / total volume 130 | double roughness; // Mannings n for green roof drainage mats 131 | double alpha; // slope/roughness term in Manning equation 132 | } TDrainMatLayer; 133 | 134 | // LID Process - generic LID design per unit of area 135 | typedef struct 136 | { 137 | char* ID; // identifying name 138 | int lidType; // type of LID 139 | TSurfaceLayer surface; // surface layer parameters 140 | TPavementLayer pavement; // pavement layer parameters 141 | TSoilLayer soil; // soil layer parameters 142 | TStorageLayer storage; // storage layer parameters 143 | TDrainLayer drain; // underdrain system parameters 144 | TDrainMatLayer drainMat; // drainage mat layer 145 | double* drainRmvl; // underdrain pollutant removals 146 | } TLidProc; 147 | 148 | // Water Balance Statistics 149 | typedef struct 150 | { 151 | double inflow; // total inflow (ft) 152 | double evap; // total evaporation (ft) 153 | double infil; // total infiltration (ft) 154 | double surfFlow; // total surface runoff (ft) 155 | double drainFlow; // total underdrain flow (ft) 156 | double initVol; // initial stored volume (ft) 157 | double finalVol; // final stored volume (ft) 158 | } TWaterBalance; 159 | 160 | // LID Report File 161 | typedef struct 162 | { 163 | FILE* file; // file pointer 164 | int wasDry; // number of successive dry periods 165 | char results[256]; // results for current time period 166 | } TLidRptFile; 167 | 168 | // LID Unit - specific LID process applied over a given area 169 | typedef struct 170 | { 171 | int lidIndex; // index of LID process 172 | int number; // number of replicate units 173 | double area; // area of single replicate unit (ft2) 174 | double fullWidth; // full top width of single unit (ft) 175 | double botWidth; // bottom width of single unit (ft) 176 | double initSat; // initial saturation of soil & storage layers 177 | double fromImperv; // fraction of impervious area runoff treated 178 | double fromPerv; // fraction of pervious area runoff treated 179 | int toPerv; // 1 if outflow sent to pervious area; 0 if not 180 | int drainSubcatch; // subcatchment receiving drain flow 181 | int drainNode; // node receiving drain flow 182 | TLidRptFile* rptFile; // pointer to detailed report file 183 | 184 | TGrnAmpt soilInfil; // infil. object for biocell soil layer 185 | double surfaceDepth; // depth of ponded water on surface layer (ft) 186 | double paveDepth; // depth of water in porous pavement layer 187 | double soilMoisture; // moisture content of biocell soil layer 188 | double storageDepth; // depth of water in storage layer (ft) 189 | 190 | // net inflow - outflow from previous time step for each LID layer (ft/s) 191 | double oldFluxRates[MAX_LAYERS]; 192 | 193 | double dryTime; // time since last rainfall (sec) 194 | double oldDrainFlow; // previous drain flow (cfs) 195 | double newDrainFlow; // current drain flow (cfs) 196 | double volTreated; // total volume treated (ft) 197 | double nextRegenDay; // next day when unit regenerated 198 | TWaterBalance waterBalance; // water balance quantites 199 | } TLidUnit; 200 | 201 | //----------------------------------------------------------------------------- 202 | // LID Methods 203 | //----------------------------------------------------------------------------- 204 | void lid_create(int lidCount, int subcatchCount); 205 | void lid_delete(void); 206 | 207 | int lid_readProcParams(char* tok[], int ntoks); 208 | int lid_readGroupParams(char* tok[], int ntoks); 209 | 210 | void lid_validate(void); 211 | void lid_initState(void); 212 | void lid_setOldGroupState(int subcatch); 213 | 214 | double lid_getPervArea(int subcatch); 215 | double lid_getFlowToPerv(int subcatch); 216 | double lid_getDrainFlow(int subcatch, int timePeriod); 217 | double lid_getStoredVolume(int subcatch); 218 | void lid_addDrainLoads(int subcatch, double c[], double tStep); 219 | void lid_addDrainRunon(int subcatch); 220 | void lid_addDrainInflow(int subcatch, double f); 221 | void lid_getRunoff(int subcatch, double tStep); 222 | void lid_writeSummary(void); 223 | void lid_writeWaterBalance(void); 224 | 225 | //----------------------------------------------------------------------------- 226 | 227 | void lidproc_initWaterBalance(TLidUnit *lidUnit, double initVol); 228 | 229 | double lidproc_getOutflow(TLidUnit* lidUnit, TLidProc* lidProc, 230 | double inflow, double evap, double infil, double maxInfil, 231 | double tStep, double* lidEvap, double* lidInfil, double* lidDrain); 232 | 233 | void lidproc_saveResults(TLidUnit* lidUnit, double ucfRainfall, 234 | double ucfRainDepth); 235 | 236 | #endif 237 | -------------------------------------------------------------------------------- /tests/outfile/test_output.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * test_output.cpp 3 | * 4 | * Created: 11/2/2017 5 | * Author: Michael E. Tryby 6 | * US EPA - ORD/NRMRL 7 | * 8 | * Unit testing for SWMM outputapi using Boost Test. 9 | */ 10 | 11 | // NOTE: Travis installs libboost test version 1.5.4 12 | //#define BOOST_TEST_DYN_LINK 13 | 14 | #define BOOST_TEST_MODULE "output" 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "swmm_output.h" 23 | 24 | // NOTE: Reference data for the unit tests is currently tied to SWMM 5.1.7 25 | #define DATA_PATH "./Example1.out" 26 | 27 | using namespace std; 28 | 29 | // Checks for minimum number of correct decimal digits 30 | boost::test_tools::predicate_result check_cdd_float(std::vector& test, 31 | std::vector& ref, long cdd_tol){ 32 | 33 | float tmp, min_cdd = 10.0; 34 | 35 | // TODO: What if the vectors aren't the same length? 36 | 37 | std::vector::iterator test_it; 38 | std::vector::iterator ref_it; 39 | 40 | for (test_it = test.begin(), ref_it = ref.begin(); 41 | (test_it < test.end()) && (ref_it < ref.end()); 42 | ++test_it, ++ref_it) 43 | { 44 | if (*test_it != *ref_it) { 45 | // Compute log absolute error 46 | tmp = abs(*test_it - *ref_it); 47 | if (tmp < 1.0e-7f) 48 | tmp = 1.0e-7f; 49 | 50 | else if (tmp > 2.0f) 51 | tmp = 1.0f; 52 | 53 | tmp = -log10(tmp); 54 | if (tmp < 0.0f) 55 | tmp = 0.0f; 56 | 57 | if (tmp < min_cdd) 58 | min_cdd = tmp; 59 | } 60 | } 61 | return floor(min_cdd) >= cdd_tol; 62 | } 63 | 64 | boost::test_tools::predicate_result check_string(std::string test, 65 | std::string ref) { 66 | 67 | if (ref.compare(test) == 0) 68 | return true; 69 | else 70 | return false; 71 | } 72 | 73 | BOOST_AUTO_TEST_SUITE(test_output_auto) 74 | 75 | BOOST_AUTO_TEST_CASE(InitTest) { 76 | SMO_Handle p_handle = NULL; 77 | 78 | int error = SMO_init(&p_handle); 79 | BOOST_REQUIRE(error == 0); 80 | BOOST_CHECK(p_handle != NULL); 81 | 82 | SMO_close(&p_handle); 83 | } 84 | 85 | BOOST_AUTO_TEST_CASE(CloseTest) { 86 | SMO_Handle p_handle = NULL; 87 | SMO_init(&p_handle); 88 | 89 | int error = SMO_close(&p_handle); 90 | BOOST_REQUIRE(error == 0); 91 | BOOST_CHECK(p_handle == NULL); 92 | } 93 | 94 | BOOST_AUTO_TEST_CASE(InitOpenCloseTest) { 95 | std::string path = std::string(DATA_PATH); 96 | SMO_Handle p_handle = NULL; 97 | SMO_init(&p_handle); 98 | 99 | int error = SMO_open(p_handle, path.c_str()); 100 | BOOST_REQUIRE(error == 0); 101 | 102 | SMO_close(&p_handle); 103 | } 104 | 105 | BOOST_AUTO_TEST_SUITE_END() 106 | 107 | struct Fixture { 108 | Fixture() { 109 | std::string path = std::string(DATA_PATH); 110 | 111 | error = SMO_init(&p_handle); 112 | SMO_clearError(p_handle); 113 | error = SMO_open(p_handle, path.c_str()); 114 | 115 | array = NULL; 116 | array_dim = 0; 117 | } 118 | ~Fixture() { 119 | SMO_free((void**)&array); 120 | error = SMO_close(&p_handle); 121 | } 122 | 123 | std::string path; 124 | int error; 125 | SMO_Handle p_handle; 126 | 127 | float* array; 128 | int array_dim; 129 | }; 130 | 131 | BOOST_AUTO_TEST_SUITE(test_output_fixture) 132 | 133 | BOOST_FIXTURE_TEST_CASE(test_getVersion, Fixture) { 134 | int version; 135 | 136 | error = SMO_getVersion(p_handle, &version); 137 | BOOST_REQUIRE(error == 0); 138 | 139 | BOOST_CHECK_EQUAL(51000, version); 140 | } 141 | 142 | BOOST_FIXTURE_TEST_CASE(test_getProjectSize, Fixture) { 143 | int* i_array = NULL; 144 | 145 | error = SMO_getProjectSize(p_handle, &i_array, &array_dim); 146 | BOOST_REQUIRE(error == 0); 147 | 148 | std::vector test; 149 | test.assign(i_array, i_array + array_dim); 150 | 151 | // subcatchs, nodes, links, pollutants 152 | const int ref_dim = 5; 153 | int ref_array[ref_dim] = {8, 14, 13, 1, 2}; 154 | 155 | std::vector ref; 156 | ref.assign(ref_array, ref_array + ref_dim); 157 | 158 | BOOST_CHECK_EQUAL_COLLECTIONS(ref.begin(), ref.end(), test.begin(), 159 | test.end()); 160 | 161 | SMO_free((void**)&i_array); 162 | } 163 | 164 | BOOST_FIXTURE_TEST_CASE(test_getUnits, Fixture) { 165 | int* i_array = NULL; 166 | 167 | error = SMO_getUnits(p_handle, &i_array, &array_dim); 168 | BOOST_REQUIRE(error == 0); 169 | 170 | std::vector test; 171 | test.assign(i_array, i_array + array_dim); 172 | 173 | // unit system, flow units, pollut units 174 | const int ref_dim = 4; 175 | const int ref_array[ref_dim] = {SMO_US, SMO_CFS, SMO_MG, SMO_UG}; 176 | 177 | std::vector ref; 178 | ref.assign(ref_array, ref_array + ref_dim); 179 | 180 | BOOST_CHECK_EQUAL_COLLECTIONS(ref.begin(), ref.end(), test.begin(), 181 | test.end()); 182 | 183 | SMO_free((void**)&i_array); 184 | } 185 | 186 | BOOST_FIXTURE_TEST_CASE(test_getFlowUnits, Fixture) { 187 | int units = -1; 188 | 189 | error = SMO_getFlowUnits(p_handle, &units); 190 | BOOST_REQUIRE(error == 0); 191 | BOOST_CHECK_EQUAL(0, units); 192 | } 193 | 194 | BOOST_FIXTURE_TEST_CASE(test_getPollutantUnits, Fixture) { 195 | int* i_array = NULL; 196 | 197 | error = SMO_getPollutantUnits(p_handle, &i_array, &array_dim); 198 | BOOST_REQUIRE(error == 0); 199 | 200 | std::vector test; 201 | test.assign(i_array, i_array + array_dim); 202 | 203 | const int ref_dim = 2; 204 | int ref_array[ref_dim] = {0, 1}; 205 | 206 | std::vector ref; 207 | ref.assign(ref_array, ref_array + ref_dim); 208 | 209 | BOOST_CHECK_EQUAL_COLLECTIONS(ref.begin(), ref.end(), test.begin(), 210 | test.end()); 211 | 212 | SMO_free((void**)&i_array); 213 | BOOST_CHECK(i_array == NULL); 214 | } 215 | 216 | BOOST_FIXTURE_TEST_CASE(test_getStartDate, Fixture) { 217 | double date = -1; 218 | 219 | error = SMO_getStartDate(p_handle, &date); 220 | BOOST_REQUIRE(error == 0); 221 | 222 | BOOST_CHECK_EQUAL(35796., date); 223 | } 224 | 225 | BOOST_FIXTURE_TEST_CASE(test_getTimes, Fixture) { 226 | int time = -1; 227 | 228 | error = SMO_getTimes(p_handle, SMO_reportStep, &time); 229 | BOOST_REQUIRE(error == 0); 230 | 231 | BOOST_CHECK_EQUAL(3600, time); 232 | 233 | error = SMO_getTimes(p_handle, SMO_numPeriods, &time); 234 | BOOST_REQUIRE(error == 0); 235 | 236 | BOOST_CHECK_EQUAL(36, time); 237 | } 238 | 239 | BOOST_FIXTURE_TEST_CASE(test_getElementName, Fixture) { 240 | char* c_array = NULL; 241 | int index = 1; 242 | 243 | error = SMO_getElementName(p_handle, SMO_node, index, &c_array, &array_dim); 244 | BOOST_REQUIRE(error == 0); 245 | 246 | std::string test(c_array); 247 | std::string ref("10"); 248 | BOOST_CHECK(check_string(test, ref)); 249 | 250 | SMO_free((void**)&c_array); 251 | } 252 | 253 | BOOST_FIXTURE_TEST_CASE(test_getSubcatchSeries, Fixture) { 254 | error = SMO_getSubcatchSeries(p_handle, 1, SMO_runoff_rate, 0, 10, &array, 255 | &array_dim); 256 | BOOST_REQUIRE(error == 0); 257 | 258 | const int ref_dim = 10; 259 | float ref_array[ref_dim] = { 260 | 0.0f, 1.2438242f, 2.5639679f, 4.524055f, 2.5115132f, 0.69808137f, 261 | 0.040894926f, 0.011605669f, 0.00509294f, 0.0027438672f}; 262 | 263 | std::vector ref_vec; 264 | ref_vec.assign(ref_array, ref_array + 10); 265 | 266 | std::vector test_vec; 267 | test_vec.assign(array, array + array_dim); 268 | 269 | BOOST_CHECK(check_cdd_float(test_vec, ref_vec, 3)); 270 | } 271 | 272 | BOOST_FIXTURE_TEST_CASE(test_getSystemSeries, Fixture) { 273 | error = SMO_getSystemSeries(p_handle, SMO_runoff_flow, 0, 10, &array, 274 | &array_dim); 275 | BOOST_REQUIRE(error == 0); 276 | 277 | const int ref_dim = 10; 278 | float ref_array[ref_dim] = { 279 | 0.0f, 6.216825f, 13.030855f, 24.252975f, 14.172027f, 4.1949716f, 280 | 0.322329f, 0.056010f, 0.024938f, 0.012474f}; 281 | 282 | std::vector ref_vec; 283 | ref_vec.assign(ref_array, ref_array + 10); 284 | 285 | std::vector test_vec; 286 | test_vec.assign(array, array + array_dim); 287 | 288 | BOOST_CHECK(check_cdd_float(test_vec, ref_vec, 3)); 289 | } 290 | 291 | 292 | BOOST_FIXTURE_TEST_CASE(test_getSubcatchResult, Fixture) { 293 | error = SMO_getSubcatchResult(p_handle, 1, 1, &array, &array_dim); 294 | BOOST_REQUIRE(error == 0); 295 | 296 | const int ref_dim = 10; 297 | float ref_array[ref_dim] = { 298 | 0.5f, 0.0f, 0.0f, 0.125f, 1.2438242f, 299 | 0.0f, 0.0f, 0.0f, 33.481991f, 6.6963983f}; 300 | 301 | std::vector ref_vec; 302 | ref_vec.assign(ref_array, ref_array + ref_dim); 303 | 304 | std::vector test_vec; 305 | test_vec.assign(array, array + array_dim); 306 | 307 | BOOST_CHECK(check_cdd_float(test_vec, ref_vec, 3)); 308 | } 309 | 310 | BOOST_FIXTURE_TEST_CASE(test_getNodeResult, Fixture) { 311 | error = SMO_getNodeResult(p_handle, 2, 2, &array, &array_dim); 312 | BOOST_REQUIRE(error == 0); 313 | 314 | const int ref_dim = 8; 315 | float ref_array[ref_dim] = { 316 | 0.296234f, 995.296204f, 0.0f, 1.302650f, 1.302650f, 0.0f, 317 | 15.361463f, 3.072293f}; 318 | 319 | std::vector ref_vec; 320 | ref_vec.assign(ref_array, ref_array + ref_dim); 321 | 322 | std::vector test_vec; 323 | test_vec.assign(array, array + array_dim); 324 | 325 | BOOST_CHECK(check_cdd_float(test_vec, ref_vec, 3)); 326 | } 327 | 328 | BOOST_FIXTURE_TEST_CASE(test_getLinkResult, Fixture) { 329 | error = SMO_getLinkResult(p_handle, 3, 3, &array, &array_dim); 330 | BOOST_REQUIRE(error == 0); 331 | 332 | const int ref_dim = 7; 333 | float ref_array[ref_dim] = { 334 | 4.631762f, 1.0f, 5.8973422f, 314.15927f, 1.0f, 19.070757f, 335 | 3.8141515f}; 336 | 337 | std::vector ref_vec; 338 | ref_vec.assign(ref_array, ref_array + ref_dim); 339 | 340 | std::vector test_vec; 341 | test_vec.assign(array, array + array_dim); 342 | 343 | BOOST_CHECK(check_cdd_float(test_vec, ref_vec, 3)); 344 | } 345 | 346 | BOOST_FIXTURE_TEST_CASE(test_getSystemResult, Fixture) { 347 | error = SMO_getSystemResult(p_handle, 4, 4, &array, &array_dim); 348 | BOOST_REQUIRE(error == 0); 349 | 350 | const int ref_dim = 14; 351 | float ref_array[ref_dim] = { 352 | 70.0f, 0.1f, 0.0f, 0.19042271f, 14.172027f, 0.0f, 0.0f, 0.0f, 353 | 0.0f, 14.172027f, 0.55517411f, 13.622702f, 2913.0793f, 0.0f}; 354 | 355 | std::vector ref_vec; 356 | ref_vec.assign(ref_array, ref_array + ref_dim); 357 | 358 | std::vector test_vec; 359 | test_vec.assign(array, array + array_dim); 360 | 361 | BOOST_CHECK(check_cdd_float(test_vec, ref_vec, 3)); 362 | } 363 | 364 | BOOST_AUTO_TEST_SUITE_END() 365 | -------------------------------------------------------------------------------- /src/solver/shape.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // shape.c 3 | // 4 | // Project: EPA SWMM5 5 | // Version: 5.2 6 | // Date: 11/01/21 (Build 5.2.0) 7 | // Author: L. Rossman 8 | // 9 | // Geometry functions for custom cross-section shapes. 10 | //----------------------------------------------------------------------------- 11 | #define _CRT_SECURE_NO_DEPRECATE 12 | 13 | #include 14 | #include "headers.h" 15 | 16 | //----------------------------------------------------------------------------- 17 | // Shared variables 18 | //----------------------------------------------------------------------------- 19 | static double Atotal; 20 | static double Ptotal; 21 | 22 | //----------------------------------------------------------------------------- 23 | // External functions (declared in funcs.h) 24 | //----------------------------------------------------------------------------- 25 | // shape_validate (called from project_validate in project.c) 26 | 27 | //----------------------------------------------------------------------------- 28 | // Local functions 29 | //----------------------------------------------------------------------------- 30 | static int computeShapeTables(TShape *shape, TTable *curve); 31 | static void getSmax(TShape *shape); 32 | static int normalizeShapeTables(TShape *shape); 33 | static int getNextInterval(TTable *curve, double y, double yLast, double wLast, 34 | double *y1, double *y2, double *w1, double *w2, 35 | double *wMax); 36 | static double getWidth(double y, double y1, double y2, double w1, double w2); 37 | static double getArea(double y, double w, double y1, double w1); 38 | static double getPerim(double y, double w, double y1, double w1); 39 | 40 | //============================================================================= 41 | 42 | int shape_validate(TShape *shape, TTable *curve) 43 | // 44 | // Input: shape = pointer to a custom x-section TShape object 45 | // curve = pointer to shape's table of width v. height 46 | // Output: returns TRUE if successful. FALSE if not 47 | // Purpose: computes the entries in a custom x-section shape's geometry 48 | // tables from its user-supplied width v. height curve. 49 | // 50 | { 51 | if (!computeShapeTables(shape, curve)) { 52 | return FALSE; 53 | } 54 | 55 | if (!normalizeShapeTables(shape)) { 56 | return FALSE; 57 | } 58 | 59 | return TRUE; 60 | } 61 | 62 | //============================================================================= 63 | 64 | int computeShapeTables(TShape *shape, TTable *curve) 65 | // 66 | // Input: shape = pointer to a TShape object 67 | // curve = pointer to shape's table of width v. depth 68 | // Output: returns TRUE if successful. FALSE if not 69 | // Purpose: computes the entries in a shape's geometry tables from 70 | // the shape's width v. height curve normalized with repsect 71 | // to full height. 72 | // 73 | // Note: the shape curve is a user-supplied table of width v. height 74 | // for a custom x-section of unit height. 75 | { 76 | int i, n; 77 | double dy, y, y1, y2, w, w1, w2; 78 | double yLast, wLast, wMax; 79 | 80 | // --- get first entry of user's shape curve 81 | if (!table_getFirstEntry(curve, &y1, &w1)) { 82 | return FALSE; 83 | } 84 | 85 | if (y1 < 0.0 || y1 >= 1.0 || w1 < 0.0) { 86 | return FALSE; 87 | } 88 | 89 | wMax = w1; 90 | 91 | // --- if first entry not at zero ht. then add an initial entry 92 | if (y1 != 0.0) { 93 | y2 = y1; 94 | w2 = w1; 95 | y1 = 0.0; 96 | w1 = 0.0; 97 | } 98 | // --- otherwise get next entry in the user's shape curve 99 | else { 100 | if (!table_getNextEntry(curve, &y2, &w2)) { 101 | return FALSE; 102 | } 103 | 104 | if (y2 < y1 || w2 < 0.0) { 105 | return FALSE; 106 | } 107 | 108 | if (y2 > 1.0) { 109 | y2 = 1.0; 110 | } 111 | 112 | if (w2 > wMax) { 113 | wMax = w2; 114 | } 115 | } 116 | 117 | // --- determine number of entries & interval size in geom. tables 118 | shape->nTbl = N_SHAPE_TBL; 119 | n = shape->nTbl - 1; 120 | dy = 1.0 / (double)(n); 121 | 122 | // --- initialize geometry tables 123 | shape->areaTbl[0] = 0.0; 124 | shape->hradTbl[0] = 0.0; 125 | shape->widthTbl[0] = w1; 126 | Ptotal = w1; 127 | Atotal = 0.0; 128 | 129 | // --- fill in rest of geometry tables 130 | y = 0.0; 131 | w = w1; 132 | 133 | for (i = 1; i <= n; i++) { 134 | // --- advance to next relative height level 135 | yLast = y; 136 | wLast = w; 137 | y = y + dy; 138 | 139 | // --- do not allow height to exceed 1.0 140 | if (fabs(y - 1.0) < TINY) { 141 | y = 1.0; 142 | } 143 | 144 | // --- if height exceeds current shape curve interval, 145 | // move to next interval of shape curve 146 | if (y > y2) { 147 | if (!getNextInterval(curve, y, yLast, wLast, &y1, &y2, &w1, &w2, 148 | &wMax)) { 149 | return FALSE; 150 | } 151 | 152 | yLast = y1; 153 | wLast = w1; 154 | } 155 | 156 | // --- get top width, area, & perimeter of current interval 157 | w = getWidth(y, y1, y2, w1, w2); 158 | Atotal += getArea(y, w, yLast, wLast); 159 | Ptotal += getPerim(y, w, yLast, wLast); 160 | 161 | // --- add top width to total perimeter if at top of shape 162 | if (y == 1.0) { 163 | Ptotal += w2; 164 | } 165 | 166 | // --- update table values 167 | shape->widthTbl[i] = w; 168 | shape->areaTbl[i] = Atotal; 169 | if (Ptotal > 0.0) { 170 | shape->hradTbl[i] = Atotal / Ptotal; 171 | } else { 172 | shape->hradTbl[i] = 0.0; 173 | } 174 | } 175 | 176 | // --- assign values to shape'a area and hyd. radius when full 177 | shape->aFull = shape->areaTbl[n]; 178 | shape->rFull = shape->hradTbl[n]; 179 | 180 | // --- assign values to shape's max. width and section factor 181 | shape->wMax = wMax; 182 | getSmax(shape); 183 | 184 | return TRUE; 185 | } 186 | 187 | //============================================================================= 188 | 189 | void getSmax(TShape *shape) 190 | // 191 | // Input: shape = pointer to a TShape object 192 | // Output: none 193 | // Purpose: computes the max. section factor and corresponding area 194 | // for a shape of unit height. 195 | // 196 | { 197 | int i; 198 | int n = shape->nTbl - 1; 199 | double sf; 200 | 201 | shape->sMax = 0.0; 202 | shape->aMax = 0.0; 203 | 204 | for (i = 1; i <= n; i++) { 205 | sf = shape->areaTbl[i] * pow(shape->hradTbl[i], 2. / 3.); 206 | 207 | if (sf > shape->sMax) { 208 | shape->sMax = sf; 209 | shape->aMax = shape->areaTbl[i]; 210 | } 211 | } 212 | } 213 | 214 | //============================================================================= 215 | 216 | int normalizeShapeTables(TShape *shape) 217 | // 218 | // Input: shape = pointer to a TShape object 219 | // Output: returns TRUE if successful. FALSE if not 220 | // Purpose: normalizes a shape's area tables to its full (or max.) condition. 221 | // 222 | { 223 | int i; 224 | int n = shape->nTbl - 1; // highest table entry index 225 | double aFull = shape->aFull; // area when full 226 | double rFull = shape->rFull; // hyd. radius when full 227 | double wMax = shape->wMax; // max. width 228 | 229 | // --- check that normalizing factors are non-zero 230 | if (aFull == 0.0 || rFull == 0.0 || wMax == 0.0) { 231 | return FALSE; 232 | } 233 | 234 | // --- normalize entries in each table by their respective factors 235 | for (i = 0; i <= n; i++) { 236 | shape->areaTbl[i] /= aFull; 237 | shape->hradTbl[i] /= rFull; 238 | shape->widthTbl[i] /= wMax; 239 | } 240 | 241 | return TRUE; 242 | } 243 | 244 | //============================================================================= 245 | 246 | int getNextInterval(TTable *curve, double y, double yLast, double wLast, 247 | double *y1, double *y2, double *w1, double *w2, 248 | double *wMax) 249 | // 250 | // Input: curve = pointer to a user-supplied shape curve table 251 | // y = current height in a geometry table 252 | // yLast = previous height in a geometry table 253 | // wLast = previous width in a geometry table 254 | // y1 = height at start of current curve interval 255 | // y2 = height at end of current curve interval 256 | // w1 = width at start of current curve interval 257 | // w2 = width at end of current curve interval 258 | // wMax = current maximum width of curve 259 | // Output: updated values for yLast, wLast, y1, y2, w1, w2, and wMax; 260 | // returns TRUE if successful, FALSE if not. 261 | // Purpose: advances to the next height interval of a shape's curve that 262 | // contains the current height being evaluated in the shape's 263 | // geometry table. 264 | // 265 | // Note: heights and widths are with repsect to a shape of unit height. 266 | { 267 | // --- keep advancing while the current geom. table height is 268 | // above the end of the curve table interval 269 | while (y > *y2) { 270 | // --- move start of geom. table interval up to the end of 271 | // the current curve table interval 272 | if (*y2 > yLast) { 273 | Atotal += getArea(*y2, *w2, yLast, wLast); 274 | Ptotal += getPerim(*y2, *w2, yLast, wLast); 275 | yLast = *y2; 276 | wLast = *w2; 277 | } 278 | 279 | // --- move to the next curve table interval 280 | *y1 = *y2; 281 | *w1 = *w2; 282 | if (!table_getNextEntry(curve, y2, w2)) { 283 | *y2 = 1.0; 284 | return TRUE; 285 | } 286 | 287 | // --- update curve table's max. width 288 | if (*w2 > *wMax) { 289 | *wMax = *w2; 290 | } 291 | 292 | // --- check for valid curve table values 293 | if (*y2 < *y1 || *w2 < 0.0) { 294 | return FALSE; 295 | } 296 | 297 | if (*y2 > 1.0) { 298 | *y2 = 1.0; 299 | } 300 | } 301 | 302 | return TRUE; 303 | } 304 | 305 | //============================================================================= 306 | 307 | double getWidth(double y, double y1, double y2, double w1, double w2) 308 | // 309 | // Input: y = height along a shape curve 310 | // y1 = height at start of a shape curve interval 311 | // y2 = height at end of a shape curve interval 312 | // w1 = width at start of a shape curve interval 313 | // w2 = width at end of a shape curve interval 314 | // Output: returns the width corresponding to height y 315 | // Purpose: interpolates a width within a given height interval along a 316 | // x-section's shape curve. 317 | // 318 | { 319 | if (y2 == y1) { 320 | return w2; 321 | } 322 | 323 | return w1 + (y - y1) / (y2 - y1) * (w2 - w1); 324 | } 325 | 326 | //============================================================================= 327 | 328 | double getArea(double y, double w, double y1, double w1) 329 | // 330 | // Input: y = height along a shape curve 331 | // w = width that corresponds to y 332 | // y1 = height at start of a shape curve interval 333 | // w1 = width at start of a shape curve interval 334 | // Output: returns the area within the trapezoid formed by the input points 335 | // Purpose: computes the area of an interval along a x-section's shape curve. 336 | // 337 | { 338 | double wMin, wMax; 339 | 340 | if (w > w1) { 341 | wMin = w1; 342 | wMax = w; 343 | } else { 344 | wMin = w; 345 | wMax = w1; 346 | } 347 | 348 | return (wMin + (wMax - wMin) / 2.0) * (y - y1); 349 | } 350 | 351 | //============================================================================= 352 | 353 | double getPerim(double y, double w, double y1, double w1) 354 | // 355 | // Input: y = height along a shape curve 356 | // w = width that corresponds to y 357 | // y1 = height at start of a shape curve interval 358 | // w1 = width at start of a shape curve interval 359 | // Output: returns the length of the sides of the trapezoid formed by the 360 | // input points 361 | // Purpose: computes the length of the wetted perimeter contributed by an 362 | // interval along a x-section's shape curve. 363 | // 364 | { 365 | double dy = y - y1; 366 | double dw = fabs(w - w1) / 2.0; 367 | 368 | return 2.0 * sqrt(dy * dy + dw * dw); 369 | } 370 | -------------------------------------------------------------------------------- /src/solver/inputrpt.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // inputrpt.c 3 | // 4 | // Project: EPA SWMM5 5 | // Version: 5.2 6 | // Date: 11/01/21 (Build 5.2.0) 7 | // Author: L. Rossman 8 | // 9 | // Report writing functions for input data summary. 10 | // 11 | // Update History 12 | // ============== 13 | // Build 5.2.0: 14 | // - Support added for reporting Street geometry tables. 15 | //----------------------------------------------------------------------------- 16 | #define _CRT_SECURE_NO_DEPRECATE 17 | 18 | #include 19 | #include 20 | #include "headers.h" 21 | #include "lid.h" 22 | 23 | #define WRITE(x) (report_writeLine((x))) 24 | 25 | //============================================================================= 26 | 27 | void inputrpt_writeInput() 28 | // 29 | // Input: none 30 | // Output: none 31 | // Purpose: writes summary of input data to report file. 32 | // 33 | { 34 | int m; 35 | int i, k; 36 | int lidCount = 0; 37 | if ( ErrorCode ) return; 38 | 39 | WRITE(""); 40 | WRITE("*************"); 41 | WRITE("Element Count"); 42 | WRITE("*************"); 43 | fprintf(Frpt.file, "\n Number of rain gages ...... %d", Nobjects[GAGE]); 44 | fprintf(Frpt.file, "\n Number of subcatchments ... %d", Nobjects[SUBCATCH]); 45 | fprintf(Frpt.file, "\n Number of nodes ........... %d", Nobjects[NODE]); 46 | fprintf(Frpt.file, "\n Number of links ........... %d", Nobjects[LINK]); 47 | fprintf(Frpt.file, "\n Number of pollutants ...... %d", Nobjects[POLLUT]); 48 | fprintf(Frpt.file, "\n Number of land uses ....... %d", Nobjects[LANDUSE]); 49 | 50 | if ( Nobjects[POLLUT] > 0 ) 51 | { 52 | WRITE(""); 53 | WRITE(""); 54 | WRITE("*****************"); 55 | WRITE("Pollutant Summary"); 56 | WRITE("*****************"); 57 | fprintf(Frpt.file, 58 | "\n Ppt. GW Kdecay"); 59 | fprintf(Frpt.file, 60 | "\n Name Units Concen. Concen. 1/days CoPollutant"); 61 | fprintf(Frpt.file, 62 | "\n -----------------------------------------------------------------------"); 63 | for (i = 0; i < Nobjects[POLLUT]; i++) 64 | { 65 | fprintf(Frpt.file, "\n %-20s %5s%10.2f%10.2f%10.2f", Pollut[i].ID, 66 | QualUnitsWords[Pollut[i].units], Pollut[i].pptConcen, 67 | Pollut[i].gwConcen, Pollut[i].kDecay*SECperDAY); 68 | if ( Pollut[i].coPollut >= 0 ) 69 | fprintf(Frpt.file, " %-s (%.2f)", 70 | Pollut[Pollut[i].coPollut].ID, Pollut[i].coFraction); 71 | } 72 | } 73 | 74 | if ( Nobjects[LANDUSE] > 0 ) 75 | { 76 | WRITE(""); 77 | WRITE(""); 78 | WRITE("***************"); 79 | WRITE("Landuse Summary"); 80 | WRITE("***************"); 81 | fprintf(Frpt.file, 82 | "\n Sweeping Maximum Last"); 83 | fprintf(Frpt.file, 84 | "\n Name Interval Removal Swept"); 85 | fprintf(Frpt.file, 86 | "\n ---------------------------------------------------"); 87 | for (i=0; i 0 ) 96 | { 97 | WRITE(""); 98 | WRITE(""); 99 | WRITE("****************"); 100 | WRITE("Raingage Summary"); 101 | WRITE("****************"); 102 | fprintf(Frpt.file, 103 | "\n Data Recording"); 104 | fprintf(Frpt.file, 105 | "\n Name Data Source Type Interval "); 106 | fprintf(Frpt.file, 107 | "\n ------------------------------------------------------------------------"); 108 | for (i = 0; i < Nobjects[GAGE]; i++) 109 | { 110 | if ( Gage[i].tSeries >= 0 ) 111 | { 112 | fprintf(Frpt.file, "\n %-20s %-30s ", 113 | Gage[i].ID, Tseries[Gage[i].tSeries].ID); 114 | fprintf(Frpt.file, "%-10s %3d min.", 115 | RainTypeWords[Gage[i].rainType], 116 | (Gage[i].rainInterval)/60); 117 | } 118 | else fprintf(Frpt.file, "\n %-20s %-30s", 119 | Gage[i].ID, Gage[i].fname); 120 | } 121 | } 122 | 123 | if ( Nobjects[SUBCATCH] > 0 ) 124 | { 125 | WRITE(""); 126 | WRITE(""); 127 | WRITE("********************"); 128 | WRITE("Subcatchment Summary"); 129 | WRITE("********************"); 130 | fprintf(Frpt.file, 131 | "\n Name Area Width %%Imperv %%Slope Rain Gage Outlet "); 132 | fprintf(Frpt.file, 133 | "\n -----------------------------------------------------------------------------------------------------------"); 134 | for (i = 0; i < Nobjects[SUBCATCH]; i++) 135 | { 136 | fprintf(Frpt.file,"\n %-20s %10.2f%10.2f%10.2f%10.4f %-20s ", 137 | Subcatch[i].ID, Subcatch[i].area*UCF(LANDAREA), 138 | Subcatch[i].width*UCF(LENGTH), Subcatch[i].fracImperv*100.0, 139 | Subcatch[i].slope*100.0, Gage[Subcatch[i].gage].ID); 140 | if ( Subcatch[i].outNode >= 0 ) 141 | { 142 | fprintf(Frpt.file, "%-20s", Node[Subcatch[i].outNode].ID); 143 | } 144 | else if ( Subcatch[i].outSubcatch >= 0 ) 145 | { 146 | fprintf(Frpt.file, "%-20s", Subcatch[Subcatch[i].outSubcatch].ID); 147 | } 148 | if ( Subcatch[i].lidArea ) lidCount++; 149 | } 150 | } 151 | if ( lidCount > 0 ) lid_writeSummary(); 152 | 153 | if ( Nobjects[NODE] > 0 ) 154 | { 155 | WRITE(""); 156 | WRITE(""); 157 | WRITE("************"); 158 | WRITE("Node Summary"); 159 | WRITE("************"); 160 | fprintf(Frpt.file, 161 | "\n Invert Max. Ponded External"); 162 | fprintf(Frpt.file, 163 | "\n Name Type Elev. Depth Area Inflow "); 164 | fprintf(Frpt.file, 165 | "\n -------------------------------------------------------------------------------"); 166 | for (i = 0; i < Nobjects[NODE]; i++) 167 | { 168 | fprintf(Frpt.file, "\n %-20s %-16s%10.2f%10.2f%10.1f", Node[i].ID, 169 | NodeTypeWords[Node[i].type-JUNCTION], 170 | Node[i].invertElev*UCF(LENGTH), 171 | Node[i].fullDepth*UCF(LENGTH), 172 | Node[i].pondedArea*UCF(LENGTH)*UCF(LENGTH)); 173 | if ( Node[i].extInflow || Node[i].dwfInflow || Node[i].rdiiInflow ) 174 | { 175 | fprintf(Frpt.file, " Yes"); 176 | } 177 | } 178 | } 179 | 180 | if ( Nobjects[LINK] > 0 ) 181 | { 182 | WRITE(""); 183 | WRITE(""); 184 | WRITE("************"); 185 | WRITE("Link Summary"); 186 | WRITE("************"); 187 | fprintf(Frpt.file, 188 | "\n Name From Node To Node Type Length %%Slope Roughness"); 189 | fprintf(Frpt.file, 190 | "\n ---------------------------------------------------------------------------------------------"); 191 | for (i = 0; i < Nobjects[LINK]; i++) 192 | { 193 | // --- list end nodes in their original orientation 194 | if ( Link[i].direction == 1 ) 195 | fprintf(Frpt.file, "\n %-16s %-16s %-16s ", 196 | Link[i].ID, Node[Link[i].node1].ID, Node[Link[i].node2].ID); 197 | else 198 | fprintf(Frpt.file, "\n %-16s %-16s %-16s ", 199 | Link[i].ID, Node[Link[i].node2].ID, Node[Link[i].node1].ID); 200 | 201 | // --- list link type 202 | if ( Link[i].type == PUMP ) 203 | { 204 | k = Link[i].subIndex; 205 | fprintf(Frpt.file, "%-5s PUMP ", 206 | PumpTypeWords[Pump[k].type]); 207 | } 208 | else fprintf(Frpt.file, "%-12s", 209 | LinkTypeWords[Link[i].type-CONDUIT]); 210 | 211 | // --- list length, slope and roughness for conduit links 212 | if (Link[i].type == CONDUIT) 213 | { 214 | k = Link[i].subIndex; 215 | fprintf(Frpt.file, "%10.1f%10.4f%10.4f", 216 | Conduit[k].length*UCF(LENGTH), 217 | Conduit[k].slope*100.0*Link[i].direction, 218 | Conduit[k].roughness); 219 | } 220 | } 221 | 222 | WRITE(""); 223 | WRITE(""); 224 | WRITE("*********************"); 225 | WRITE("Cross Section Summary"); 226 | WRITE("*********************"); 227 | fprintf(Frpt.file, 228 | "\n Full Full Hyd. Max. No. of Full"); 229 | fprintf(Frpt.file, 230 | "\n Conduit Shape Depth Area Rad. Width Barrels Flow"); 231 | fprintf(Frpt.file, 232 | "\n ---------------------------------------------------------------------------------------"); 233 | for (i = 0; i < Nobjects[LINK]; i++) 234 | { 235 | if (Link[i].type == CONDUIT) 236 | { 237 | k = Link[i].subIndex; 238 | fprintf(Frpt.file, "\n %-16s ", Link[i].ID); 239 | if ( Link[i].xsect.type == CUSTOM ) 240 | fprintf(Frpt.file, "%-16s ", Curve[Link[i].xsect.transect].ID); 241 | else if ( Link[i].xsect.type == IRREGULAR ) 242 | fprintf(Frpt.file, "%-16s ", 243 | Transect[Link[i].xsect.transect].ID); 244 | else if ( Link[i].xsect.type == STREET_XSECT ) 245 | fprintf(Frpt.file, "%-16s ", 246 | Street[Link[i].xsect.transect].ID); 247 | else fprintf(Frpt.file, "%-16s ", 248 | XsectTypeWords[Link[i].xsect.type]); 249 | fprintf(Frpt.file, "%8.2f %8.2f %8.2f %8.2f %3d %8.2f", 250 | Link[i].xsect.yFull*UCF(LENGTH), 251 | Link[i].xsect.aFull*UCF(LENGTH)*UCF(LENGTH), 252 | Link[i].xsect.rFull*UCF(LENGTH), 253 | Link[i].xsect.wMax*UCF(LENGTH), 254 | Conduit[k].barrels, 255 | Link[i].qFull*UCF(FLOW)); 256 | } 257 | } 258 | } 259 | 260 | if (Nobjects[SHAPE] > 0) 261 | { 262 | WRITE(""); 263 | WRITE(""); 264 | WRITE("*************"); 265 | WRITE("Shape Summary"); 266 | WRITE("*************"); 267 | for (i = 0; i < Nobjects[SHAPE]; i++) 268 | { 269 | k = Shape[i].curve; 270 | fprintf(Frpt.file, "\n\n Shape %s", Curve[k].ID); 271 | fprintf(Frpt.file, "\n Area: "); 272 | for ( m = 1; m < N_SHAPE_TBL; m++) 273 | { 274 | if ( m % 5 == 1 ) fprintf(Frpt.file,"\n "); 275 | fprintf(Frpt.file, "%10.4f ", Shape[i].areaTbl[m]); 276 | } 277 | fprintf(Frpt.file, "\n Hrad: "); 278 | for ( m = 1; m < N_SHAPE_TBL; m++) 279 | { 280 | if ( m % 5 == 1 ) fprintf(Frpt.file,"\n "); 281 | fprintf(Frpt.file, "%10.4f ", Shape[i].hradTbl[m]); 282 | } 283 | fprintf(Frpt.file, "\n Width: "); 284 | for ( m = 1; m < N_SHAPE_TBL; m++) 285 | { 286 | if ( m % 5 == 1 ) fprintf(Frpt.file,"\n "); 287 | fprintf(Frpt.file, "%10.4f ", Shape[i].widthTbl[m]); 288 | } 289 | } 290 | } 291 | 292 | if (Nobjects[TRANSECT] > 0) 293 | { 294 | WRITE(""); 295 | WRITE(""); 296 | WRITE("****************"); 297 | WRITE("Transect Summary"); 298 | WRITE("****************"); 299 | for (i = 0; i < Nobjects[TRANSECT]; i++) 300 | { 301 | fprintf(Frpt.file, "\n\n Transect %s", Transect[i].ID); 302 | fprintf(Frpt.file, "\n Area: "); 303 | for ( m = 1; m < N_TRANSECT_TBL; m++) 304 | { 305 | if ( m % 5 == 1 ) fprintf(Frpt.file,"\n "); 306 | fprintf(Frpt.file, "%10.4f ", Transect[i].areaTbl[m]); 307 | } 308 | fprintf(Frpt.file, "\n Hrad: "); 309 | for ( m = 1; m < N_TRANSECT_TBL; m++) 310 | { 311 | if ( m % 5 == 1 ) fprintf(Frpt.file,"\n "); 312 | fprintf(Frpt.file, "%10.4f ", Transect[i].hradTbl[m]); 313 | } 314 | fprintf(Frpt.file, "\n Width: "); 315 | for ( m = 1; m < N_TRANSECT_TBL; m++) 316 | { 317 | if ( m % 5 == 1 ) fprintf(Frpt.file,"\n "); 318 | fprintf(Frpt.file, "%10.4f ", Transect[i].widthTbl[m]); 319 | } 320 | } 321 | } 322 | 323 | if (Nobjects[STREET] > 0) 324 | { 325 | WRITE(""); 326 | WRITE(""); 327 | WRITE("**************"); 328 | WRITE("Street Summary"); 329 | WRITE("**************"); 330 | for (i = 0; i < Nobjects[STREET]; i++) 331 | { 332 | fprintf(Frpt.file, "\n\n Street %s", Street[i].ID); 333 | fprintf(Frpt.file, "\n Area: "); 334 | for (m = 1; m < Street[i].transect.nTbl; m++) 335 | { 336 | if (m % 5 == 1) fprintf(Frpt.file, "\n "); 337 | fprintf(Frpt.file, "%10.4f ", Street[i].transect.areaTbl[m]); 338 | } 339 | fprintf(Frpt.file, "\n Hrad: "); 340 | for (m = 1; m < Street[i].transect.nTbl; m++) 341 | { 342 | if (m % 5 == 1) fprintf(Frpt.file, "\n "); 343 | fprintf(Frpt.file, "%10.4f ", Street[i].transect.hradTbl[m]); 344 | } 345 | fprintf(Frpt.file, "\n Width: "); 346 | for (m = 1; m < Street[i].transect.nTbl; m++) 347 | { 348 | if (m % 5 == 1) fprintf(Frpt.file, "\n "); 349 | fprintf(Frpt.file, "%10.4f ", Street[i].transect.widthTbl[m]); 350 | } 351 | } 352 | } 353 | WRITE(""); 354 | } 355 | --------------------------------------------------------------------------------