GCC Code Coverage Report


Directory: src/solver/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 87.5% 349 / 0 / 399
Functions: 77.8% 14 / 0 / 18
Branches: 79.6% 156 / 0 / 196

output.c
Line Branch Exec Source
1 //-----------------------------------------------------------------------------
2 // output.c
3 //
4 // Project: EPA SWMM5
5 // Version: 5.2
6 // Date: 06/01/22 (Build 5.2.1)
7 // Author: L. Rossman
8 //
9 // Binary output file access functions.
10 //
11 // Update History
12 // ==============
13 // Build 5.1.008:
14 // - Possible divide by zero for reported system wide variables avoided.
15 // - Updating of maximum node depth at reporting times added.
16 // Build 5.1.010:
17 // - Potentional ET added to list of system-wide variables saved to file.
18 // Build 5.1.013:
19 // - Names NsubcatchVars, NnodeVars & NlinkVars replaced with
20 // NumSubcatchVars, NumNodeVars & NumLinkVars
21 // - Support added for saving average node & link routing results to
22 // binary file in each reporting period.
23 // Build 5.1.014:
24 // - Incorrect loop limit fixed in function output_saveAvgResults.
25 // Build 5.2.0:
26 // - Changed how time step averaged flow is computed.
27 // - Object's rptFlag changed to record its index in output file.
28 // - Large file support added.
29 // Build5.2.1:
30 // - Corrects the definition of F_OFF for non-Microsoft C/C++ compilers.
31 //-----------------------------------------------------------------------------
32 #define _CRT_SECURE_NO_DEPRECATE
33
34 // Large File Support
35 #ifdef _MSC_VER // Windows (32-bit and 64-bit)
36 #define F_OFF __int64
37 #define F_SEEK _fseeki64
38 #else // Other platforms
39 #define F_OFF off_t
40 #define F_SEEK fseeko
41 #endif
42
43 #include <stdlib.h>
44 #include <string.h>
45 #include <math.h>
46 #include "headers.h"
47
48 // Definition of 4-byte integer, 4-byte real and 8-byte real types
49 #define INT4 int
50 #define REAL4 float
51 #define REAL8 double
52
53 enum InputDataType {INPUT_TYPE_CODE, INPUT_AREA, INPUT_INVERT, INPUT_MAX_DEPTH,
54 INPUT_OFFSET, INPUT_LENGTH};
55
56 typedef struct
57 {
58 REAL4* xAvg;
59 } TAvgResults;
60
61 //-----------------------------------------------------------------------------
62 // Shared variables
63 //-----------------------------------------------------------------------------
64 static F_OFF IDStartPos; // starting file position of ID names
65 static F_OFF InputStartPos; // starting file position of input data
66 static F_OFF OutputStartPos; // starting file position of output data
67 static F_OFF BytesPerPeriod; // bytes saved per simulation time period
68 static INT4 NumSubcatchVars; // number of subcatchment output variables
69 static INT4 NumNodeVars; // number of node output variables
70 static INT4 NumLinkVars; // number of link output variables
71 static INT4 NumSubcatch; // number of subcatchments reported on
72 static INT4 NumNodes; // number of nodes reported on
73 static INT4 NumLinks; // number of links reported on
74 static INT4 NumPolluts; // number of pollutants reported on
75
76 static REAL4 SysResults[MAX_SYS_RESULTS]; // values of system output vars.
77
78 static TAvgResults* AvgLinkResults;
79 static TAvgResults* AvgNodeResults;
80 static int Nsteps;
81
82 //-----------------------------------------------------------------------------
83 // Exportable variables (shared with report.c)
84 //-----------------------------------------------------------------------------
85 REAL4* SubcatchResults;
86 REAL4* NodeResults;
87 REAL4* LinkResults;
88
89
90 //-----------------------------------------------------------------------------
91 // Local functions
92 //-----------------------------------------------------------------------------
93 static void output_openOutFile(void);
94 static void output_saveID(char* id, FILE* file);
95 static void output_saveSubcatchResults(double reportTime, FILE* file);
96 static void output_saveNodeResults(double reportTime, FILE* file);
97 static void output_saveLinkResults(double reportTime, FILE* file);
98
99 static int output_openAvgResults(void);
100 static void output_closeAvgResults(void);
101 static void output_initAvgResults(void);
102 static void output_saveAvgResults(FILE* file);
103
104 //-----------------------------------------------------------------------------
105 // External functions (declared in funcs.h)
106 //-----------------------------------------------------------------------------
107 // output_open (called by swmm_start in swmm5.c)
108 // output_end (called by swmm_end in swmm5.c)
109 // output_close (called by swmm_close in swmm5.c)
110 // output_updateAvgResults (called by swmm_step in swmm5.c)
111 // output_saveResults (called by swmm_step in swmm5.c)
112 // output_checkFileSize (called by swmm_report)
113 // output_readDateTime (called by routines in report.c)
114 // output_readSubcatchResults (called by report_Subcatchments)
115 // output_readNodeResults (called by report_Nodes)
116 // output_readLinkResults (called by report_Links)
117
118
119 //=============================================================================
120
121 61 int output_open()
122 //
123 // Input: none
124 // Output: returns an error code
125 // Purpose: writes basic project data to binary output file.
126 //
127 {
128 int j;
129 int m;
130 INT4 k;
131 REAL4 x;
132 REAL8 z;
133 F_OFF numResults;
134
135 // --- open binary output file
136 61 output_openOutFile();
137
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
61 if ( ErrorCode ) return ErrorCode;
138
139 // --- ignore pollutants if no water quality analsis performed
140
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 58 times.
61 if ( IgnoreQuality ) NumPolluts = 0;
141 58 else NumPolluts = Nobjects[POLLUT];
142
143 // --- subcatchment results consist of Rainfall, Snowdepth, Evap,
144 // Infil, Runoff, GW Flow, GW Elev, GW Sat, and Washoff
145 61 NumSubcatchVars = MAX_SUBCATCH_RESULTS - 1 + NumPolluts;
146
147 // --- node results consist of Depth, Head, Volume, Lateral Inflow,
148 // Total Inflow, Overflow and Quality
149 61 NumNodeVars = MAX_NODE_RESULTS - 1 + NumPolluts;
150
151 // --- link results consist of Depth, Flow, Velocity, Volume,
152 // Capacity and Quality
153 61 NumLinkVars = MAX_LINK_RESULTS - 1 + NumPolluts;
154
155 // --- get number of objects reported on
156 61 NumSubcatch = 0;
157 61 NumNodes = 0;
158 61 NumLinks = 0;
159
3/4
✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 96 times.
✓ Branch 3 taken 61 times.
157 for (j=0; j<Nobjects[SUBCATCH]; j++) if (Subcatch[j].rptFlag) NumSubcatch++;
160
3/4
✓ Branch 0 taken 423 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 423 times.
✓ Branch 3 taken 61 times.
484 for (j=0; j<Nobjects[NODE]; j++) if (Node[j].rptFlag) NumNodes++;
161
3/4
✓ Branch 0 taken 332 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 332 times.
✓ Branch 3 taken 61 times.
393 for (j=0; j<Nobjects[LINK]; j++) if (Link[j].rptFlag) NumLinks++;
162
163 // --- find size of results saved in each time period
164 61 numResults = ((F_OFF)NumSubcatch * (F_OFF)NumSubcatchVars)
165 61 + ((F_OFF)NumNodes * (F_OFF)NumNodeVars)
166 61 + ((F_OFF)NumLinks * (F_OFF)NumLinkVars) + MAX_SYS_RESULTS;
167 61 BytesPerPeriod = sizeof(REAL8) + (numResults * sizeof(REAL4));
168 61 Nperiods = 0;
169
170 61 SubcatchResults = NULL;
171 61 NodeResults = NULL;
172 61 LinkResults = NULL;
173 61 SubcatchResults = (REAL4 *) calloc(NumSubcatchVars, sizeof(REAL4));
174 61 NodeResults = (REAL4 *) calloc(NumNodeVars, sizeof(REAL4));
175 61 LinkResults = (REAL4 *) calloc(NumLinkVars, sizeof(REAL4));
176
3/6
✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 61 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 61 times.
61 if ( !SubcatchResults || !NodeResults || !LinkResults )
177 {
178 report_writeErrorMsg(ERR_MEMORY, "");
179 return ErrorCode;
180 }
181
182 // --- allocate memory to store average node & link results per period
183 61 AvgNodeResults = NULL;
184 61 AvgLinkResults = NULL;
185
3/4
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 60 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
61 if ( RptFlags.averages && !output_openAvgResults() )
186 {
187 report_writeErrorMsg(ERR_MEMORY, "");
188 return ErrorCode;
189 }
190
191 61 F_SEEK(Fout.file, 0, SEEK_SET);
192 61 k = MAGICNUMBER;
193 61 fwrite(&k, sizeof(INT4), 1, Fout.file); // Magic number
194 61 k = VERSION;
195 61 fwrite(&k, sizeof(INT4), 1, Fout.file); // Version number
196 61 k = FlowUnits;
197 61 fwrite(&k, sizeof(INT4), 1, Fout.file); // Flow units
198 61 k = NumSubcatch;
199 61 fwrite(&k, sizeof(INT4), 1, Fout.file); // # subcatchments
200 61 k = NumNodes;
201 61 fwrite(&k, sizeof(INT4), 1, Fout.file); // # nodes
202 61 k = NumLinks;
203 61 fwrite(&k, sizeof(INT4), 1, Fout.file); // # links
204 61 k = NumPolluts;
205 61 fwrite(&k, sizeof(INT4), 1, Fout.file); // # pollutants
206
207 // --- save ID names of subcatchments, nodes, links, & pollutants
208 61 IDStartPos = ftell(Fout.file);
209
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 61 times.
157 for (j=0; j<Nobjects[SUBCATCH]; j++)
210 {
211
1/2
✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
96 if ( Subcatch[j].rptFlag ) output_saveID(Subcatch[j].ID, Fout.file);
212 }
213
2/2
✓ Branch 0 taken 423 times.
✓ Branch 1 taken 61 times.
484 for (j=0; j<Nobjects[NODE]; j++)
214 {
215
1/2
✓ Branch 0 taken 423 times.
✗ Branch 1 not taken.
423 if ( Node[j].rptFlag ) output_saveID(Node[j].ID, Fout.file);
216 }
217
2/2
✓ Branch 0 taken 332 times.
✓ Branch 1 taken 61 times.
393 for (j=0; j<Nobjects[LINK]; j++)
218 {
219
1/2
✓ Branch 0 taken 332 times.
✗ Branch 1 not taken.
332 if ( Link[j].rptFlag ) output_saveID(Link[j].ID, Fout.file);
220 }
221
2/2
✓ Branch 1 taken 19 times.
✓ Branch 2 taken 61 times.
80 for (j=0; j<NumPolluts; j++) output_saveID(Pollut[j].ID, Fout.file);
222
223 // --- save codes of pollutant concentration units
224
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 61 times.
80 for (j=0; j<NumPolluts; j++)
225 {
226 19 k = Pollut[j].units;
227 19 fwrite(&k, sizeof(INT4), 1, Fout.file);
228 }
229
230 61 InputStartPos = ftell(Fout.file);
231
232 // --- save subcatchment area
233 61 k = 1;
234 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
235 61 k = INPUT_AREA;
236 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
237
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 61 times.
157 for (j=0; j<Nobjects[SUBCATCH]; j++)
238 {
239
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 96 times.
96 if ( !Subcatch[j].rptFlag ) continue;
240 96 SubcatchResults[0] = (REAL4)(Subcatch[j].area * UCF(LANDAREA));
241 96 fwrite(&SubcatchResults[0], sizeof(REAL4), 1, Fout.file);
242 }
243
244 // --- save node type, invert, & max. depth
245 61 k = 3;
246 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
247 61 k = INPUT_TYPE_CODE;
248 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
249 61 k = INPUT_INVERT;
250 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
251 61 k = INPUT_MAX_DEPTH;
252 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
253
2/2
✓ Branch 0 taken 423 times.
✓ Branch 1 taken 61 times.
484 for (j=0; j<Nobjects[NODE]; j++)
254 {
255
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 423 times.
423 if ( !Node[j].rptFlag ) continue;
256 423 k = Node[j].type;
257 423 NodeResults[0] = (REAL4)(Node[j].invertElev * UCF(LENGTH));
258 423 NodeResults[1] = (REAL4)(Node[j].fullDepth * UCF(LENGTH));
259 423 fwrite(&k, sizeof(INT4), 1, Fout.file);
260 423 fwrite(NodeResults, sizeof(REAL4), 2, Fout.file);
261 }
262
263 // --- save link type, offsets, max. depth, & length
264 61 k = 5;
265 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
266 61 k = INPUT_TYPE_CODE;
267 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
268 61 k = INPUT_OFFSET;
269 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
270 61 k = INPUT_OFFSET;
271 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
272 61 k = INPUT_MAX_DEPTH;
273 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
274 61 k = INPUT_LENGTH;
275 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
276
277
2/2
✓ Branch 0 taken 332 times.
✓ Branch 1 taken 61 times.
393 for (j=0; j<Nobjects[LINK]; j++)
278 {
279
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 332 times.
332 if ( !Link[j].rptFlag ) continue;
280 332 k = Link[j].type;
281
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 323 times.
332 if ( k == PUMP )
282 {
283
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 9 times.
45 for (m=0; m<4; m++) LinkResults[m] = 0.0f;
284 }
285 else
286 {
287 323 LinkResults[0] = (REAL4)(Link[j].offset1 * UCF(LENGTH));
288 323 LinkResults[1] = (REAL4)(Link[j].offset2 * UCF(LENGTH));
289
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 308 times.
323 if ( Link[j].direction < 0 )
290 {
291 15 x = LinkResults[0];
292 15 LinkResults[0] = LinkResults[1];
293 15 LinkResults[1] = x;
294 }
295
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 317 times.
323 if ( k == OUTLET ) LinkResults[2] = 0.0f;
296 317 else LinkResults[2] = (REAL4)(Link[j].xsect.yFull * UCF(LENGTH));
297
2/2
✓ Branch 0 taken 299 times.
✓ Branch 1 taken 24 times.
323 if ( k == CONDUIT )
298 {
299 299 m = Link[j].subIndex;
300 299 LinkResults[3] = (REAL4)(Conduit[m].length * UCF(LENGTH));
301 }
302 24 else LinkResults[3] = 0.0f;
303 }
304 332 fwrite(&k, sizeof(INT4), 1, Fout.file);
305 332 fwrite(LinkResults, sizeof(REAL4), 4, Fout.file);
306 }
307
308 // --- save number & codes of subcatchment result variables
309 61 k = NumSubcatchVars;
310 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
311 61 k = SUBCATCH_RAINFALL;
312 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
313 61 k = SUBCATCH_SNOWDEPTH;
314 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
315 61 k = SUBCATCH_EVAP;
316 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
317 61 k = SUBCATCH_INFIL;
318 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
319 61 k = SUBCATCH_RUNOFF;
320 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
321 61 k = SUBCATCH_GW_FLOW;
322 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
323 61 k = SUBCATCH_GW_ELEV;
324 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
325 61 k = SUBCATCH_SOIL_MOIST;
326 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
327
328
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 61 times.
80 for (j=0; j<NumPolluts; j++)
329 {
330 19 k = SUBCATCH_WASHOFF + j;
331 19 fwrite(&k, sizeof(INT4), 1, Fout.file);
332 }
333
334 // --- save number & codes of node result variables
335 61 k = NumNodeVars;
336 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
337 61 k = NODE_DEPTH;
338 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
339 61 k = NODE_HEAD;
340 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
341 61 k = NODE_VOLUME;
342 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
343 61 k = NODE_LATFLOW;
344 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
345 61 k = NODE_INFLOW;
346 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
347 61 k = NODE_OVERFLOW;
348 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
349
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 61 times.
80 for (j=0; j<NumPolluts; j++)
350 {
351 19 k = NODE_QUAL + j;
352 19 fwrite(&k, sizeof(INT4), 1, Fout.file);
353 }
354
355 // --- save number & codes of link result variables
356 61 k = NumLinkVars;
357 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
358 61 k = LINK_FLOW;
359 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
360 61 k = LINK_DEPTH;
361 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
362 61 k = LINK_VELOCITY;
363 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
364 61 k = LINK_VOLUME;
365 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
366 61 k = LINK_CAPACITY;
367 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
368
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 61 times.
80 for (j=0; j<NumPolluts; j++)
369 {
370 19 k = LINK_QUAL + j;
371 19 fwrite(&k, sizeof(INT4), 1, Fout.file);
372 }
373
374 // --- save number & codes of system result variables
375 61 k = MAX_SYS_RESULTS;
376 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
377
2/2
✓ Branch 1 taken 915 times.
✓ Branch 2 taken 61 times.
976 for (k=0; k<MAX_SYS_RESULTS; k++) fwrite(&k, sizeof(INT4), 1, Fout.file);
378
379 // --- save starting report date & report step
380 // (if reporting start date > simulation start date then
381 // make saved starting report date one reporting period
382 // prior to the date of the first reported result)
383 61 z = (double)ReportStep/86400.0;
384
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 1 time.
61 if ( StartDateTime + z > ReportStart ) z = StartDateTime;
385 else
386 {
387 1 z = floor((ReportStart - StartDateTime)/z) - 1.0;
388 1 z = StartDateTime + z*(double)ReportStep/86400.0;
389 }
390 61 fwrite(&z, sizeof(REAL8), 1, Fout.file);
391 61 k = ReportStep;
392
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 61 times.
61 if ( fwrite(&k, sizeof(INT4), 1, Fout.file) < 1)
393 {
394 report_writeErrorMsg(ERR_OUT_WRITE, "");
395 return ErrorCode;
396 }
397 61 OutputStartPos = ftell(Fout.file);
398 61 return ErrorCode;
399 }
400
401 //=============================================================================
402 /* DEPRECATED
403 void output_checkFileSize()
404 //
405 // Input: none
406 // Output: none
407 // Purpose: checks if the size of the binary output file will be too big
408 // to access using a file pointer variable for a 32-bit compile.
409 //
410 {
411 if ( RptFlags.subcatchments != NONE ||
412 RptFlags.nodes != NONE ||
413 RptFlags.links != NONE )
414 {
415 if (sizeof(void*) == 4 &&
416 (double)OutputStartPos + (double)BytesPerPeriod * TotalDuration
417 / 1000.0 / (double)ReportStep >= (double)MAXFILESIZE )
418 {
419 report_writeErrorMsg(ERR_OUT_SIZE, "");
420 }
421 }
422 }
423 */
424
425 //=============================================================================
426
427 61 void output_openOutFile()
428 //
429 // Input: none
430 // Output: none
431 // Purpose: opens a project's binary output file.
432 //
433 {
434 // --- close output file if already opened
435
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
61 if (Fout.file != NULL) fclose(Fout.file);
436
437 // --- else if file name supplied then set file mode to SAVE
438
1/2
✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
61 else if (strlen(Fout.name) != 0) Fout.mode = SAVE_FILE;
439
440 // --- otherwise set file mode to SCRATCH & generate a name
441 else
442 {
443 Fout.mode = SCRATCH_FILE;
444 getTempFileName(Fout.name);
445 }
446
447 // --- try to open the file
448
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 61 times.
61 if ( (Fout.file = fopen(Fout.name, "w+b")) == NULL)
449 {
450 writecon(FMT14);
451 ErrorCode = ERR_OUT_FILE;
452 }
453 61 }
454
455 //=============================================================================
456
457 80799 void output_saveResults(double reportTime)
458 //
459 // Input: reportTime = elapsed simulation time (millisec)
460 // Output: none
461 // Purpose: writes computed results for current report time to binary file.
462 //
463 {
464 int i;
465 extern TRoutingTotals StepFlowTotals; // defined in massbal.c
466 80799 DateTime reportDate = getDateTime(reportTime);
467 REAL8 date;
468
469 // --- initialize system-wide results
470
2/2
✓ Branch 0 taken 1789 times.
✓ Branch 1 taken 79010 times.
80799 if ( reportDate < ReportStart ) return;
471
2/2
✓ Branch 0 taken 1185150 times.
✓ Branch 1 taken 79010 times.
1264160 for (i=0; i<MAX_SYS_RESULTS; i++) SysResults[i] = 0.0f;
472
473 // --- save date corresponding to this elapsed reporting time
474 79010 date = reportDate;
475 79010 fwrite(&date, sizeof(REAL8), 1, Fout.file);
476
477 // --- save subcatchment results
478
2/2
✓ Branch 0 taken 15682 times.
✓ Branch 1 taken 63328 times.
79010 if (Nobjects[SUBCATCH] > 0)
479 15682 output_saveSubcatchResults(reportTime, Fout.file);
480
481 // --- save average routing results over reporting period if called for
482
2/2
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 78963 times.
79010 if ( RptFlags.averages ) output_saveAvgResults(Fout.file);
483
484 // --- otherwise save interpolated point routing results
485 else
486 {
487
1/2
✓ Branch 0 taken 78963 times.
✗ Branch 1 not taken.
78963 if (Nobjects[NODE] > 0)
488 78963 output_saveNodeResults(reportTime, Fout.file);
489
2/2
✓ Branch 0 taken 76251 times.
✓ Branch 1 taken 2712 times.
78963 if (Nobjects[LINK] > 0)
490 76251 output_saveLinkResults(reportTime, Fout.file);
491 }
492
493 // --- update & save system-wide flows
494 79010 SysResults[SYS_FLOODING] = (REAL4)(StepFlowTotals.flooding * UCF(FLOW));
495 79010 SysResults[SYS_OUTFLOW] = (REAL4)(StepFlowTotals.outflow * UCF(FLOW));
496 79010 SysResults[SYS_DWFLOW] = (REAL4)(StepFlowTotals.dwInflow * UCF(FLOW));
497 79010 SysResults[SYS_GWFLOW] = (REAL4)(StepFlowTotals.gwInflow * UCF(FLOW));
498 79010 SysResults[SYS_IIFLOW] = (REAL4)(StepFlowTotals.iiInflow * UCF(FLOW));
499 79010 SysResults[SYS_EXFLOW] = (REAL4)(StepFlowTotals.exInflow * UCF(FLOW));
500 79010 SysResults[SYS_INFLOW] = SysResults[SYS_RUNOFF] +
501 79010 SysResults[SYS_DWFLOW] +
502 79010 SysResults[SYS_GWFLOW] +
503 79010 SysResults[SYS_IIFLOW] +
504 79010 SysResults[SYS_EXFLOW];
505 79010 fwrite(SysResults, sizeof(REAL4), MAX_SYS_RESULTS, Fout.file);
506
507 // --- save outfall flows to interface file if called for
508
3/4
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 78938 times.
✓ Branch 2 taken 72 times.
✗ Branch 3 not taken.
79010 if ( Foutflows.mode == SAVE_FILE && !IgnoreRouting )
509 72 iface_saveOutletResults(reportDate, Foutflows.file);
510 79010 Nperiods++;
511 }
512
513 //=============================================================================
514
515 61 void output_end()
516 //
517 // Input: none
518 // Output: none
519 // Purpose: writes closing records to binary file.
520 //
521 {
522 INT4 k;
523 61 fwrite(&IDStartPos, sizeof(INT4), 1, Fout.file);
524 61 fwrite(&InputStartPos, sizeof(INT4), 1, Fout.file);
525 61 fwrite(&OutputStartPos, sizeof(INT4), 1, Fout.file);
526 61 k = Nperiods;
527 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
528 61 k = (INT4)ErrorCode;
529 61 fwrite(&k, sizeof(INT4), 1, Fout.file);
530 61 k = MAGICNUMBER;
531
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 61 times.
61 if (fwrite(&k, sizeof(INT4), 1, Fout.file) < 1)
532 {
533 report_writeErrorMsg(ERR_OUT_WRITE, "");
534 }
535 61 }
536
537 //=============================================================================
538
539 61 void output_close()
540 //
541 // Input: none
542 // Output: none
543 // Purpose: frees memory used for accessing the binary file.
544 //
545 {
546
1/2
✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
61 FREE(SubcatchResults);
547
1/2
✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
61 FREE(NodeResults);
548
1/2
✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
61 FREE(LinkResults);
549 61 output_closeAvgResults();
550 61 }
551
552 //=============================================================================
553
554 870 void output_saveID(char* id, FILE* file)
555 //
556 // Input: id = name of an object
557 // file = ptr. to binary output file
558 // Output: none
559 // Purpose: writes an object's name to the binary output file.
560 //
561 {
562 870 INT4 n = (INT4)strlen(id);
563 870 fwrite(&n, sizeof(INT4), 1, file);
564 870 fwrite(id, sizeof(char), n, file);
565 870 }
566
567 //=============================================================================
568
569 15682 void output_saveSubcatchResults(double reportTime, FILE* file)
570 //
571 // Input: reportTime = elapsed simulation time (millisec)
572 // file = ptr. to binary output file
573 // Output: none
574 // Purpose: writes computed subcatchment results to binary file.
575 //
576 {
577 int j;
578 double f;
579 double area;
580 15682 REAL4 totalArea = 0.0f;
581 15682 DateTime reportDate = getDateTime(reportTime);
582
583 // --- update reported rainfall at each rain gage
584
2/2
✓ Branch 0 taken 15825 times.
✓ Branch 1 taken 15682 times.
31507 for ( j=0; j<Nobjects[GAGE]; j++ )
585 {
586 15825 gage_setReportRainfall(j, reportDate);
587 }
588
589 // --- find where current reporting time lies between latest runoff times
590 15682 f = (reportTime - OldRunoffTime) / (NewRunoffTime - OldRunoffTime);
591
592 // --- write subcatchment results to file
593
2/2
✓ Branch 0 taken 104318 times.
✓ Branch 1 taken 15682 times.
120000 for ( j=0; j<Nobjects[SUBCATCH]; j++)
594 {
595 // --- retrieve interpolated results for reporting time & write to file
596 104318 subcatch_getResults(j, f, SubcatchResults);
597
1/2
✓ Branch 0 taken 104318 times.
✗ Branch 1 not taken.
104318 if ( Subcatch[j].rptFlag )
598 104318 fwrite(SubcatchResults, sizeof(REAL4), NumSubcatchVars, file);
599
600 // --- update system-wide results
601 104318 area = Subcatch[j].area * UCF(LANDAREA);
602 104318 totalArea += (REAL4)area;
603 104318 SysResults[SYS_RAINFALL] +=
604 104318 (REAL4)(SubcatchResults[SUBCATCH_RAINFALL] * area);
605 104318 SysResults[SYS_SNOWDEPTH] +=
606 104318 (REAL4)(SubcatchResults[SUBCATCH_SNOWDEPTH] * area);
607 104318 SysResults[SYS_EVAP] +=
608 104318 (REAL4)(SubcatchResults[SUBCATCH_EVAP] * area);
609
2/2
✓ Branch 0 taken 2928 times.
✓ Branch 1 taken 101390 times.
104318 if ( Subcatch[j].groundwater ) SysResults[SYS_EVAP] +=
610 2928 (REAL4)(Subcatch[j].groundwater->evapLoss * UCF(EVAPRATE) * area);
611 104318 SysResults[SYS_INFIL] +=
612 104318 (REAL4)(SubcatchResults[SUBCATCH_INFIL] * area);
613 104318 SysResults[SYS_RUNOFF] += (REAL4)SubcatchResults[SUBCATCH_RUNOFF];
614 }
615
616 // --- normalize system-wide results to catchment area
617
1/2
✓ Branch 0 taken 15682 times.
✗ Branch 1 not taken.
15682 if ( totalArea > 0.0 )
618 {
619 15682 SysResults[SYS_EVAP] /= totalArea;
620 15682 SysResults[SYS_RAINFALL] /= totalArea;
621 15682 SysResults[SYS_SNOWDEPTH] /= totalArea;
622 15682 SysResults[SYS_INFIL] /= totalArea;
623 }
624
625 // --- update system temperature and PET
626
2/2
✓ Branch 0 taken 576 times.
✓ Branch 1 taken 15106 times.
15682 if ( UnitSystem == SI ) f = (5./9.) * (Temp.ta - 32.0);
627 15106 else f = Temp.ta;
628 15682 SysResults[SYS_TEMPERATURE] = (REAL4)f;
629 15682 f = Evap.rate * UCF(EVAPRATE);
630 15682 SysResults[SYS_PET] = (REAL4)f;
631
632 15682 }
633
634 //=============================================================================
635
636 78963 void output_saveNodeResults(double reportTime, FILE* file)
637 //
638 // Input: reportTime = elapsed simulation time (millisec)
639 // file = ptr. to binary output file
640 // Output: none
641 // Purpose: writes computed node results to binary file.
642 //
643 {
644 int j;
645
646 // --- find where current reporting time lies between latest routing times
647 78963 double f = (reportTime - OldRoutingTime) /
648 78963 (NewRoutingTime - OldRoutingTime);
649
650 // --- write node results to file
651
2/2
✓ Branch 0 taken 1583984 times.
✓ Branch 1 taken 78963 times.
1662947 for (j=0; j<Nobjects[NODE]; j++)
652 {
653 // --- retrieve interpolated results for reporting time & write to file
654 1583984 node_getResults(j, f, NodeResults);
655
1/2
✓ Branch 0 taken 1583984 times.
✗ Branch 1 not taken.
1583984 if ( Node[j].rptFlag )
656 1583984 fwrite(NodeResults, sizeof(REAL4), NumNodeVars, file);
657 1583984 stats_updateMaxNodeDepth(j, NodeResults[NODE_DEPTH]);
658
659 // --- update system-wide storage volume
660 1583984 SysResults[SYS_STORAGE] += NodeResults[NODE_VOLUME];
661 }
662 78963 }
663
664 //=============================================================================
665
666 76251 void output_saveLinkResults(double reportTime, FILE* file)
667 //
668 // Input: reportTime = elapsed simulation time (millisec)
669 // file = ptr. to binary output file
670 // Output: none
671 // Purpose: writes computed link results to binary file.
672 //
673 {
674 int j;
675 double f;
676 double z;
677
678 // --- find where current reporting time lies between latest routing times
679 76251 f = (reportTime - OldRoutingTime) / (NewRoutingTime - OldRoutingTime);
680
681 // --- write link results to file
682
2/2
✓ Branch 0 taken 1500102 times.
✓ Branch 1 taken 76251 times.
1576353 for (j=0; j<Nobjects[LINK]; j++)
683 {
684 // --- retrieve interpolated results for reporting time & write to file
685
1/2
✓ Branch 0 taken 1500102 times.
✗ Branch 1 not taken.
1500102 if (Link[j].rptFlag )
686 {
687 1500102 link_getResults(j, f, LinkResults);
688 1500102 fwrite(LinkResults, sizeof(REAL4), NumLinkVars, file);
689 }
690
691 // --- update system-wide results
692 1500102 z = ((1.0-f)*Link[j].oldVolume + f*Link[j].newVolume) * UCF(VOLUME);
693 1500102 SysResults[SYS_STORAGE] += (REAL4)z;
694 }
695 76251 }
696
697 //=============================================================================
698
699 void output_readDateTime(long period, DateTime* days)
700 //
701 // Input: period = index of reporting time period
702 // Output: days = date/time value
703 // Purpose: retrieves the date/time for a specific reporting period
704 // from the binary output file.
705 //
706 {
707 F_OFF p = period;
708 F_OFF bytePos = OutputStartPos + (p-1)*BytesPerPeriod;
709 F_SEEK(Fout.file, bytePos, SEEK_SET);
710 *days = NO_DATE;
711 fread(days, sizeof(REAL8), 1, Fout.file);
712 }
713
714 //=============================================================================
715
716 void output_readSubcatchResults(long period, int index)
717 //
718 // Input: period = index of reporting time period
719 // index = subcatchment index in binary output file
720 // Output: none
721 // Purpose: reads computed results for a subcatchment at a specific time
722 // period.
723 //
724 {
725 long offset = index*NumSubcatchVars;
726 F_OFF p = period;
727 F_OFF bytePos = OutputStartPos + (p-1)*BytesPerPeriod +
728 sizeof(REAL8) + (F_OFF)offset * sizeof(REAL4);
729 F_SEEK(Fout.file, bytePos, SEEK_SET);
730 fread(SubcatchResults, sizeof(REAL4), NumSubcatchVars, Fout.file);
731 }
732
733 //=============================================================================
734
735 void output_readNodeResults(long period, int index)
736 //
737 // Input: period = index of reporting time period
738 // index = node index in binary output file
739 // Output: none
740 // Purpose: reads computed results for a node at a specific time period.
741 //
742 {
743 long offset = NumSubcatch*NumSubcatchVars + index*NumNodeVars;
744 F_OFF p = period;
745 F_OFF bytePos = OutputStartPos + (p-1)*BytesPerPeriod +
746 sizeof(REAL8) + (F_OFF)offset * sizeof(REAL4);
747 F_SEEK(Fout.file, bytePos, SEEK_SET);
748 fread(NodeResults, sizeof(REAL4), NumNodeVars, Fout.file);
749 }
750
751 //=============================================================================
752
753 void output_readLinkResults(long period, int index)
754 //
755 // Input: period = index of reporting time period
756 // index = link index in binary output file
757 // Output: none
758 // Purpose: reads computed results for a link at a specific time period.
759 //
760 {
761 long offset = (NumSubcatch*NumSubcatchVars + NumNodes*NumNodeVars + index*NumLinkVars);
762 F_OFF p = period;
763 F_OFF bytePos = OutputStartPos + (p-1)*BytesPerPeriod +
764 sizeof(REAL8) + (F_OFF)offset * sizeof(REAL4);
765 F_SEEK(Fout.file, bytePos, SEEK_SET);
766 fread(LinkResults, sizeof(REAL4), NumLinkVars, Fout.file);
767 fread(SysResults, sizeof(REAL4), MAX_SYS_RESULTS, Fout.file);
768 }
769
770 //=============================================================================
771 // Functions for saving average results within a reporting period to file.
772 //=============================================================================
773
774 1 int output_openAvgResults()
775 //
776 // Allocates memory for storing average results for nodes and links.
777 {
778 int i;
779
780 // --- allocate memory for averages at reportable nodes
781 1 AvgNodeResults = (TAvgResults *)calloc(NumNodes, sizeof(TAvgResults));
782
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if ( AvgNodeResults == NULL ) return FALSE;
783
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
3 for (i = 0; i < NumNodes; i++ ) AvgNodeResults[i].xAvg = NULL;
784
785 // --- allocate memory for averages at reportable links
786 1 AvgLinkResults = (TAvgResults *)calloc(NumLinks, sizeof(TAvgResults));
787
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (AvgLinkResults == NULL)
788 {
789 output_closeAvgResults();
790 return FALSE;
791 }
792
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 for (i = 0; i < NumLinks; i++) AvgLinkResults[i].xAvg = NULL;
793
794 // --- allocate memory for each reportable variable for each reportable node
795
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
3 for (i = 0; i < NumNodes; i++)
796 {
797 2 AvgNodeResults[i].xAvg = (REAL4*) calloc(NumNodeVars, sizeof(REAL4));
798
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (AvgNodeResults[i].xAvg == NULL)
799 {
800 output_closeAvgResults();
801 return FALSE;
802 }
803 }
804
805 // --- allocate memory for each reportable variable for each reportable link
806
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 for (i = 0; i < NumLinks; i++)
807 {
808 1 AvgLinkResults[i].xAvg = (REAL4*)calloc(NumLinkVars, sizeof(REAL4));
809
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if (AvgLinkResults[i].xAvg == NULL)
810 {
811 output_closeAvgResults();
812 return FALSE;
813 }
814 }
815 1 return TRUE;
816 }
817
818 //=============================================================================
819
820 61 void output_closeAvgResults()
821 //
822 // Frees memory used for storing average results for nodes and links.
823 {
824 int i;
825
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 60 times.
61 if (AvgNodeResults)
826 {
827
3/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 time.
3 for (i = 0; i < NumNodes; i++) FREE(AvgNodeResults[i].xAvg);
828
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 FREE(AvgNodeResults);
829 }
830
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 60 times.
61 if (AvgLinkResults)
831 {
832
3/4
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1 time.
2 for (i = 0; i < NumLinks; i++) FREE(AvgLinkResults[i].xAvg);
833
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 FREE(AvgLinkResults);
834 }
835 61 }
836
837 //=============================================================================
838
839 47 void output_initAvgResults()
840 //
841 // Initializes average node & link results.
842 {
843 int i, j;
844 47 Nsteps = 0;
845
2/2
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 47 times.
141 for (i = 0; i < NumNodes; i++)
846 {
847
2/2
✓ Branch 0 taken 564 times.
✓ Branch 1 taken 94 times.
658 for (j = 0; j < NumNodeVars; j++) AvgNodeResults[i].xAvg[j] = 0.0;
848 }
849
2/2
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 47 times.
94 for (i = 0; i < NumLinks; i++)
850 {
851
2/2
✓ Branch 0 taken 235 times.
✓ Branch 1 taken 47 times.
282 for (j = 0; j < NumLinkVars; j++) AvgLinkResults[i].xAvg[j] = 0.0;
852 }
853 47 }
854
855 //=============================================================================
856
857 481 void output_updateAvgResults()
858 {
859 int i, j, k, sign;
860
861 // --- update average accumulations for nodes
862 481 k = 0;
863
2/2
✓ Branch 0 taken 962 times.
✓ Branch 1 taken 481 times.
1443 for (i = 0; i < Nobjects[NODE]; i++)
864 {
865
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 962 times.
962 if ( !Node[i].rptFlag ) continue;
866 962 node_getResults(i, 1.0, NodeResults);
867
2/2
✓ Branch 0 taken 5772 times.
✓ Branch 1 taken 962 times.
6734 for (j = 0; j < NumNodeVars; j++)
868 {
869 5772 AvgNodeResults[k].xAvg[j] += NodeResults[j];
870 }
871 962 k++;
872 }
873
874 // --- update average accumulations for links
875 481 k = 0;
876
2/2
✓ Branch 0 taken 481 times.
✓ Branch 1 taken 481 times.
962 for (i = 0; i < Nobjects[LINK]; i++)
877 {
878
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 481 times.
481 if ( !Link[i].rptFlag ) continue;
879 481 link_getResults(i, 1.0, LinkResults);
880
881 // --- save sign of current flow rate
882
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 481 times.
481 sign = SGN(LinkResults[LINK_FLOW]);
883
884 // --- add current results to average accumulation
885
2/2
✓ Branch 0 taken 2405 times.
✓ Branch 1 taken 481 times.
2886 for (j = 0; j < NumLinkVars; j++)
886 {
887
2/2
✓ Branch 0 taken 481 times.
✓ Branch 1 taken 1924 times.
2405 if (j == LINK_CAPACITY)
888 {
889 // --- accumulate capacity (fraction full) for conduits
890
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 481 times.
481 if ( Link[i].type == CONDUIT )
891 AvgLinkResults[k].xAvg[j] += LinkResults[j];
892
893 // --- for other links capacity is pump speed or regulator
894 // opening fraction which shouldn't be averaged
895 // (multiplying by Nsteps+1 will preserve last value
896 // when average results are taken in saveAvgResults())
897 else
898 481 AvgLinkResults[k].xAvg[j] = LinkResults[j] * (Nsteps+1);
899 }
900
901 // --- accumulation for all other reported results
902 1924 else AvgLinkResults[k].xAvg[j] += LinkResults[j];
903 }
904 481 k++;
905 }
906 481 Nsteps++;
907 481 }
908
909 //=============================================================================
910
911 47 void output_saveAvgResults(FILE* file)
912 {
913 int i, j;
914
915 // --- examine each reportable node
916
2/2
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 47 times.
141 for (i = 0; i < NumNodes; i++)
917 {
918 // --- determine the node's average results
919
2/2
✓ Branch 0 taken 564 times.
✓ Branch 1 taken 94 times.
658 for (j = 0; j < NumNodeVars; j++)
920 {
921 564 NodeResults[j] = AvgNodeResults[i].xAvg[j] / Nsteps;
922 }
923
924 // --- save average results to file
925 94 fwrite(NodeResults, sizeof(REAL4), NumNodeVars, file);
926 }
927
928 // --- update each node's max depth and contribution to system storage
929
2/2
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 47 times.
141 for (i = 0; i < Nobjects[NODE]; i++)
930 {
931 94 stats_updateMaxNodeDepth(i, Node[i].newDepth * UCF(LENGTH));
932 94 SysResults[SYS_STORAGE] += (REAL4)(Node[i].newVolume * UCF(VOLUME));
933 }
934
935 // --- examine each reportable link
936
2/2
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 47 times.
94 for (i = 0; i < NumLinks; i++)
937 {
938 // --- determine the link's average results
939
2/2
✓ Branch 0 taken 235 times.
✓ Branch 1 taken 47 times.
282 for (j = 0; j < NumLinkVars; j++)
940 {
941 235 LinkResults[j] = AvgLinkResults[i].xAvg[j] / Nsteps;
942 }
943
944 // --- save average results to file
945 47 fwrite(LinkResults, sizeof(REAL4), NumLinkVars, file);
946 }
947
948 // --- add each link's volume to total system storage
949
2/2
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 47 times.
94 for (i = 0; i < Nobjects[LINK]; i++)
950 {
951 47 SysResults[SYS_STORAGE] += (REAL4)(Link[i].newVolume * UCF(VOLUME));
952 }
953
954 // --- re-initialize average results for all nodes and links
955 47 output_initAvgResults();
956 47 }
957