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