GCC Code Coverage Report


Directory: src/solver/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 88.0% 103 / 0 / 117
Functions: 100.0% 8 / 0 / 8
Branches: 71.2% 47 / 0 / 66

shape.c
Line Branch Exec Source
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 <math.h>
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 31 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
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
31 if (!computeShapeTables(shape, curve)) {
52 return FALSE;
53 }
54
55
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
31 if (!normalizeShapeTables(shape)) {
56 return FALSE;
57 }
58
59 31 return TRUE;
60 }
61
62 //=============================================================================
63
64 31 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
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
31 if (!table_getFirstEntry(curve, &y1, &w1)) {
82 return FALSE;
83 }
84
85
3/6
✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 31 times.
31 if (y1 < 0.0 || y1 >= 1.0 || w1 < 0.0) {
86 return FALSE;
87 }
88
89 31 wMax = w1;
90
91 // --- if first entry not at zero ht. then add an initial entry
92
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 24 times.
31 if (y1 != 0.0) {
93 7 y2 = y1;
94 7 w2 = w1;
95 7 y1 = 0.0;
96 7 w1 = 0.0;
97 }
98 // --- otherwise get next entry in the user's shape curve
99 else {
100
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
24 if (!table_getNextEntry(curve, &y2, &w2)) {
101 return FALSE;
102 }
103
104
2/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
24 if (y2 < y1 || w2 < 0.0) {
105 return FALSE;
106 }
107
108
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 10 times.
24 if (y2 > 1.0) {
109 14 y2 = 1.0;
110 }
111
112
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 21 times.
24 if (w2 > wMax) {
113 3 wMax = w2;
114 }
115 }
116
117 // --- determine number of entries & interval size in geom. tables
118 31 shape->nTbl = N_SHAPE_TBL;
119 31 n = shape->nTbl - 1;
120 31 dy = 1.0 / (double)(n);
121
122 // --- initialize geometry tables
123 31 shape->areaTbl[0] = 0.0;
124 31 shape->hradTbl[0] = 0.0;
125 31 shape->widthTbl[0] = w1;
126 31 Ptotal = w1;
127 31 Atotal = 0.0;
128
129 // --- fill in rest of geometry tables
130 31 y = 0.0;
131 31 w = w1;
132
133
2/2
✓ Branch 0 taken 1550 times.
✓ Branch 1 taken 31 times.
1581 for (i = 1; i <= n; i++) {
134 // --- advance to next relative height level
135 1550 yLast = y;
136 1550 wLast = w;
137 1550 y = y + dy;
138
139 // --- do not allow height to exceed 1.0
140
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 1519 times.
1550 if (fabs(y - 1.0) < TINY) {
141 31 y = 1.0;
142 }
143
144 // --- if height exceeds current shape curve interval,
145 // move to next interval of shape curve
146
2/2
✓ Branch 0 taken 444 times.
✓ Branch 1 taken 1106 times.
1550 if (y > y2) {
147
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 444 times.
444 if (!getNextInterval(curve, y, yLast, wLast, &y1, &y2, &w1, &w2,
148 &wMax)) {
149 return FALSE;
150 }
151
152 444 yLast = y1;
153 444 wLast = w1;
154 }
155
156 // --- get top width, area, & perimeter of current interval
157 1550 w = getWidth(y, y1, y2, w1, w2);
158 1550 Atotal += getArea(y, w, yLast, wLast);
159 1550 Ptotal += getPerim(y, w, yLast, wLast);
160
161 // --- add top width to total perimeter if at top of shape
162
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 1519 times.
1550 if (y == 1.0) {
163 31 Ptotal += w2;
164 }
165
166 // --- update table values
167 1550 shape->widthTbl[i] = w;
168 1550 shape->areaTbl[i] = Atotal;
169
1/2
✓ Branch 0 taken 1550 times.
✗ Branch 1 not taken.
1550 if (Ptotal > 0.0) {
170 1550 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 31 shape->aFull = shape->areaTbl[n];
178 31 shape->rFull = shape->hradTbl[n];
179
180 // --- assign values to shape's max. width and section factor
181 31 shape->wMax = wMax;
182 31 getSmax(shape);
183
184 31 return TRUE;
185 }
186
187 //=============================================================================
188
189 31 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 31 int n = shape->nTbl - 1;
199 double sf;
200
201 31 shape->sMax = 0.0;
202 31 shape->aMax = 0.0;
203
204
2/2
✓ Branch 0 taken 1550 times.
✓ Branch 1 taken 31 times.
1581 for (i = 1; i <= n; i++) {
205 1550 sf = shape->areaTbl[i] * pow(shape->hradTbl[i], 2. / 3.);
206
207
2/2
✓ Branch 0 taken 1499 times.
✓ Branch 1 taken 51 times.
1550 if (sf > shape->sMax) {
208 1499 shape->sMax = sf;
209 1499 shape->aMax = shape->areaTbl[i];
210 }
211 }
212 31 }
213
214 //=============================================================================
215
216 31 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 31 int n = shape->nTbl - 1; // highest table entry index
225 31 double aFull = shape->aFull; // area when full
226 31 double rFull = shape->rFull; // hyd. radius when full
227 31 double wMax = shape->wMax; // max. width
228
229 // --- check that normalizing factors are non-zero
230
3/6
✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 31 times.
31 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
2/2
✓ Branch 0 taken 1581 times.
✓ Branch 1 taken 31 times.
1612 for (i = 0; i <= n; i++) {
236 1581 shape->areaTbl[i] /= aFull;
237 1581 shape->hradTbl[i] /= rFull;
238 1581 shape->widthTbl[i] /= wMax;
239 }
240
241 31 return TRUE;
242 }
243
244 //=============================================================================
245
246 444 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
2/2
✓ Branch 0 taken 637 times.
✓ Branch 1 taken 444 times.
1081 while (y > *y2) {
270 // --- move start of geom. table interval up to the end of
271 // the current curve table interval
272
2/2
✓ Branch 0 taken 615 times.
✓ Branch 1 taken 22 times.
637 if (*y2 > yLast) {
273 615 Atotal += getArea(*y2, *w2, yLast, wLast);
274 615 Ptotal += getPerim(*y2, *w2, yLast, wLast);
275 615 yLast = *y2;
276 615 wLast = *w2;
277 }
278
279 // --- move to the next curve table interval
280 637 *y1 = *y2;
281 637 *w1 = *w2;
282
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 637 times.
637 if (!table_getNextEntry(curve, y2, w2)) {
283 *y2 = 1.0;
284 return TRUE;
285 }
286
287 // --- update curve table's max. width
288
2/2
✓ Branch 0 taken 209 times.
✓ Branch 1 taken 428 times.
637 if (*w2 > *wMax) {
289 209 *wMax = *w2;
290 }
291
292 // --- check for valid curve table values
293
2/4
✓ Branch 0 taken 637 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 637 times.
637 if (*y2 < *y1 || *w2 < 0.0) {
294 return FALSE;
295 }
296
297
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 637 times.
637 if (*y2 > 1.0) {
298 *y2 = 1.0;
299 }
300 }
301
302 444 return TRUE;
303 }
304
305 //=============================================================================
306
307 1550 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
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1550 times.
1550 if (y2 == y1) {
320 return w2;
321 }
322
323 1550 return w1 + (y - y1) / (y2 - y1) * (w2 - w1);
324 }
325
326 //=============================================================================
327
328 2165 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
2/2
✓ Branch 0 taken 384 times.
✓ Branch 1 taken 1781 times.
2165 if (w > w1) {
341 384 wMin = w1;
342 384 wMax = w;
343 } else {
344 1781 wMin = w;
345 1781 wMax = w1;
346 }
347
348 2165 return (wMin + (wMax - wMin) / 2.0) * (y - y1);
349 }
350
351 //=============================================================================
352
353 2165 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 2165 double dy = y - y1;
366 2165 double dw = fabs(w - w1) / 2.0;
367
368 2165 return 2.0 * sqrt(dy * dy + dw * dw);
369 }
370