GCC Code Coverage Report


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