GCC Code Coverage Report


Directory: src/solver/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 80.2% 73 / 0 / 91
Functions: 100.0% 4 / 0 / 4
Branches: 55.8% 29 / 0 / 52

exfil.c
Line Branch Exec Source
1 //-----------------------------------------------------------------------------
2 // exfil.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 // Storage unit exfiltration functions.
10 //
11 // Update History
12 // ==============
13 // Build 5.1.008:
14 // - Monthly conductivity adjustment applied to exfiltration rate.
15 // Build 5.1.010:
16 // - New modified Green-Ampt infiltration option used.
17 // Build 5.1.011:
18 // - Fixed units conversion error for storage units with surface area curves.
19 // Build 5.2.0:
20 // - Support added for analytical storage shapes.
21 //-----------------------------------------------------------------------------
22 #define _CRT_SECURE_NO_DEPRECATE
23
24 #include <math.h>
25 #include <stdlib.h>
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 3 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
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 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
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 else if ( ntoks < n + 3 ) return error_setInpError(ERR_ITEMS, "");
59
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 3 times.
12 else for (i = 0; i < 3; i++)
60 {
61
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
9 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
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if ( x[1] == 0.0 ) return 0;
67
68 // --- create an exfiltration object
69 3 return createStorageExfil(k, x);
70 }
71
72 //=============================================================================
73
74 3 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 3 TExfil* exfil = Storage[k].exfil;
85
86 // --- initialize exfiltration object
87
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if ( exfil != NULL )
88 {
89 // --- initialize the Green-Ampt infil. parameters
90 3 grnampt_initState(exfil->btmExfil);
91 3 grnampt_initState(exfil->bankExfil);
92
93
2/4
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3 switch (Storage[k].shape)
94 {
95 // --- shape given by a Storage Curve
96 1 case TABULAR:
97 1 i = Storage[k].aCurve;
98 1 exfil->btmArea = 0.0;
99 1 exfil->bankMinDepth = 0.0;
100 1 exfil->bankMaxDepth = 0.0;
101 1 exfil->bankMaxArea = 0.0;
102
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if ( i >= 0 )
103 {
104 // --- get bottom area
105 1 aCurve = &Curve[i];
106 1 Storage[k].exfil->btmArea = table_lookupEx(aCurve, 0.0);
107
108 // --- find min/max bank depths and max. bank area
109 1 table_getFirstEntry(aCurve, &d, &a);
110 1 alast = a;
111
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1 time.
5 while ( table_getNextEntry(aCurve, &d, &a) )
112 {
113
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if ( a < alast ) break;
114
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 else if ( a > alast )
115 {
116 4 exfil->bankMaxArea = a;
117 4 exfil->bankMaxDepth = d;
118 }
119 else if ( exfil->bankMaxArea == 0.0 )
120 exfil->bankMinDepth = d;
121 else break;
122 4 alast = a;
123 }
124
125 // --- convert from user units to internal units
126 1 exfil->btmArea /= UCF(LENGTH) * UCF(LENGTH);
127 1 exfil->bankMaxArea /= UCF(LENGTH) * UCF(LENGTH);
128 1 exfil->bankMinDepth /= UCF(LENGTH);
129 1 exfil->bankMaxDepth /= UCF(LENGTH);
130 }
131 1 break;
132
133 // --- functional storage shape curve
134 2 case FUNCTIONAL:
135 2 exfil->btmArea = Storage[k].a0;
136
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if ( Storage[k].a2 == 0.0 )
137 2 exfil->btmArea +=Storage[k].a1;
138 2 exfil->bankMinDepth = 0.0;
139 2 exfil->bankMaxDepth = BIG;
140 2 exfil->bankMaxArea = BIG;
141 2 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 3 }
155
156 //=============================================================================
157
158 19083 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 19083 double exfilRate = 0.0;
170
171 // --- find infiltration through bottom of unit
172
2/2
✓ Branch 0 taken 1082 times.
✓ Branch 1 taken 18001 times.
19083 if ( exfil->btmExfil->IMDmax == 0.0 )
173 {
174 1082 exfilRate = exfil->btmExfil->Ks * Adjust.hydconFactor;
175 }
176 18001 else exfilRate = grnampt_getInfil(exfil->btmExfil, tStep, 0.0, depth,
177 MOD_GREEN_AMPT);
178 19083 exfilRate *= exfil->btmArea;
179
180 // --- find infiltration through sloped banks
181
2/2
✓ Branch 0 taken 19058 times.
✓ Branch 1 taken 25 times.
19083 if ( depth > exfil->bankMinDepth )
182 {
183 // --- get area of banks
184
1/2
✓ Branch 0 taken 19058 times.
✗ Branch 1 not taken.
19058 area = MIN(area, exfil->bankMaxArea) - exfil->btmArea;
185
2/2
✓ Branch 0 taken 18000 times.
✓ Branch 1 taken 1058 times.
19058 if ( area > 0.0 )
186 {
187 // --- if infil. rate not a function of depth
188
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18000 times.
18000 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
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18000 times.
18000 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 18000 else depth = (depth - exfil->bankMinDepth) / 2.0;
206
207 // --- use Green-Ampt function for bank infiltration
208 18000 exfilRate += area * grnampt_getInfil(exfil->bankExfil,
209 tStep, 0.0, depth, MOD_GREEN_AMPT);
210 }
211 }
212 }
213 19083 return exfilRate;
214 }
215
216 //=============================================================================
217
218 3 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 3 exfil = Storage[k].exfil;
232
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if ( exfil == NULL )
233 {
234 3 exfil = (TExfil *) malloc(sizeof(TExfil));
235
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if ( exfil == NULL ) return error_setInpError(ERR_MEMORY, "");
236 3 Storage[k].exfil = exfil;
237
238 // --- create Green-Ampt infiltration objects for the bottom & banks
239 3 exfil->btmExfil = NULL;
240 3 exfil->bankExfil = NULL;
241 3 exfil->btmExfil = (TGrnAmpt *) malloc(sizeof(TGrnAmpt));
242
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if ( exfil->btmExfil == NULL ) return error_setInpError(ERR_MEMORY, "");
243 3 exfil->bankExfil = (TGrnAmpt *) malloc(sizeof(TGrnAmpt));
244
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if ( exfil->bankExfil == NULL ) return error_setInpError(ERR_MEMORY, "");
245 }
246
247 // --- initialize the Green-Ampt parameters
248
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if ( !grnampt_setParams(exfil->btmExfil, x) )
249 return error_setInpError(ERR_NUMBER, "");
250 3 grnampt_setParams(exfil->bankExfil, x);
251 3 return 0;
252 }
253