SWMM-Docs  5.2.0.dev5
Stormwater Management Model
swmm5.c
1 //-----------------------------------------------------------------------------
2 // swmm5.c
3 //
4 // Project: EPA SWMM5
5 // Version: 5.1
6 // Date: 03/19/14 (Build 5.1.001)
7 // 03/19/15 (Build 5.1.008)
8 // 08/01/16 (Build 5.1.011)
9 // 03/14/17 (Build 5.1.012)
10 // 05/10/18 (Build 5.1.013)
11 // Author: L. Rossman
12 //
13 // This is the main module of the computational engine for Version 5 of
14 // the U.S. Environmental Protection Agency's Storm Water Management Model
15 // (SWMM). It contains functions that control the flow of computations.
16 //
17 // This engine should be compiled into a shared object library whose API
18 // functions are listed in swmm5.h.
19 //
20 // Build 5.1.008:
21 // - Support added for the MinGW compiler.
22 // - Reporting of project options moved to swmm_start.
23 // - Hot start file now read before routing system opened.
24 // - Final routing step adjusted so that total duration not exceeded.
25 //
26 // Build 5.1.011:
27 // - Made sure that MS exception handling only used with MS C compiler.
28 // - Added name of module handling an exception to error report.
29 // - Elapsed simulation time now saved to new global variable ElaspedTime.
30 // - Added swmm_getError() function that retrieves error code and message.
31 // - Changed WarningCode to Warnings (# warnings issued).
32 // - Added swmm_getWarnings() function to retrieve value of Warnings.
33 // - Fixed error code returned on swmm_xxx functions.
34 //
35 // Build 5.1.012:
36 // - #include <direct.h> only used when compiled for Windows.
37 //
38 // Build 5.1.013:
39 // - Support added for saving average results within a reporting period.
40 // - SWMM engine now always compiled to a shared object library.
41 //
42 //-----------------------------------------------------------------------------
43 #define _CRT_SECURE_NO_DEPRECATE
44 
45 // --- define WINDOWS
46 #undef WINDOWS
47 #ifdef _WIN32
48  #define WINDOWS
49 #endif
50 #ifdef __WIN32__
51  #define WINDOWS
52 #endif
53 
54 // --- define EXH (MS Windows exception handling)
55 #undef EXH // indicates if exception handling included
56 #ifdef WINDOWS
57  #ifdef _MSC_VER
58  #define EXH
59  #endif
60 
61  // Use alias of methods unavailable before VS2015
62  #if _MSC_VER < 1900
63  #define snprintf _snprintf
64  #endif
65 #endif
66 
67 // --- include Windows & exception handling headers
68 #ifdef WINDOWS
69  #include <windows.h>
70  #include <direct.h>
71 #endif
72 #ifdef EXH
73  #include <excpt.h>
74 #endif
75 
76 
77 // --- define DLLEXPORT
78 
79 //#ifndef DLLEXPORT
80 #ifdef WINDOWS
81  #ifdef __MINGW32__
82  // Seems to be more wrapper friendly
83  #define DLLEXPORT __declspec(dllexport) __cdecl
84  #else
85  #define DLLEXPORT __declspec(dllexport) __stdcall
86  #endif
87 #else
88  #define DLLEXPORT
89 #endif
90 //#endif
91 
92 #include <stdio.h>
93 #include <stdlib.h>
94 #include <string.h>
95 #include <math.h>
96 #include <time.h>
97 #include <float.h>
98 
99 //-----------------------------------------------------------------------------
100 // SWMM's header files
101 //
102 // Note: the directives listed below are also contained in headers.h which
103 // is included at the start of most of SWMM's other code modules.
104 //-----------------------------------------------------------------------------
105 #include "consts.h" // defined constants
106 #include "macros.h" // macros used throughout SWMM
107 #include "enums.h" // enumerated variables
108 #include "error.h" // error message codes
109 #include "datetime.h" // date/time functions
110 #include "objects.h" // definitions of SWMM's data objects
111 #include "funcs.h" // declaration of all global functions
112 #include "text.h" // listing of all text strings
113 #define EXTERN // defined as 'extern' in headers.h
114 #include "globals.h" // declaration of all global variables
115 
116 #include "swmm5.h" // declaration of exportable functions
117 #include "toolkitAPI.h"
118  // callable from other programs
119 #define MAX_EXCEPTIONS 100 // max. number of exceptions handled
120 
121 //-----------------------------------------------------------------------------
122 // Unit conversion factors
123 //-----------------------------------------------------------------------------
124 const double Ucf[10][2] =
125  {// US SI
126  {43200.0, 1097280.0 }, // RAINFALL (in/hr, mm/hr --> ft/sec)
127  {12.0, 304.8 }, // RAINDEPTH (in, mm --> ft)
128  {1036800.0, 26334720.0}, // EVAPRATE (in/day, mm/day --> ft/sec)
129  {1.0, 0.3048 }, // LENGTH (ft, m --> ft)
130  {2.2956e-5, 0.92903e-5}, // LANDAREA (ac, ha --> ft2)
131  {1.0, 0.02832 }, // VOLUME (ft3, m3 --> ft3)
132  {1.0, 1.608 }, // WINDSPEED (mph, km/hr --> mph)
133  {1.0, 1.8 }, // TEMPERATURE (deg F, deg C --> deg F)
134  {2.203e-6, 1.0e-6 }, // MASS (lb, kg --> mg)
135  {43560.0, 3048.0 } // GWFLOW (cfs/ac, cms/ha --> ft/sec)
136  };
137 #ifdef __cplusplus
138 extern const double Qcf[6] = // Flow Conversion Factors:
139 #else
140 const double Qcf[6] = // Flow Conversion Factors:
141 #endif
142  {1.0, 448.831, 0.64632, // cfs, gpm, mgd --> cfs
143  0.02832, 28.317, 2.4466 }; // cms, lps, mld --> cfs
144 
145 //-----------------------------------------------------------------------------
146 // Shared variables
147 //-----------------------------------------------------------------------------
148 static int IsOpenFlag; // TRUE if a project has been opened
149 static int IsStartedFlag; // TRUE if a simulation has been started
150 static int SaveResultsFlag; // TRUE if output to be saved to binary file
151 static int ExceptionCount; // number of exceptions handled
152 static int DoRunoff; // TRUE if runoff is computed
153 static int DoRouting; // TRUE if flow routing is computed
154 
155 //-----------------------------------------------------------------------------
156 // External API functions (prototyped in swmm5.h)
157 //-----------------------------------------------------------------------------
158 // swmm_run
159 // swmm_open
160 // swmm_start
161 // swmm_step
162 // swmm_end
163 // swmm_report
164 // swmm_close
165 // swmm_getMassBalErr
166 // swmm_getVersion
167 
168 //-----------------------------------------------------------------------------
169 // Local functions
170 //-----------------------------------------------------------------------------
171 static void execRouting(void);
172 
173 // Exception filtering function
174 #ifdef EXH
175 static int xfilter(int xc, char* module, double elapsedTime, long step);
176 #endif
177 
178 //=============================================================================
179 
180 int DLLEXPORT swmm_run(char* f1, char* f2, char* f3)
181 //
182 // Input: f1 = name of input file
183 // f2 = name of report file
184 // f3 = name of binary output file
185 // Output: returns error code
186 // Purpose: runs a SWMM simulation.
187 //
188 {
189  long newHour, oldHour = 0;
190  long theDay, theHour;
191  double elapsedTime = 0.0;
192 
193  // --- initialize flags //(5.1.013)
194  IsOpenFlag = FALSE; //
195  IsStartedFlag = FALSE; //
196  SaveResultsFlag = TRUE; //
197 
198  // --- open the files & read input data
199  ErrorCode = 0;
200  swmm_open(f1, f2, f3);
201 
202  // --- run the simulation if input data OK
203  if ( !ErrorCode )
204  {
205  // --- initialize values
206  swmm_start(TRUE);
207 
208  // --- execute each time step until elapsed time is re-set to 0
209  if ( !ErrorCode )
210  {
211  writecon("\n o Simulating day: 0 hour: 0");
212  do
213  {
214  swmm_step(&elapsedTime);
215  newHour = (long)(elapsedTime * 24.0);
216  if ( newHour > oldHour )
217  {
218  theDay = (long)elapsedTime;
219  theHour = (long)((elapsedTime - floor(elapsedTime)) * 24.0);
220  writecon("\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
221  sprintf(Msg, "%-5ld hour: %-2ld", theDay, theHour); //(5.1.013)
222  writecon(Msg);
223  oldHour = newHour;
224  }
225  } while ( elapsedTime > 0.0 && !ErrorCode );
226  writecon("\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
227  "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
228  writecon("Simulation complete ");
229  }
230 
231  // --- clean up
232  swmm_end();
233  }
234 
235  // --- report results
236  if ( Fout.mode == SCRATCH_FILE ) swmm_report();
237 
238  // --- close the system
239  swmm_close();
240  return error_getCode(ErrorCode);
241 }
242 
243 //=============================================================================
244 
245 int DLLEXPORT swmm_open(char* f1, char* f2, char* f3)
246 //
247 // Input: f1 = name of input file
248 // f2 = name of report file
249 // f3 = name of binary output file
250 // Output: returns error code
251 // Purpose: opens a SWMM project.
252 //
253 {
254 // --- to be safe, reset the state of the floating point unit //(5.1.013)
255 #ifdef WINDOWS //(5.1.013)
256  _fpreset();
257 #endif
258 
259 #ifdef EXH
260  // --- begin exception handling here
261  __try
262 #endif
263  {
264  // --- initialize error & warning codes
265  datetime_setDateFormat(M_D_Y);
266  ErrorCode = 0;
267  strcpy(ErrorMsg, "");
268  Warnings = 0;
269  IsOpenFlag = FALSE;
270  IsStartedFlag = FALSE;
271  ExceptionCount = 0;
272 
273  // --- open a SWMM project
274  project_open(f1, f2, f3);
275  if ( ErrorCode ) return error_getCode(ErrorCode);
276  IsOpenFlag = TRUE;
277  report_writeLogo();
278  writecon(FMT06);
279 
280  // --- retrieve project data from input file
281  project_readInput();
282  if ( ErrorCode ) return error_getCode(ErrorCode);
283 
284  // --- write project title to report file & validate data
285  report_writeTitle();
286  project_validate();
287 
288  // --- write input summary to report file if requested
289  if ( RptFlags.input ) inputrpt_writeInput();
290  }
291 
292 #ifdef EXH
293  // --- end of try loop; handle exception here
294  __except(xfilter(GetExceptionCode(), "swmm_open", 0.0, 0))
295  {
296  ErrorCode = ERR_SYSTEM;
297  }
298 #endif
299  return error_getCode(ErrorCode);
300 }
301 
302 //=============================================================================
303 
304 int DLLEXPORT swmm_start(int saveResults)
305 //
306 // Input: saveResults = TRUE if simulation results saved to binary file
307 // Output: returns an error code
308 // Purpose: starts a SWMM simulation.
309 //
310 {
311  // --- check that a project is open & no run started
312  if ( ErrorCode ) return error_getCode(ErrorCode);
313  if ( !IsOpenFlag || IsStartedFlag )
314  {
315  report_writeErrorMsg(ERR_NOT_OPEN, "");
316  return error_getCode(ErrorCode);
317  }
318 
319  // --- save saveResults flag to global variable
320  SaveResultsFlag = saveResults;
321  ExceptionCount = 0;
322 
323 #ifdef EXH
324  // --- begin exception handling loop here
325  __try
326 #endif
327  {
328  // --- initialize elapsed time in decimal days
329  ElapsedTime = 0.0;
330 
331  // --- initialize runoff, routing & reporting time (in milliseconds)
332  NewRunoffTime = 0.0;
333  NewRoutingTime = 0.0;
334  ReportTime = (double)(1000 * ReportStep);
335  StepCount = 0;
336  NonConvergeCount = 0;
337  IsStartedFlag = TRUE;
338 
339  // --- initialize global continuity errors
340  RunoffError = 0.0;
341  GwaterError = 0.0;
342  FlowError = 0.0;
343  QualError = 0.0;
344 
345  // --- open rainfall processor (creates/opens a rainfall
346  // interface file and generates any RDII flows)
347  if ( !IgnoreRainfall ) rain_open();
348  if ( ErrorCode ) return error_getCode(ErrorCode);
349 
350  // --- initialize state of each major system component
351  project_init();
352 
353  // --- see if runoff & routing needs to be computed
354  if ( Nobjects[SUBCATCH] > 0 ) DoRunoff = TRUE;
355  else DoRunoff = FALSE;
356  if ( Nobjects[NODE] > 0 && !IgnoreRouting ) DoRouting = TRUE;
357  else DoRouting = FALSE;
358 
359  // --- open binary output file
360  output_open();
361 
362  // --- open runoff processor
363  if ( DoRunoff ) runoff_open();
364 
365  // --- open & read hot start file if present
366  if ( !hotstart_open() ) return ErrorCode;
367 
368  // --- open routing processor
369  if ( DoRouting ) routing_open();
370 
371  // --- open mass balance and statistics processors
372  massbal_open();
373  stats_open();
374 
375  // --- write project options to report file
376  report_writeOptions();
377  if ( RptFlags.controls ) report_writeControlActionsHeading();
378  }
379 
380 #ifdef EXH
381  // --- end of try loop; handle exception here
382  __except(xfilter(GetExceptionCode(), "swmm_start", 0.0, 0))
383  {
384  ErrorCode = ERR_SYSTEM;
385  }
386 #endif
387  return error_getCode(ErrorCode);
388 }
389 //=============================================================================
390 
391 int DLLEXPORT swmm_step(double* elapsedTime)
392 //
393 // Input: elapsedTime = current elapsed time in decimal days
394 // Output: updated value of elapsedTime,
395 // returns error code
396 // Purpose: advances the simulation by one routing time step.
397 //
398 {
399  // --- check that simulation can proceed
400  if ( ErrorCode ) return error_getCode(ErrorCode);
401  if ( !IsOpenFlag || !IsStartedFlag )
402  {
403  report_writeErrorMsg(ERR_NOT_OPEN, "");
404  return error_getCode(ErrorCode);
405  }
406 
407 #ifdef EXH
408  // --- begin exception handling loop here
409  __try
410 #endif
411  {
412  // --- if routing time has not exceeded total duration
413  if ( NewRoutingTime < TotalDuration )
414  {
415  // --- route flow & WQ through drainage system
416  // (runoff will be calculated as needed)
417  // (NewRoutingTime is updated)
418  execRouting();
419  }
420 
422  // --- if saving results to the binary file
423  if ( SaveResultsFlag )
424  {
425  // --- and it's time to save results
426  if ( NewRoutingTime >= ReportTime )
427  {
428  // --- if user requested that average results be saved:
429  if ( RptFlags.averages )
430  {
431  // --- include latest results in current averages
432  // if current time equals the reporting time
433  if ( NewRoutingTime == ReportTime ) output_updateAvgResults();
434 
435  // --- save current average results to binary file
436  // (which will re-set averages to 0)
437  output_saveResults(ReportTime);
438 
439  // --- if current time exceeds reporting period then
440  // start computing averages for next period
441  if ( NewRoutingTime > ReportTime ) output_updateAvgResults();
442  }
443 
444  // --- otherwise save interpolated point results
445  else output_saveResults(ReportTime);
446 
447  // --- advance to next reporting period
448  ReportTime = ReportTime + (double)(1000 * ReportStep);
449  }
450 
451  // --- not a reporting period so update average results if applicable
452  else if ( RptFlags.averages ) output_updateAvgResults();
453  }
455 
456  // --- update elapsed time (days)
457  if ( NewRoutingTime < TotalDuration )
458  {
459  ElapsedTime = NewRoutingTime / MSECperDAY;
460  }
461 
462  // --- otherwise end the simulation
463  else ElapsedTime = 0.0;
464  *elapsedTime = ElapsedTime;
465  }
466 
467 #ifdef EXH
468  // --- end of try loop; handle exception here
469  __except(xfilter(GetExceptionCode(), "swmm_step", ElapsedTime, StepCount))
470  {
471  ErrorCode = ERR_SYSTEM;
472  }
473 #endif
474  return error_getCode(ErrorCode);
475 }
476 
477 //=============================================================================
478 
479 void execRouting()
480 //
481 // Input: none
482 // Output: none
483 // Purpose: routes flow & WQ through drainage system over a single time step.
484 //
485 {
486  double nextRoutingTime; // updated elapsed routing time (msec)
487  double routingStep; // routing time step (sec)
488 
489 #ifdef EXH
490  // --- begin exception handling loop here
491  __try
492 #endif
493  {
494  // --- determine when next routing time occurs
495  StepCount++;
496  if ( !DoRouting ) routingStep = MIN(WetStep, ReportStep);
497  else routingStep = routing_getRoutingStep(RouteModel, RouteStep);
498  if ( routingStep <= 0.0 )
499  {
500  ErrorCode = ERR_TIMESTEP;
501  return;
502  }
503  nextRoutingTime = NewRoutingTime + 1000.0 * routingStep;
504 
505  // --- adjust routing step so that total duration not exceeded
506  if ( nextRoutingTime > TotalDuration )
507  {
508  routingStep = (TotalDuration - NewRoutingTime) / 1000.0;
509  routingStep = MAX(routingStep, 1./1000.0);
510  nextRoutingTime = TotalDuration;
511  }
512 
513  // --- compute runoff until next routing time reached or exceeded
514  if ( DoRunoff ) while ( NewRunoffTime < nextRoutingTime )
515  {
516  runoff_execute();
517  if ( ErrorCode ) return;
518  }
519 
520  // --- if no runoff analysis, update climate state (for evaporation)
521  else climate_setState(getDateTime(NewRoutingTime));
522 
523  // --- route flows & pollutants through drainage system
524  // (while updating NewRoutingTime)
525  if ( DoRouting ) routing_execute(RouteModel, routingStep);
526  else
527  NewRoutingTime = nextRoutingTime;
528  }
529 
530 #ifdef EXH
531  // --- end of try loop; handle exception here
532  __except(xfilter(GetExceptionCode(), "execRouting",
533  ElapsedTime, StepCount))
534  {
535  ErrorCode = ERR_SYSTEM;
536  return;
537  }
538 #endif
539 }
540 
541 //=============================================================================
542 
543 int DLLEXPORT swmm_end(void)
544 //
545 // Input: none
546 // Output: none
547 // Purpose: ends a SWMM simulation.
548 //
549 {
550  // --- check that project opened and run started
551  if ( !IsOpenFlag )
552  {
553  report_writeErrorMsg(ERR_NOT_OPEN, "");
554  return error_getCode(ErrorCode);
555  }
556 
557  if ( IsStartedFlag )
558  {
559  // --- write ending records to binary output file
560  if ( Fout.file ) output_end();
561 
562  // --- report mass balance results and system statistics
563  if ( !ErrorCode )
564  {
565  massbal_report();
566  stats_report();
567  }
568 
569  // --- close all computing systems
570  stats_close();
571  massbal_close();
572  if ( !IgnoreRainfall ) rain_close();
573  if ( DoRunoff ) runoff_close();
574  if ( DoRouting ) routing_close(RouteModel);
575  hotstart_close();
576  IsStartedFlag = FALSE;
577  }
578  return error_getCode(ErrorCode);
579 }
580 
581 //=============================================================================
582 
583 int DLLEXPORT swmm_report()
584 //
585 // Input: none
586 // Output: returns an error code
587 // Purpose: writes simulation results to report file.
588 //
589 {
590  if ( Fout.mode == SCRATCH_FILE ) output_checkFileSize();
591  if ( ErrorCode ) report_writeErrorCode();
592  else
593  {
594  writecon(FMT07);
595  report_writeReport();
596  }
597  return error_getCode(ErrorCode);
598 }
599 
600 //=============================================================================
601 
602 int DLLEXPORT swmm_close()
603 //
604 // Input: none
605 // Output: returns an error code
606 // Purpose: closes a SWMM project.
607 //
608 {
609  if ( Fout.file ) output_close();
610  if ( IsOpenFlag ) project_close();
611  report_writeSysTime();
612  if ( Finp.file != NULL ) fclose(Finp.file);
613  if ( Frpt.file != NULL ) fclose(Frpt.file);
614  if ( Fout.file != NULL )
615  {
616  fclose(Fout.file);
617  if ( Fout.mode == SCRATCH_FILE ) remove(Fout.name);
618  }
619  IsOpenFlag = FALSE;
620  IsStartedFlag = FALSE;
621  return 0;
622 }
623 
624 //=============================================================================
625 
626 int DLLEXPORT swmm_getMassBalErr(float* runoffErr, float* flowErr,
627  float* qualErr)
628 //
629 // Input: none
630 // Output: runoffErr = runoff mass balance error (percent)
631 // flowErr = flow routing mass balance error (percent)
632 // qualErr = quality routing mass balance error (percent)
633 // returns an error code
634 // Purpose: reports a simulation's mass balance errors.
635 //
636 {
637  *runoffErr = 0.0;
638  *flowErr = 0.0;
639  *qualErr = 0.0;
640 
641  if ( IsOpenFlag && !IsStartedFlag)
642  {
643  *runoffErr = (float)RunoffError;
644  *flowErr = (float)FlowError;
645  *qualErr = (float)QualError;
646  }
647  return 0;
648 }
649 
650 //=============================================================================
651 
652 int DLLEXPORT swmm_getVersion(void)
653 //
654 // Input: none
655 // Output: returns SWMM engine version number
656 // Purpose: retrieves version number of current SWMM engine which
657 // uses a format of xyzzz where x = major version number,
658 // y = minor version number, and zzz = build number.
659 //
660 // NOTE: Each New Release should be updated in consts.h
661 // THIS FUNCTION WILL EVENTUALLY BE DEPRECATED
662 {
663  return VERSION;
664 }
665 
666 void DLLEXPORT swmm_getSemVersion(char* semver)
667 //
668 // Output: Returns Semantic Version
669 // Purpose: retrieves the current semantic version
670 //
671 // NOTE: Each New Release should be updated in consts.h
672 {
673  getSemVersion(semver);
674 }
675 
676 void DLLEXPORT swmm_getVersionInfo(char* major, char* minor, char* patch)
677 //
678 // Output: Returns Semantic Version Info
679 // Purpose: retrieves the current semantic version
680 //
681 // NOTE: Each New Release should be updated in consts.h
682 {
683  strncpy(major, SEMVERSION_MAJOR, sizeof SEMVERSION_MAJOR);
684  strncpy(minor, SEMVERSION_MINOR, sizeof SEMVERSION_MINOR);
685  strncpy(patch, SEMVERSION_PATCH, sizeof SEMVERSION_PATCH);
686 }
687 
688 //=============================================================================
689 
690 int DLLEXPORT swmm_getWarnings(void)
691 //
692 // Input: none
693 // Output: returns number of warning messages issued.
694 // Purpose: retireves number of warning messages issued during an analysis.
695 {
696  return Warnings;
697 }
698 
699 //=============================================================================
700 
701 int DLLEXPORT swmm_getError(char* errMsg, int msgLen)
702 //
703 // Input: errMsg = character array to hold error message text
704 // msgLen = maximum size of errMsg
705 // Output: returns error message code number and text of error message.
706 // Purpose: retrieves the code number and text of the error condition that
707 // caused SWMM to abort its analysis.
708 {
709  size_t errMsgLen = msgLen;
710 
711  // --- copy text of last error message into errMsg
712  if ( ErrorCode > 0 && strlen(ErrorMsg) == 0 ) sstrncpy(errMsg, "", 1);
713  else
714  {
715  errMsgLen = MIN(errMsgLen, strlen(ErrorMsg));
716  errMsg = sstrncpy(errMsg, ErrorMsg, errMsgLen);
717  }
718 
719  // --- remove leading line feed from errMsg
720  if ( errMsgLen > 0 && errMsg[0] == '\n' ) errMsg[0] = ' ';
721  return error_getCode(ErrorCode);
722 }
723 
724 //=============================================================================
725 // General purpose functions
726 //=============================================================================
727 
728 double UCF(int u)
729 //
730 // Input: u = integer code of quantity being converted
731 // Output: returns a units conversion factor
732 // Purpose: computes a conversion factor from SWMM's internal
733 // units to user's units
734 //
735 {
736  if ( u < FLOW ) return Ucf[u][UnitSystem];
737  else return Qcf[FlowUnits];
738 }
739 
740 //=============================================================================
741 
742 char* sstrncpy(char *dest, const char *src, size_t maxlen)
743 //
744 // Input: dest = string to be copied to
745 // src = string to be copied from
746 // maxlen = number of characters to copy
747 // Output: returns a pointer to dest
748 // Purpose: safe version of standard strncpy function
749 //
750 {
751  strncpy(dest, src, maxlen);
752  dest[maxlen] = '\0';
753  return dest;
754 }
755 
756 //=============================================================================
757 
758 int strcomp(char *s1, char *s2)
759 //
760 // Input: s1 = a character string
761 // s2 = a character string
762 // Output: returns 1 if s1 is same as s2, 0 otherwise
763 // Purpose: does a case insensitive comparison of two strings.
764 //
765 {
766  int i;
767  for (i = 0; UCHAR(s1[i]) == UCHAR(s2[i]); i++)
768  {
769  if (!s1[i+1] && !s2[i+1]) return(1);
770  }
771  return(0);
772 }
773 
774 //=============================================================================
775 
776 char* getTempFileName(char* fname)
777 //
778 // Input: fname = file name string (with max size of MAXFNAME)
779 // Output: returns pointer to file name
780 // Purpose: creates a temporary file name with path prepended to it.
781 //
782 {
783 // For Windows systems:
784 #ifdef WINDOWS
785 
786  char* name = NULL;
787  char* dir = NULL;
788 
789  // --- set dir to user's choice of a temporary directory
790  if (strlen(TempDir) > 0)
791  {
792  _mkdir(TempDir);
793  dir = TempDir;
794  }
795 
796  // --- use _tempnam to get a pointer to an unused file name
797  name = _tempnam(dir, "swmm");
798  if (name == NULL) return NULL;
799 
800  // --- copy the file name to fname
801  if (strlen(name) < MAXFNAME) strncpy(fname, name, MAXFNAME);
802  else fname = NULL;
803 
804  // --- free the pointer returned by _tempnam
805  free(name);
806 
807  // --- return the new contents of fname
808  return fname;
809 
810 // For non-Windows systems:
811 #else
812 
813  // --- use system function mkstemp() to create a temporary file name
814  strcpy(fname, "swmmXXXXXX");
815  mkstemp(fname);
816  return fname;
817 
818 #endif
819 }
820 
821 //=============================================================================
822 
823 void getElapsedTime(DateTime aDate, int* days, int* hrs, int* mins)
824 //
825 // Input: aDate = simulation calendar date + time
826 // Output: days, hrs, mins = elapsed days, hours & minutes for aDate
827 // Purpose: finds elapsed simulation time for a given calendar date
828 //
829 {
830  DateTime x;
831  int secs;
832  x = aDate - StartDateTime;
833  if ( x <= 0.0 )
834  {
835  *days = 0;
836  *hrs = 0;
837  *mins = 0;
838  }
839  else
840  {
841  *days = (int)x;
842  datetime_decodeTime(x, hrs, mins, &secs);
843  }
844 }
845 
846 //=============================================================================
847 
848 DateTime getDateTime(double elapsedMsec)
849 //
850 // Input: elapsedMsec = elapsed milliseconds
851 // Output: returns date/time value
852 // Purpose: finds calendar date/time value for elapsed milliseconds of
853 // simulation time.
854 //
855 {
856  return datetime_addSeconds(StartDateTime, (elapsedMsec+1)/1000.0);
857 }
858 
859 //=============================================================================
860 
861 void writecon(char *s)
862 //
863 // Input: s = a character string
864 // Output: none
865 // Purpose: writes string of characters to the console.
866 //
867 {
868  fprintf(stdout,"%s", s);
869  fflush(stdout);
870 }
871 
872 //=============================================================================
873 
874 #ifdef EXH
875 int xfilter(int xc, char* module, double elapsedTime, long step)
876 //
877 // Input: xc = exception code
878 // module = name of code module where exception was handled
879 // elapsedTime = simulation time when exception occurred (days)
880 // step = step count at time when exception occurred
881 // Output: returns an exception handling code
882 // Purpose: exception filtering routine for operating system exceptions
883 // under Windows and the Microsoft C compiler.
884 //
885 {
886  int rc; // result code
887  long hour; // current hour of simulation
888  char msg[40]; // exception type text
889  char xmsg[120]; // error message text
890  switch (xc)
891  {
892  case EXCEPTION_ACCESS_VIOLATION:
893  sprintf(msg, "\n Access violation ");
894  rc = EXCEPTION_EXECUTE_HANDLER;
895  break;
896  case EXCEPTION_FLT_DENORMAL_OPERAND:
897  sprintf(msg, "\n Illegal floating point operand ");
898  rc = EXCEPTION_CONTINUE_EXECUTION;
899  break;
900  case EXCEPTION_FLT_DIVIDE_BY_ZERO:
901  sprintf(msg, "\n Floating point divide by zero ");
902  rc = EXCEPTION_CONTINUE_EXECUTION;
903  break;
904  case EXCEPTION_FLT_INVALID_OPERATION:
905  sprintf(msg, "\n Illegal floating point operation ");
906  rc = EXCEPTION_CONTINUE_EXECUTION;
907  break;
908  case EXCEPTION_FLT_OVERFLOW:
909  sprintf(msg, "\n Floating point overflow ");
910  rc = EXCEPTION_CONTINUE_EXECUTION;
911  break;
912  case EXCEPTION_FLT_STACK_CHECK:
913  sprintf(msg, "\n Floating point stack violation ");
914  rc = EXCEPTION_EXECUTE_HANDLER;
915  break;
916  case EXCEPTION_FLT_UNDERFLOW:
917  sprintf(msg, "\n Floating point underflow ");
918  rc = EXCEPTION_CONTINUE_EXECUTION;
919  break;
920  case EXCEPTION_INT_DIVIDE_BY_ZERO:
921  sprintf(msg, "\n Integer divide by zero ");
922  rc = EXCEPTION_CONTINUE_EXECUTION;
923  break;
924  case EXCEPTION_INT_OVERFLOW:
925  sprintf(msg, "\n Integer overflow ");
926  rc = EXCEPTION_CONTINUE_EXECUTION;
927  break;
928  default:
929  sprintf(msg, "\n Exception %d ", xc);
930  rc = EXCEPTION_EXECUTE_HANDLER;
931  }
932  hour = (long)(elapsedTime / 1000.0 / 3600.0);
933  sprintf(xmsg, "%sin module %s at step %d, hour %d",
934  msg, module, step, hour);
935  if ( rc == EXCEPTION_EXECUTE_HANDLER ||
936  ++ExceptionCount >= MAX_EXCEPTIONS )
937  {
938  strcat(xmsg, " --- execution halted.");
939  rc = EXCEPTION_EXECUTE_HANDLER;
940  }
941  report_writeLine(xmsg);
942  return rc;
943 }
944 #endif
945 
946 int swmm_IsOpenFlag()
947 //
948 // Check if Project is Open
949 {
950  // TRUE if a project has been opened
951  return IsOpenFlag;
952 }
953 
954 
955 int swmm_IsStartedFlag()
956 //
957 // Check if Simulation has started
958 {
959  // TRUE if a simulation has been started
960  return IsStartedFlag;
961 }
962 
963 
964 void getSemVersion(char* semver)
965 //
966 // Output: Returns Semantic Version
967 // Purpose: retrieves the current semantic version
968 //
969 // NOTE: Each New Release should be updated in consts.h
970 {
971  snprintf(semver, SEMVERSION_LEN, "%s.%s.%s",
972  SEMVERSION_MAJOR, SEMVERSION_MINOR, SEMVERSION_PATCH);
973 }
974 //=============================================================================
void DLLEXPORT swmm_getVersionInfo(char *major, char *minor, char *patch)
Get full semantic version number info.
Definition: swmm5.c:676
int DLLEXPORT swmm_end(void)
End SWMM simulation.
Definition: swmm5.c:543
Prototypes for SWMM5 functions exported to swmm5.dll.
void DLLEXPORT swmm_getSemVersion(char *semver)
Get full semantic version number.
Definition: swmm5.c:666
int DLLEXPORT swmm_close(void)
Frees all memory and files used by SWMM.
Definition: swmm5.c:602
int DLLEXPORT swmm_report(void)
Write text report file.
Definition: swmm5.c:583
int DLLEXPORT swmm_run(char *f1, char *f2, char *f3)
Opens SWMM input file, reads in network data, runs, and closes.
Definition: swmm5.c:180
int DLLEXPORT swmm_step(double *elapsedTime)
Step SWMM simulation forward.
Definition: swmm5.c:391
int DLLEXPORT swmm_getVersion(void)
Get Legacy SWMM version number.
Definition: swmm5.c:652
int DLLEXPORT swmm_start(int saveFlag)
Start SWMM simulation.
Definition: swmm5.c:304
int DLLEXPORT swmm_getMassBalErr(float *runoffErr, float *flowErr, float *qualErr)
Get routing errors.
Definition: swmm5.c:626
int DLLEXPORT swmm_open(char *f1, char *f2, char *f3)
Opens SWMM input file & reads in network data.
Definition: swmm5.c:245
Exportable Functions for Toolkit API.