diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 6dab50d49..56fc11b0c 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -67,7 +67,7 @@ jobs: - name: Setup python uses: actions/setup-python@v4 with: - python-version: '3.7' + python-version: '3.11' - name: Install requirements run: | @@ -80,7 +80,7 @@ jobs: - name: Before reg test env: NRTESTS_URL: https://github.com/USEPA/swmm-nrtestsuite - BENCHMARK_TAG: v2.2.0 + BENCHMARK_TAG: v2.5.0-dev run: before-nrtest.cmd ${{ env.BENCHMARK_TAG }} - name: Run reg test diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b651cf71..99af0d1cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ endif() project(swmm-solver - VERSION 5.2.3 + VERSION 5.2.4 LANGUAGES C CXX ) diff --git a/README.md b/README.md index 2f24cbad4..cdfbc9aba 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,23 @@ -ORD Stormwater-Management-Model Solver -================================== +# ORD Stormwater-Management-Model Solver Stormwater Management Model (aka "SWMM") solver only - ## Build Status + [![Build and Test](../../actions/workflows/build-and-test.yml/badge.svg)](../../actions/workflows/build-and-test.yml) + [![Build Docs](../../actions/workflows/build_docs.yml/badge.svg)](../../actions/workflows/build_docs.yml) -## Disclaimer -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. +## Disclaimer +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. ## Introduction + 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. 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. - ## Find Out More -The source code distributed here is identical to the code found at the official [SWMM Website](http://www2.epa.gov/water-research/storm-water-management-model-swmm). + +The source code distributed here is identical to the code found at the official [SWMM Website](https://www.epa.gov/water-research/storm-water-management-model-swmm). diff --git a/src/outfile/swmm_output.c b/src/outfile/swmm_output.c index 77d893692..6430650a6 100644 --- a/src/outfile/swmm_output.c +++ b/src/outfile/swmm_output.c @@ -728,7 +728,7 @@ int EXPORT_OUT_API SMO_getSystemSeries(SMO_Handle p_handle, SMO_systemAttribute errorcode = 411; else { // loop over and build time series - for (k = 0; k < length; k++) + for (k = 0; k < len; k++) temp[k] = getSystemValue(p_data, startPeriod + k, attr); *outValueArray = temp; diff --git a/src/solver/consts.h b/src/solver/consts.h index 84433f391..0b1f1a245 100644 --- a/src/solver/consts.h +++ b/src/solver/consts.h @@ -1,379 +1,377 @@ /*! -* \file consts.h -* \brief Constants used in the SWMM model -* \author L. Rossman -* \author Caleb Buahin (Last Editor) -* \date 02/12/2023 (Build 5.2.3) -* \date 05/28/2023 (Last Updated) -* \version 5.2 -*/ - + * \file consts.h + * \brief Constants used in the SWMM model + * \author L. Rossman + * \author Caleb Buahin (Last Editor) + * \date 02/12/2023 (Build 5.2.3) + * \date 05/28/2023 (Last Updated) + * \version 5.2 + */ #ifndef CONSTS_H #define CONSTS_H -/*! -* \defgroup general_constants General Constants -* \brief General constants used in the SWMM model -* @{ -*/ +/*! + * \defgroup general_constants General Constants + * \brief General constants used in the SWMM model + * @{ + */ /*! -* \def VERSION -* \brief model version number -*/ -#define VERSION 52003 + * \def VERSION + * \brief model version number + */ +#define VERSION 52003 /*! -* \def MAGICNUMBER -* \brief magic number used to validate a SWMM output file -*/ -#define MAGICNUMBER 516114522 + * \def MAGICNUMBER + * \brief magic number used to validate a SWMM output file + */ +#define MAGICNUMBER 516114522 /*! -* \def EOFMARK -* \brief end of file mark. Use 0x04 for UNIX systems -*/ -#define EOFMARK 0x1A + * \def EOFMARK + * \brief end of file mark. Use 0x04 for UNIX systems + */ +#define EOFMARK 0x1A /*! -* \def MAXTITLE -* \brief maximum number of title lines -*/ -#define MAXTITLE 3 + * \def MAXTITLE + * \brief maximum number of title lines + */ +#define MAXTITLE 3 /*! -* \def MAXMSG -* \brief maximum number of characters in message text -*/ -#define MAXMSG 1024 + * \def MAXMSG + * \brief maximum number of characters in message text + */ +#define MAXMSG 1024 /*! -* \def MAXLINE -* \brief maximum number of characters per input line -*/ -#define MAXLINE 1024 + * \def MAXLINE + * \brief maximum number of characters per input line + */ +#define MAXLINE 1024 /*! -* \def MAXFNAME -* \brief maximum number of characters in file name -*/ -#define MAXFNAME 259 + * \def MAXFNAME + * \brief maximum number of characters in file name + */ +#define MAXFNAME 259 /*! -* \def MAXTOKS -* \brief maximum number of items per input line -*/ -#define MAXTOKS 40 + * \def MAXTOKS + * \brief maximum number of items per input line + */ +#define MAXTOKS 40 /*! -* \def MAXSTATES -* \brief maximum number of computed hydraulic variables -*/ -#define MAXSTATES 10 + * \def MAXSTATES + * \brief maximum number of computed hydraulic variables + */ +#define MAXSTATES 10 /*! -* \def MAXODES -* \brief maximum number of ODEs to be solved -*/ -#define MAXODES 4 + * \def MAXODES + * \brief maximum number of ODEs to be solved + */ +#define MAXODES 4 /*! -* \def NA -* \brief NOT APPLICABLE code -*/ -#define NA -1 + * \def NA + * \brief NOT APPLICABLE code + */ +#define NA -1 /*! -* \def TRUE -* \brief Value for TRUE state -*/ -#define TRUE 1 + * \def TRUE + * \brief Value for TRUE state + */ +#define TRUE 1 /*! -* \def FALSE -* \brief Value for FALSE state -*/ -#define FALSE 0 + * \def FALSE + * \brief Value for FALSE state + */ +#define FALSE 0 /*! -* \def BIG -* \brief Generic large value -*/ -#define BIG 1.E10 + * \def BIG + * \brief Generic large value + */ +#define BIG 1.E10 /*! -* \def TINY -* \brief Generic small value -*/ -#define TINY 1.E-6 + * \def TINY + * \brief Generic small value + */ +#define TINY 1.E-6 /*! -* \def ZERO -* \brief Effective zero value -*/ -#define ZERO 1.E-10 + * \def ZERO + * \brief Effective zero value + */ +#define ZERO 1.E-10 /*! -* \def MISSING -* \brief Missing value code -*/ -#define MISSING -1.E10 + * \def MISSING + * \brief Missing value code + */ +#define MISSING -1.E10 /*! -* \def PI -* \brief Value of pi -*/ -#define PI 3.141592654 + * \def PI + * \brief Value of pi + */ +#define PI 3.141592654 /*! -* \def GRAVITY -* \brief accel. of gravity in US units -*/ -#define GRAVITY 32.2 + * \def GRAVITY + * \brief accel. of gravity in US units + */ +#define GRAVITY 32.2 /*! -* \def SI_GRAVITY -* \brief accel. of gravity in SI units -*/ -#define SI_GRAVITY 9.81 + * \def SI_GRAVITY + * \brief accel. of gravity in SI units + */ +#define SI_GRAVITY 9.81 /*! -* \def MAXFILESIZE -* \brief largest file size in bytes -* \deprecated This constant is no longer used in the SWMM source code. -*/ -#define MAXFILESIZE 2147483647L // largest file size in bytes + * \def MAXFILESIZE + * \brief largest file size in bytes + * \deprecated This constant is no longer used in the SWMM source code. + */ +#define MAXFILESIZE 2147483647L // largest file size in bytes /*! -* @} -*/ + * @} + */ /*! -* \defgroup manning_factors Mannings Units Conversion Factor -* \brief Conversion factor used in the Manning Equation -* @{ -*/ + * \defgroup manning_factors Mannings Units Conversion Factor + * \brief Conversion factor used in the Manning Equation + * @{ + */ /*! -* \def PHI -* \brief Conversion factor used in the Manning Equation -*/ -#define PHI 1.486 + * \def PHI + * \brief Conversion factor used in the Manning Equation + */ +#define PHI 1.486 /*! -* @} -*/ + * @} + */ /*! -* \defgroup measurable_runoff_depth Measurable Runoff Flow & Depth -* \brief Minimum measurable runoff flow & depth -* @{ -*/ + * \defgroup measurable_runoff_depth Measurable Runoff Flow & Depth + * \brief Minimum measurable runoff flow & depth + * @{ + */ /*! -* \def MIN_RUNOFF_FLOW -* \brief Minimum measurable runoff flow -*/ -#define MIN_RUNOFF_FLOW 0.001 + * \def MIN_RUNOFF_FLOW + * \brief Minimum measurable runoff flow + */ +#define MIN_RUNOFF_FLOW 0.001 /*! -* \def MIN_EXCESS_DEPTH -* \brief Minimum measurable excess depth. ft, = 0.03 mm -*/ -#define MIN_EXCESS_DEPTH 0.0001 + * \def MIN_EXCESS_DEPTH + * \brief Minimum measurable excess depth. ft, = 0.03 mm + */ +#define MIN_EXCESS_DEPTH 0.0001 /*! -* \def MIN_TOTAL_DEPTH -* \brief Minimum measurable total depth. ft, = 0.05 inches -*/ -#define MIN_TOTAL_DEPTH 0.004167 + * \def MIN_TOTAL_DEPTH + * \brief Minimum measurable total depth. ft, = 0.05 inches + */ +#define MIN_TOTAL_DEPTH 0.004167 /*! -* \def MIN_RUNOFF -* \brief Minimum measurable runoff depth. ft, = 0.001 inches -*/ -#define MIN_RUNOFF 2.31481e-8 + * \def MIN_RUNOFF + * \brief Minimum measurable runoff depth. ft, = 0.001 inches + */ +#define MIN_RUNOFF 2.31481e-8 /*! -* @} -*/ + * @} + */ /*! -* \defgroup min_flow_depth_volume Minimum Flow, Depth & Volume -* \brief Minimum flow, depth & volume used to evaluate steady state conditions -* @{ -*/ + * \defgroup min_flow_depth_volume Minimum Flow, Depth & Volume + * \brief Minimum flow, depth & volume used to evaluate steady state conditions + * @{ + */ /*! -* \def FLOW_TOL -* \brief Minimum flow used to evaluate steady state conditions. cfs -*/ -#define FLOW_TOL 0.00001 + * \def FLOW_TOL + * \brief Minimum flow used to evaluate steady state conditions. cfs + */ +#define FLOW_TOL 0.00001 /*! -* \def DEPTH_TOL -* \brief Minimum depth used to evaluate steady state conditions. ft -*/ -#define DEPTH_TOL 0.00001 + * \def DEPTH_TOL + * \brief Minimum depth used to evaluate steady state conditions. ft + */ +#define DEPTH_TOL 0.00001 /*! -* \def VOLUME_TOL -* \brief Minimum volume used to evaluate steady state conditions. ft3 -*/ -#define VOLUME_TOL 0.01 + * \def VOLUME_TOL + * \brief Minimum volume used to evaluate steady state conditions. ft3 + */ +#define VOLUME_TOL 0.01 /*! -* @} -*/ + * @} + */ //--------------------------------------------------- // Minimum depth for reporting non-zero water quality //--------------------------------------------------- -//#define MIN_WQ_DEPTH 0.01 // ft (= 3 mm) -//#define MIN_WQ_FLOW 0.001 // cfs - +// #define MIN_WQ_DEPTH 0.01 // ft (= 3 mm) +// #define MIN_WQ_FLOW 0.001 // cfs /*! -* \defgroup min_flow_area_dynwave Minimum Flow Depth & Area for Dynamic Wave Routing -* \brief Minimum flow depth & area for dynamic wave routing -* @{ -*/ + * \defgroup min_flow_area_dynwave Minimum Flow Depth & Area for Dynamic Wave + * Routing \brief Minimum flow depth & area for dynamic wave routing + * @{ + */ /*! -* \def FUDGE -* \brief Fudge factor used to evaluate steady state conditions. ft or ft2 -*/ -#define FUDGE 0.0001 // ft or ft2 + * \def FUDGE + * \brief Fudge factor used to evaluate steady state conditions. ft or ft2 + */ +#define FUDGE 0.0001 // ft or ft2 /*! -* @} -*/ + * @} + */ /*! -* \defgroup conversion_factors Conversion Factors -* \brief Various conversion factors -* @{ -*/ + * \defgroup conversion_factors Conversion Factors + * \brief Various conversion factors + * @{ + */ /*! -* \def GPMperCFS -* \brief Conversion factor for gallons per minute to cubic feet per second -*/ -#define GPMperCFS 448.831 + * \def GPMperCFS + * \brief Conversion factor for gallons per minute to cubic feet per second + */ +#define GPMperCFS 448.831 /*! -* \def AFDperCFS -* \brief Conversion factor for acre-feet per day to cubic feet per second -*/ -#define AFDperCFS 1.9837 + * \def AFDperCFS + * \brief Conversion factor for acre-feet per day to cubic feet per second + */ +#define AFDperCFS 1.9837 /*! -* \def MGDperCFS -* \brief Conversion factor for million gallons per day to cubic feet per second -*/ -#define MGDperCFS 0.64632 + * \def MGDperCFS + * \brief Conversion factor for million gallons per day to cubic feet per second + */ +#define MGDperCFS 0.64632 /*! -* \def IMGDperCFS -* \brief Conversion factor for million gallons per day to cubic feet per second -*/ -#define IMGDperCFS 0.5382 + * \def IMGDperCFS + * \brief Conversion factor for million gallons per day to cubic feet per second + */ +#define IMGDperCFS 0.5382 /*! -* \def CMSperCFS -* \brief Conversion factor for cubic meters per second to cubic feet per second -*/ -#define LPSperCFS 28.317 + * \def CMSperCFS + * \brief Conversion factor for cubic meters per second to cubic feet per second + */ +#define LPSperCFS 28.317 /*! -* \def LPMperCFS -* \brief Conversion factor for liters per minute to cubic feet per second -*/ -#define LPMperCFS 1699.0 + * \def LPMperCFS + * \brief Conversion factor for liters per minute to cubic feet per second + */ +#define LPMperCFS 1699.0 /*! -* \def CMHperCFS -* \brief Conversion factor for cubic meters per hour to cubic feet per second -*/ -#define CMHperCFS 101.94 + * \def CMHperCFS + * \brief Conversion factor for cubic meters per hour to cubic feet per second + */ +#define CMHperCFS 101.94 /*! -* \def CMDperCFS -* \brief Conversion factor for cubic meters per day to cubic feet per second -*/ -#define CMDperCFS 2446.6 + * \def CMDperCFS + * \brief Conversion factor for cubic meters per day to cubic feet per second + */ +#define CMDperCFS 2446.6 /*! -* \def MLDperCFS -* \brief Conversion factor for megaliters per day to cubic feet per second -*/ -#define MLDperCFS 2.4466 + * \def MLDperCFS + * \brief Conversion factor for megaliters per day to cubic feet per second + */ +#define MLDperCFS 2.4466 /*! -* \def M3perFT3 -* \brief Conversion factor for cubic meters to cubic feet -*/ -#define M3perFT3 0.028317 + * \def M3perFT3 + * \brief Conversion factor for cubic meters to cubic feet + */ +#define M3perFT3 0.028317 /*! -* \def LperFT3 -* \brief Conversion factor for liters to cubic feet -*/ -#define LperFT3 28.317 + * \def LperFT3 + * \brief Conversion factor for liters to cubic feet + */ +#define LperFT3 28.317 /*! -* \def MperFT -* \brief Conversion factor for meters to feet -*/ -#define MperFT 0.3048 + * \def MperFT + * \brief Conversion factor for meters to feet + */ +#define MperFT 0.3048 /*! -* \def PSIperFT -* \brief Conversion factor for pounds per square inch to feet -*/ -#define PSIperFT 0.4333 + * \def PSIperFT + * \brief Conversion factor for pounds per square inch to feet + */ +#define PSIperFT 0.4333 /*! -* \def KPAperPSI -* \brief Conversion factor for kilopascals to pounds per square inch -*/ -#define KPAperPSI 6.895 + * \def KPAperPSI + * \brief Conversion factor for kilopascals to pounds per square inch + */ +#define KPAperPSI 6.895 /*! -* \def KWperHP -* \brief Conversion factor for kilowatts to horsepower -*/ -#define KWperHP 0.7457 + * \def KWperHP + * \brief Conversion factor for kilowatts to horsepower + */ +#define KWperHP 0.7457 /*! -* \def SECperDAY -* \brief Conversion factor for seconds to days -*/ -#define SECperDAY 86400 + * \def SECperDAY + * \brief Conversion factor for seconds to days + */ +#define SECperDAY 86400 /*! -* \def MSECperDAY -* \brief Conversion factor for milliseconds to days -*/ -#define MSECperDAY 8.64e7 + * \def MSECperDAY + * \brief Conversion factor for milliseconds to days + */ +#define MSECperDAY 8.64e7 /*! -* \def MMperINCH -* \brief Conversion factor for millimeters to inches -*/ -#define MMperINCH 25.40 + * \def MMperINCH + * \brief Conversion factor for millimeters to inches + */ +#define MMperINCH 25.40 /*! -* @} -*/ + * @} + */ /*! -* \defgroup token_seperators Token Separators -* \brief Token separator characters -* @{ -*/ + * \defgroup token_seperators Token Separators + * \brief Token separator characters + * @{ + */ /*! -* \def SEPSTR -* \brief Token separator characters -*/ -#define SEPSTR " \t\n\r" + * \def SEPSTR + * \brief Token separator characters + */ +#define SEPSTR " \t\n\r" /*! -* @} -*/ - + * @} + */ -#endif //CONSTS_H +#endif // CONSTS_H diff --git a/src/solver/dwflow.c b/src/solver/dwflow.c index d6484fe57..25b2b874a 100644 --- a/src/solver/dwflow.c +++ b/src/solver/dwflow.c @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 08/01/22 (Build 5.2.1) +// Date: 06/12/23 (Build 5.2.4) // Author: L. Rossman // M. Tryby (EPA) // R. Dickinson (CDM) @@ -26,6 +26,8 @@ // (qOld) in call to link_getLossRate. // Build 5.2.1: // - Implements the new option to skip checking for normal flow limitations. +// Build 5.2.4: +// - Arguments to function link_getLossRate changed. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -231,7 +233,7 @@ void dwflow_findConduitFlow(int j, int steps, double omega, double dt) } // --- 6. term for evap and seepage losses per unit length - dq6 = link_getLossRate(j, qLast) * 2.5 * dt * v / link_getLength(j); + dq6 = link_getLossRate(j, DW, qLast, dt) * 2.5 * dt * v / link_getLength(j); // --- combine terms to find new conduit flow denom = 1.0 + dq1 + dq5; diff --git a/src/solver/dynwave.c b/src/solver/dynwave.c index ac302e849..85968e2a9 100644 --- a/src/solver/dynwave.c +++ b/src/solver/dynwave.c @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 11/01/21 (Build 5.2.0) +// Date: 07/13/23 (Build 5.2.4) // Author: L. Rossman // M. Tryby (EPA) // R. Dickinson (CDM) @@ -44,6 +44,9 @@ // - Roll back the 5.1.014 change for conduit losses in updateNodeFlows(). // Build 5.2.0: // - Support added for reporting most frequent non-converging links. +// Build 5.2.4: +// - Conduit evap+seepage outflow split evenly between outflow from +// conduit's upstream and non-outfall downstream nodes. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -129,7 +132,7 @@ void dynwave_init() " Not enough memory for dynamic wave routing."); return; } - + // --- initialize node surface areas & crown elev. for (i = 0; i < Nobjects[NODE]; i++ ) { @@ -144,6 +147,7 @@ void dynwave_init() j = Link[i].node1; z = Node[j].invertElev + Link[i].offset1 + Link[i].xsect.yFull; Node[j].crownElev = MAX(Node[j].crownElev, z); + j = Link[i].node2; z = Node[j].invertElev + Link[i].offset2 + Link[i].xsect.yFull; Node[j].crownElev = MAX(Node[j].crownElev, z); @@ -534,29 +538,39 @@ void updateNodeFlows(int i) int n1 = Link[i].node1; int n2 = Link[i].node2; double q = Link[i].newFlow; - double uniformLossRate = 0.0; - - // --- compute any uniform seepage loss from a conduit - if ( Link[i].type == CONDUIT ) - { - k = Link[i].subIndex; - uniformLossRate = Conduit[k].evapLossRate + Conduit[k].seepLossRate; - barrels = Conduit[k].barrels; - uniformLossRate *= barrels; - } + double conduitLossRate = 0.0; // --- update total inflow & outflow at upstream/downstream nodes if ( q >= 0.0 ) { - Node[n1].outflow += q + uniformLossRate; + Node[n1].outflow += q; Node[n2].inflow += q; } else { Node[n1].inflow -= q; - Node[n2].outflow -= q - uniformLossRate; + Node[n2].outflow -= q; } - + + // --- add any uniform evap & seepage loss from conduit link + if ( Link[i].type == CONDUIT ) + { + k = Link[i].subIndex; + barrels = Conduit[k].barrels; + conduitLossRate = (Conduit[k].evapLossRate + Conduit[k].seepLossRate) * + barrels; + if (conduitLossRate > 0.0) + { + // --- outfall nodes do not share evap & seepage losses + if (Node[n1].type != OUTFALL && Node[n2].type != OUTFALL) + conduitLossRate /= 2.0; + if (Node[n1].type != OUTFALL) + Node[n1].outflow += conduitLossRate; + if (Node[n2].type != OUTFALL) + Node[n2].outflow += conduitLossRate; + } + } + // --- add surf. area contributions to upstream/downstream nodes Xnode[Link[i].node1].newSurfArea += Link[i].surfArea1 * barrels; Xnode[Link[i].node2].newSurfArea += Link[i].surfArea2 * barrels; @@ -585,7 +599,7 @@ int findNodeDepths(double dt) // { int i; - double yOld; // previous node depth (ft) + double yOld = 0.0; // previous node depth (ft) // --- compute outfall depths based on flow in connecting link for ( i = 0; i < Nobjects[LINK]; i++ ) link_setOutfallDepth(i); @@ -654,12 +668,11 @@ void setNodeDepth(int i, double dt) Node[i].overflow = 0.0; surfArea = Xnode[i].newSurfArea; surfArea = MAX(surfArea, MinSurfArea); - + // --- determine average net flow volume into node over the time step dQ = Node[i].inflow - Node[i].outflow; dV = 0.5 * (Node[i].oldNetInflow + dQ) * dt; - // --- determine if node is EXTRAN surcharged if (SurchargeMethod == EXTRAN) { diff --git a/src/solver/flowrout.c b/src/solver/flowrout.c index f296c3fb0..73f5f67d4 100644 --- a/src/solver/flowrout.c +++ b/src/solver/flowrout.c @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 05/02/22 (Build 5.2.1) +// Date: 06/12/23 (Build 5.2.4) // Author: L. Rossman // M. Tryby (EPA) // @@ -27,6 +27,8 @@ // Build 5.2.1: // - For storage routing, after convergence the reported depth is now // based on the last volume found rather than the next trial depth. +// Build 5.2.4: +// - Arguments to link_getLossRate changed. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -767,7 +769,7 @@ int steadyflow_execute(int j, double* qin, double* qout, double tStep) else { // --- adjust flow for evap and infil losses - q -= link_getLossRate(j, q); + q -= link_getLossRate(j, SF, q, tStep); // --- flow can't exceed full flow if ( q > Link[j].qFull ) diff --git a/src/solver/funcs.h b/src/solver/funcs.h index 6f9782723..f28748319 100644 --- a/src/solver/funcs.h +++ b/src/solver/funcs.h @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 11/01/21 (Build 5.2.0) +// Date: 06/12/23 (Build 5.2.4) // Author: L. Rossman // M. Tryby (EPA) // @@ -29,6 +29,8 @@ // - Support added for named variables & math expressions in control rules. // - Support added for tracking a gage's prior n-hour rainfall total. // - Refactored external inflow code. +// Build 5.2.4: +// - Additional arguments added to function link_getLossRate. //----------------------------------------------------------------------------- #ifndef FUNCS_H @@ -422,7 +424,7 @@ double link_getYnorm(int link, double q); double link_getVelocity(int link, double q, double y); double link_getFroude(int link, double v, double y); double link_getPower(int link); -double link_getLossRate(int link, double q); +double link_getLossRate(int link, int routeModel, double q, double tstep); char link_getFullState(double a1, double a2, double aFull); void link_getResults(int link, double wt, float x[]); diff --git a/src/solver/hotstart.c b/src/solver/hotstart.c index 69f7abcc9..376403b9d 100644 --- a/src/solver/hotstart.c +++ b/src/solver/hotstart.c @@ -35,6 +35,9 @@ // - Link control setting bug when reading a hot start file fixed. // Build 5.1.015: // - Support added for multiple infiltration methods within a project. +// Build 5.2.5: +// - Fixed bug in fwrite count argument when writing catchment landuse pollutant +// build-up. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -416,7 +419,7 @@ void saveRunoff(void) for (j=0; j i) && (! getDouble(toks[i], &x[i-2]) || x[i-2]) < 0.0 ) + if ( (ntoks > i) && (! getDouble(toks[i], &x[i-2]) || x[i-2] < 0.0) ) return error_setInpError(ERR_NUMBER, toks[i]); } diff --git a/src/solver/lidproc.c b/src/solver/lidproc.c index aae0ac9bd..85245fb30 100644 --- a/src/solver/lidproc.c +++ b/src/solver/lidproc.c @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 11/01/21 (Build 5.2.0) +// Date: 07/13/23 (Build 5.2.4) // Author: L. Rossman // // This module computes the hydrologic performance of an LID (Low Impact @@ -53,6 +53,11 @@ // - Fixed failure to account for effect of Impervious Surface Fraction on // pavement permeability for Permeable Pavement LID // - Fixed units conversion for pavement depth in detailed report file. +// Build 5.2.4: +// - Modified flux limits in biocellFluxRates, pavementFluxRates and +// trenchFluxRates. +// - Corrected head calculation in getStorageDrainRate when unit has both +// a soil and pavement layer. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -654,61 +659,64 @@ void biocellFluxRates(double x[], double f[]) SurfaceInfil = MIN(SurfaceInfil, maxRate); } - //... storage & soil layers are full - else if ( soilTheta >= soilPorosity && storageDepth >= storageThickness ) + else { - //... limiting rate is smaller of soil perc and storage outflow - maxRate = StorageExfil + StorageDrain; - if ( SoilPerc < maxRate ) + //... storage & soil layers are full + if ( soilTheta >= soilPorosity && storageDepth >= storageThickness ) { - maxRate = SoilPerc; - if ( maxRate > StorageExfil ) StorageDrain = maxRate - StorageExfil; - else + //... limiting rate is smaller of soil perc and storage outflow + maxRate = StorageExfil + StorageDrain; + if ( SoilPerc < maxRate ) { - StorageExfil = maxRate; - StorageDrain = 0.0; + maxRate = SoilPerc; + if ( maxRate > StorageExfil ) StorageDrain = maxRate - StorageExfil; + else + { + StorageExfil = maxRate; + StorageDrain = 0.0; + } } - } - else SoilPerc = maxRate; - - //... apply limiting rate to surface infil. - SurfaceInfil = MIN(SurfaceInfil, maxRate); - } + else SoilPerc = maxRate; - //... either layer not full - else if ( storageThickness > 0.0 ) - { - //... limit storage exfiltration by available storage volume - maxRate = SoilPerc - StorageEvap + storageDepth*storageVoidFrac/Tstep; - StorageExfil = MIN(StorageExfil, maxRate); - StorageExfil = MAX(StorageExfil, 0.0); + //... apply limiting rate to surface infil. + SurfaceInfil = MIN(SurfaceInfil, maxRate); + } - //... limit underdrain flow by volume above drain offset - if ( StorageDrain > 0.0 ) + //... either layer not full + else { - maxRate = -StorageExfil - StorageEvap; - if ( storageDepth >= storageThickness) maxRate += SoilPerc; - if ( theLidProc->drain.offset <= storageDepth ) + //... limit storage exfiltration by available storage volume + maxRate = SoilPerc - StorageEvap + storageDepth*storageVoidFrac/Tstep; + StorageExfil = MIN(StorageExfil, maxRate); + StorageExfil = MAX(StorageExfil, 0.0); + + //... limit underdrain flow by volume above drain offset + if ( StorageDrain > 0.0 ) { - maxRate += (storageDepth - theLidProc->drain.offset) * - storageVoidFrac/Tstep; + maxRate = -StorageExfil - StorageEvap; + if ( storageDepth >= storageThickness) maxRate += SoilPerc; + if ( theLidProc->drain.offset <= storageDepth ) + { + maxRate += (storageDepth - theLidProc->drain.offset) * + storageVoidFrac/Tstep; + } + maxRate = MAX(maxRate, 0.0); + StorageDrain = MIN(StorageDrain, maxRate); } - maxRate = MAX(maxRate, 0.0); - StorageDrain = MIN(StorageDrain, maxRate); - } - - //... limit soil perc by unused storage volume - maxRate = StorageExfil + StorageDrain + StorageEvap + - (storageThickness - storageDepth) * - storageVoidFrac/Tstep; - SoilPerc = MIN(SoilPerc, maxRate); + + //... limit soil perc by unused storage volume + maxRate = StorageExfil + StorageDrain + StorageEvap + + (storageThickness - storageDepth) * + storageVoidFrac/Tstep; + SoilPerc = MIN(SoilPerc, maxRate); - //... limit surface infil. by unused soil volume - maxRate = (soilPorosity - soilTheta) * soilThickness / Tstep + - SoilPerc + SoilEvap; - SurfaceInfil = MIN(SurfaceInfil, maxRate); + //... limit surface infil. by unused soil volume + maxRate = (soilPorosity - soilTheta) * soilThickness / Tstep + + SoilPerc + SoilEvap; + SurfaceInfil = MIN(SurfaceInfil, maxRate); + } } - + //... find surface layer outflow rate SurfaceOutflow = getSurfaceOutflowRate(surfaceDepth); @@ -803,7 +811,7 @@ void trenchFluxRates(double x[], double f[]) SurfaceOutflow = getSurfaceOutflowRate(surfaceDepth); // ... find net fluxes for each layer - f[SURF] = SurfaceInflow - SurfaceEvap - StorageInflow - SurfaceOutflow / + f[SURF] = (SurfaceInflow - SurfaceEvap - StorageInflow - SurfaceOutflow) / theLidProc->surface.voidFrac;; f[STOR] = (StorageInflow - StorageEvap - StorageExfil - StorageDrain) / theLidProc->storage.voidFrac; @@ -966,6 +974,7 @@ void pavementFluxRates(double x[], double f[]) StorageExfil = MIN(StorageExfil, SoilPerc); StorageDrain = SoilPerc - StorageExfil; } + PavePerc = MIN(PavePerc, SoilPerc); //... limit surface infil. by available pavement volume availVolume = (paveThickness - paveDepth) * paveVoidFrac; @@ -981,6 +990,8 @@ void pavementFluxRates(double x[], double f[]) PavePerc = MIN(PavePerc, SoilPerc); SoilPerc = PavePerc; SurfaceInfil = MIN(SurfaceInfil,PavePerc); + maxRate = MAX(StorageVolume / Tstep + SoilPerc - StorageEvap, 0.0); + StorageExfil = MIN(StorageExfil, maxRate); } //... no adjoining layers are full @@ -1370,7 +1381,11 @@ double getStorageDrainRate(double storageDepth, double soilTheta, // depth in layer above it if ( soilTheta >= soilPorosity ) { - if ( paveThickness > 0.0 ) head += paveDepth; + if ( paveThickness > 0.0 ) + { + head += paveDepth; + if ( paveDepth >= paveThickness ) head += surfaceDepth; + } else head += surfaceDepth; } } @@ -1378,7 +1393,7 @@ double getStorageDrainRate(double storageDepth, double soilTheta, // --- no soil layer so increase head by water level in pavement // layer and possibly surface layer - if ( paveThickness > 0.0 ) + else if ( paveThickness > 0.0 ) { head += paveDepth; if ( paveDepth >= paveThickness ) head += surfaceDepth; diff --git a/src/solver/link.c b/src/solver/link.c index 052a030b9..c8e035f4c 100644 --- a/src/solver/link.c +++ b/src/solver/link.c @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 10/29/22 (Build 5.2.2) +// Date: 06/12/23 (Build 5.2.4) // Author: L. Rossman // M. Tryby (EPA) // @@ -46,6 +46,8 @@ // - Warning no longer issued when conduit elevation drop < MIN_DELTA_Z. // Build 5.2.2: // - Warning for conduit elevation drop < MIN_DELTA_Z restored. +// Build 5.2.4: +// - Conduit evap+seepage loss under DW routing limited by conduit volume. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -99,7 +101,8 @@ static double conduit_getLength(int j); static double conduit_getLengthFactor(int j, int k, double roughness); static double conduit_getSlope(int j); static double conduit_getInflow(int j); -static double conduit_getLossRate(int j, double q); +static double conduit_getLossRate(int j, int routeModel, double q, + double tstep); static int pump_readParams(int j, int k, char* tok[], int ntoks); static void pump_validate(int j, int k); @@ -887,9 +890,10 @@ double link_getPower(int j) //============================================================================= -double link_getLossRate(int j, double q) +double link_getLossRate(int j, int routeModel, double q, double tstep) // // Input: j = link index +// routeModel = flow routing model type // q = flow rate (ft3/sec) // tstep = time step (sec) // Output: returns uniform loss rate in link (ft3/sec) @@ -897,7 +901,8 @@ double link_getLossRate(int j, double q) // evaporation and seepage. // { - if ( Link[j].type == CONDUIT ) return conduit_getLossRate(j, q); + if ( Link[j].type == CONDUIT ) + return conduit_getLossRate(j, routeModel, q, tstep); else return 0.0; } @@ -1326,10 +1331,12 @@ double conduit_getInflow(int j) //============================================================================= -double conduit_getLossRate(int j, double q) +double conduit_getLossRate(int j, int routeModel, double q, double tstep) // // Input: j = link index +// routeModel = type of flow routing model // q = current link flow rate (cfs) +// tstep = current routing time step (sec) // Output: returns rate of evaporation & seepage losses (ft3/sec) // Purpose: computes volumetric rate of water evaporation & seepage // from a conduit (per barrel). @@ -1338,7 +1345,7 @@ double conduit_getLossRate(int j, double q) TXsect *xsect; double depth = 0.5 * (Link[j].oldDepth + Link[j].newDepth); double length; - double topWidth; + double width, topWidth; double evapLossRate = 0.0, seepLossRate = 0.0, totalLossRate = 0.0; @@ -1359,19 +1366,25 @@ double conduit_getLossRate(int j, double q) if ( Link[j].seepRate > 0.0 ) { // limit depth to depth at max width - if ( depth >= xsect->ywMax ) depth = xsect->ywMax; + if (xsect->type == RECT_CLOSED) width = xsect->wMax; + else + { + if ( depth >= xsect->ywMax ) depth = xsect->ywMax; + width = xsect_getWofY(xsect, depth); + } // compute seepage loss rate across length of conduit - seepLossRate = Link[j].seepRate * xsect_getWofY(xsect, depth) * - length; + seepLossRate = Link[j].seepRate * width * length; seepLossRate *= Adjust.hydconFactor; } // --- compute total loss rate totalLossRate = evapLossRate + seepLossRate; - // --- total loss rate cannot exceed flow rate - q = ABS(q); + // --- limit total loss rate to current volume for DW routing + // or current link flow rate otherwise + if (routeModel == DW) q = Link[j].newVolume / tstep; + else q = ABS(q); if (totalLossRate > q) { evapLossRate = evapLossRate * q / totalLossRate; diff --git a/src/solver/project.c b/src/solver/project.c index a5a20dbd8..266fef914 100644 --- a/src/solver/project.c +++ b/src/solver/project.c @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 11/21/22 (Build 5.2.2) +// Date: 07/17/23 (Build 5.2.4) // Author: L. Rossman // // Project management functions. @@ -52,6 +52,10 @@ // Build 5.2.2: // - Default number of threads changed from OMP max. number to 1 // to be consistent with User Manual. +// Build 5.2.4: +// - Default Inertial Damping changed from SOME to PARTIAL_DAMPING. +// - Default CourantFactor changed from 0 (fixed routing time step) +// - to 0.75 (variable time step) //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -842,12 +846,12 @@ void setDefaults() SurchargeMethod = EXTRAN; // Use EXTRAN method for surcharging CrownCutoff = 0.96; // Fractional pipe crown cutoff AllowPonding = FALSE; // No ponding at nodes - InertDamping = SOME; // Partial inertial damping + InertDamping = PARTIAL_DAMPING; // Partial inertial damping NormalFlowLtd = BOTH; // Default normal flow limitation ForceMainEqn = H_W; // Hazen-Williams eqn. for force mains LinkOffsets = DEPTH_OFFSET; // Use depth for link offsets LengtheningStep = 0; // No lengthening of conduits - CourantFactor = 0.0; // No variable time step + CourantFactor = 0.75; // Variable time step reduced to 75% MinSurfArea = 0.0; // Force use of default min. surface area MinSlope = 0.0; // No user supplied minimum conduit slope SkipSteadyState = FALSE; // Do flow routing in steady state periods diff --git a/src/solver/statsrpt.c b/src/solver/statsrpt.c index 52cc169eb..8c69c5c2f 100644 --- a/src/solver/statsrpt.c +++ b/src/solver/statsrpt.c @@ -30,6 +30,9 @@ // Build 5.2.2 // - Calculation of % Evaporation and % Exfiltration losses for storage // units was corrected. +// Build 5.2.5 +// - Changed flow format to scientific to prevent the merging of extremely +// large flows that make it difficult to interpret results. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -89,8 +92,8 @@ void statsrpt_writeReport() // { // --- set number of decimal places for reporting flow values - if ( FlowUnits == MGD || FlowUnits == CMS ) sstrncpy(FlowFmt, "%9.3f", 5); - else sstrncpy(FlowFmt, "%9.2f", 5); + if ( FlowUnits == MGD || FlowUnits == CMS ) sstrncpy(FlowFmt, "%9.3g", 5); + else sstrncpy(FlowFmt, "%9.2g", 5); // --- conversion factor from cu. ft. to mil. gallons or megaliters if (UnitSystem == US) Vcf = 7.48 / 1.0e6; diff --git a/src/solver/street.c b/src/solver/street.c index fd05451b7..0c55d9115 100644 --- a/src/solver/street.c +++ b/src/solver/street.c @@ -3,11 +3,14 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 11/01/21 (Build 5.2.0) +// Date: 07/13/23 (Build 5.2.4) // Author: L. Rossman // // Street Cross-Section Functions // +// Build 5.2.4: +// - Fixed incorrect index used to retrieve street backing parameters +// in street_readParams. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -106,8 +109,8 @@ int street_readParams(char* tok[], int ntoks) // --- read street backing parameters if (ntoks > 8) { - if (!getDouble(tok[8], &x[8]) || x[k] < 0.0) - return error_setInpError(ERR_NUMBER, tok[k]); + if (!getDouble(tok[8], &x[8]) || x[8] < 0.0) + return error_setInpError(ERR_NUMBER, tok[8]); if (x[8] > 0.0) { if (ntoks < 11) return error_setInpError(ERR_ITEMS, ""); diff --git a/src/solver/surfqual.c b/src/solver/surfqual.c index aa17ed644..4b1a2f7d3 100644 --- a/src/solver/surfqual.c +++ b/src/solver/surfqual.c @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 11/01/21 (Build 5.2.0) +// Date: 07/14/23 (Build 5.2.4) // Author: L. Rossman // // Subcatchment water quality functions. @@ -16,6 +16,10 @@ // - Support for separate accounting of LID drain flows included. // Build 5.1.014: // - Fixed bug in computing effective BMP removal by LIDs. +// Build 5.2.4: +// - Set low runoff flow concentrations to zero before computing runoff +// mass loads rather than after so that they match wet weather mass +// inflows reported for conveyance system nodes. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -253,7 +257,7 @@ void surfqual_getWashoff(int j, double runoff, double tStep) { // --- convert washoff load to a concentration cOut = 0.0; - if ( vOut1 > 0.0 ) cOut = OutflowLoad[p] / vOut1; + if ( vOut1 > 0.0 && hasOutflow ) cOut = OutflowLoad[p] / vOut1; // --- assign any difference between pre- and post-LID // subcatchment outflow loads to BMP removal @@ -279,7 +283,6 @@ void surfqual_getWashoff(int j, double runoff, double tStep) } // --- save new washoff concentration - if ( !hasOutflow ) cOut = 0.0; Subcatch[j].newQual[p] = cOut / LperFT3; } diff --git a/src/solver/text.h b/src/solver/text.h index 353296b8e..4bb46f059 100644 --- a/src/solver/text.h +++ b/src/solver/text.h @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 12/22/22 (Build 5.2.3) +// Date: 07/15/23 (Build 5.2.4) // Author: L. Rossman // // Text strings @@ -25,7 +25,7 @@ #define FMT03 " There are errors.\n" #define FMT04 " There are warnings.\n" #define FMT08 \ - "\n EPA STORM WATER MANAGEMENT MODEL - VERSION 5.2 (Build 5.2.3)" + "\n EPA STORM WATER MANAGEMENT MODEL - VERSION 5.2 (Build 5.2.4)" #define FMT09 \ "\n ------------------------------------------------------------" #define FMT10 "\n" diff --git a/src/solver/transect.c b/src/solver/transect.c index 831ba017f..6ebd25558 100644 --- a/src/solver/transect.c +++ b/src/solver/transect.c @@ -3,7 +3,7 @@ // // Project: EPA SWMM5 // Version: 5.2 -// Date: 11/01/21 (Build 5.2.0) +// Date: 07/13/23 (Build 5.2.4) // Author: L. Rossman // // Geometry processing for irregular cross-section transects. @@ -12,6 +12,8 @@ // ============== // Build 5.2.0: // - Function added to create a transect for a Street cross-section. +// Build 5.2.4: +// - Corrected street transect points in transect_createStreetTransect. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -610,8 +612,8 @@ void transect_createStreetTransect(TStreet* street) w2 = street->gutterWidth; w3 = street->width; w4 = w3 - w2; - y3 = street->gutterDepression; - y1 = street->curbHeight + y3; + y3 = street->gutterDepression + street->slope * w2; + y1 = street->curbHeight + street->gutterDepression; ymax = street->backSlope * street->backWidth + y1; y4 = y3 + street->slope * w4; ymax = MAX(ymax, y4); diff --git a/src/solver/xsect.c b/src/solver/xsect.c index 1a53d36e2..78aa926a0 100644 --- a/src/solver/xsect.c +++ b/src/solver/xsect.c @@ -34,6 +34,10 @@ // - Support added for Street cross sections. // Build 5.2.2: // - Feasibility check added to Mod. Baskethandle & Rect.-Round shapes. +// Build 5.2.5: +// - Addressing inconsistent results for custom sized elliptical pipes. +// Stems from inccorect equations for pipe full area and hydraulic radius +// for elliptical pipes from SWMM 4.4. //----------------------------------------------------------------------------- #define _CRT_SECURE_NO_DEPRECATE @@ -569,8 +573,8 @@ int xsect_setParams(TXsect *xsect, int type, double p[], double ucf) // --- length of major axis if ( p[1] < 0.0 ) return FALSE; xsect->wMax = p[1]/ucf; - xsect->aFull = 1.2692 * xsect->yFull * xsect->yFull; - xsect->rFull = 0.3061 * xsect->yFull; + xsect->aFull = 0.8117 * xsect->yFull * xsect->wMax; + xsect->rFull = 0.2448 * sqrt(xsect->yFull * xsect->wMax); } xsect->sFull = xsect->aFull * pow(xsect->rFull, 2./3.); xsect->sMax = xsect->sFull; @@ -597,8 +601,8 @@ int xsect_setParams(TXsect *xsect, int type, double p[], double ucf) // --- length of minor axis xsect->yFull = p[0]/ucf; xsect->wMax = p[1]/ucf; - xsect->aFull = 1.2692 * xsect->wMax * xsect->wMax; - xsect->rFull = 0.3061 * xsect->wMax; + xsect->aFull = 0.8117 * xsect->yFull * xsect->wMax; + xsect->rFull = 0.2448 * sqrt(xsect->yFull * xsect->wMax); } xsect->sFull = xsect->aFull * pow(xsect->rFull, 2./3.); xsect->sMax = xsect->sFull; diff --git a/tests/outfile/test_output.cpp b/tests/outfile/test_output.cpp index 43bc73ad3..f4686245f 100644 --- a/tests/outfile/test_output.cpp +++ b/tests/outfile/test_output.cpp @@ -269,6 +269,26 @@ BOOST_FIXTURE_TEST_CASE(test_getSubcatchSeries, Fixture) { BOOST_CHECK(check_cdd_float(test_vec, ref_vec, 3)); } +BOOST_FIXTURE_TEST_CASE(test_getSystemSeries, Fixture) { + error = SMO_getSystemSeries(p_handle, SMO_runoff_flow, 0, 10, &array, + &array_dim); + BOOST_REQUIRE(error == 0); + + const int ref_dim = 10; + float ref_array[ref_dim] = { + 0.0f, 6.216825f, 13.030855f, 24.252975f, 14.172027f, 4.1949716f, + 0.322329f, 0.056010f, 0.024938f, 0.012474f}; + + std::vector ref_vec; + ref_vec.assign(ref_array, ref_array + 10); + + std::vector test_vec; + test_vec.assign(array, array + array_dim); + + BOOST_CHECK(check_cdd_float(test_vec, ref_vec, 3)); +} + + BOOST_FIXTURE_TEST_CASE(test_getSubcatchResult, Fixture) { error = SMO_getSubcatchResult(p_handle, 1, 1, &array, &array_dim); BOOST_REQUIRE(error == 0);