roadway.c
| Line | Branch | Exec | Source |
|---|---|---|---|
| 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 <math.h> | ||
| 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 | 72008 | 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 | 72008 | q = 0.0, // flow across roadway (cfs) | |
| 100 | 72008 | dqdh = 0.0; // derivative of flow w.r.t. head (ft2/sec) | |
| 101 | |||
| 102 | // --- get road width & surface type | ||
| 103 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 72008 times.
|
72008 | if ( Link[j].type != WEIR ) return 0.0; |
| 104 | 72008 | k = Link[j].subIndex; | |
| 105 | 72008 | roadWidth = Weir[k].roadWidth; | |
| 106 | 72008 | roadSurf = Weir[k].roadSurface; | |
| 107 | |||
| 108 | // --- user-supplied discharge coeff. | ||
| 109 | 72008 | cD = Weir[k].cDisch1; | |
| 110 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 72008 times.
|
72008 | if ( UnitSystem == SI ) cD = cD / 0.552; |
| 111 | |||
| 112 | // --- check if there's enough info to use a variable cD value | ||
| 113 | 72008 | useVariableCd = FALSE; | |
| 114 |
2/4✓ Branch 0 taken 72008 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 72008 times.
✗ Branch 3 not taken.
|
72008 | if ( roadWidth > 0.0 && roadSurf >= 1 ) useVariableCd = TRUE; |
| 115 | |||
| 116 | // --- upstream and downstream heads | ||
| 117 | 72008 | hWr = h1 - hRoad; | |
| 118 | 72008 | ht = h2 - hRoad; | |
| 119 |
2/2✓ Branch 0 taken 356 times.
✓ Branch 1 taken 71652 times.
|
72008 | if ( hWr > FUDGE ) |
| 120 | { | ||
| 121 | // --- get discharge coeff. as function of heads | ||
| 122 |
1/2✓ Branch 0 taken 356 times.
✗ Branch 1 not taken.
|
356 | if ( useVariableCd ) cD = getCd(hWr, ht, roadWidth, roadSurf); |
| 123 | |||
| 124 | // --- use user-supplied weir length | ||
| 125 | 356 | length = Link[j].xsect.wMax; | |
| 126 | |||
| 127 | // --- weir eqn. for discharge across roadway | ||
| 128 | 356 | q = cD * length * pow(hWr, 1.5); | |
| 129 | 356 | dqdh = 1.5 * q / hWr; | |
| 130 | } | ||
| 131 | |||
| 132 | // --- assign output values | ||
| 133 | 72008 | Link[j].dqdh = dqdh; | |
| 134 |
2/2✓ Branch 0 taken 356 times.
✓ Branch 1 taken 71652 times.
|
72008 | Link[j].newDepth = MAX(h1 - hRoad, 0.0); |
| 135 | 72008 | Link[j].flowClass = SUBCRITICAL; | |
| 136 |
1/2✓ Branch 0 taken 72008 times.
✗ Branch 1 not taken.
|
72008 | if ( hRoad > h2 ) |
| 137 | { | ||
| 138 |
1/2✓ Branch 0 taken 72008 times.
✗ Branch 1 not taken.
|
72008 | if ( dir == 1.0 ) Link[j].flowClass = DN_CRITICAL; |
| 139 | ✗ | else Link[j].flowClass = UP_CRITICAL; | |
| 140 | } | ||
| 141 | 72008 | return dir * q; | |
| 142 | } | ||
| 143 | |||
| 144 | //============================================================================= | ||
| 145 | |||
| 146 | 356 | double getCd(double hWr, double ht, double roadWidth, int roadSurf) | |
| 147 | { | ||
| 148 | 356 | 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 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 356 times.
|
356 | if ( hWr <= 0.0 ) return 0.0; |
| 154 | 356 | hL = hWr / roadWidth; | |
| 155 |
1/2✓ Branch 0 taken 356 times.
✗ Branch 1 not taken.
|
356 | if ( hL <= 0.15 ) |
| 156 | { | ||
| 157 |
2/2✓ Branch 0 taken 178 times.
✓ Branch 1 taken 178 times.
|
356 | if ( roadSurf == PAVED ) cR = getY(hWr, Cr_Low_Paved, N_Cr_Low_Paved); |
| 158 | 178 | 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 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 356 times.
|
356 | 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 | 356 | return cR * kT; | |
| 172 | } | ||
| 173 | |||
| 174 | //============================================================================= | ||
| 175 | |||
| 176 | 356 | double getY(double x, const double table[][2], const int n) | |
| 177 | { | ||
| 178 | int i; | ||
| 179 | double x1, y1,dx, dy; | ||
| 180 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 356 times.
|
356 | if ( x <= table[0][0] ) return table[0][1]; |
| 181 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 356 times.
|
356 | if ( x >= table[n-1][0] ) return table[n-1][1]; |
| 182 |
1/2✓ Branch 0 taken 356 times.
✗ Branch 1 not taken.
|
356 | for (i = 1; i < n; i++) |
| 183 | { | ||
| 184 |
1/2✓ Branch 0 taken 356 times.
✗ Branch 1 not taken.
|
356 | if ( x <= table[i][0] ) |
| 185 | { | ||
| 186 | 356 | x1 = table[i-1][0]; | |
| 187 | 356 | dx = table[i][0] - x1; | |
| 188 | 356 | y1 = table[i-1][1]; | |
| 189 | 356 | dy = table[i][1] - y1; | |
| 190 | 356 | return y1 + (x - x1) * dy / dx; | |
| 191 | } | ||
| 192 | } | ||
| 193 | ✗ | return table[n-1][1]; | |
| 194 | } | ||
| 195 |