Hi Python Tutors, I'm using a storm water modelling program, EPA SWMM, to model the hydrology and hydraulics of a study area.
SWMM reports its results in a binary (.out) file that contains the results for each element in the model at each time step in the model run. According to the SWMM interface manual (http://www.epa.gov/ednnrmrl/models/swmm/swmm5_iface.zip), one can use a DLL file to read the .out file. I want to do this so that I can read the state of a river at a specific time and plot its water level in a GIS. After some searching on the Internet, I came across ctypes, which I have tried. According to the SWMM manual: [manual] Opening the Output File ---------------------------------- A function named OpenSwmmOutFile(outFile) that performs these tasks is contained in the example code files that accompany this guide. The argument to the function is the name of the binary output file. The return value from the function is an integer code with the following meanings: 0 - the run was successful 1 - the run was terminated with an error 2 - the output file could not be opened. [/manual] So, I tried the following python code: [code] In [14]: swmmdll = cdll.LoadLibrary("C:\\Hanlie\\model\\SWMM\\swmm5_0_018.dll") In [15]: results_file="C:\\Hanlie\\model\\SWMM\\c83a_v0\\c83a_v0.3.out" In [16]: open_file=swmmdll.OpenSwmmOutFile(results_file) ------------------------------------------------------------ Traceback (most recent call last): File "<ipython console>", line 1, in <module> File "C:\Python26\lib\ctypes\__init__.py", line 366, in __getattr__ func = self.__getitem__(name) File "C:\Python26\lib\ctypes\__init__.py", line 371, in __getitem__ func = self._FuncPtr((name_or_ordinal, self)) AttributeError: function 'OpenSwmmOutFile' not found [/code] Can anyone perhaps help me to access the functions in this DLL? The manual also states: [manual] The following files are needed for applications that call functions from the swmm5.dll library: · swmm5.h for C/C++ applications · swmm5.bas for Visual Basic applications · swmm5.pas for Delphi applications. [/manual] And they give an example in C, Basic and Pascal to use the interface. I have appended the C example to this message. Thanks Hanlie [code] // swmm5_iface.c // // Example code for interfacing SWMM 5 with C/C++ programs. // // Remember to #include the file swmm5_iface.h in the calling program. #include <stdio.h> #include <windows.h> #include "swmm5.h" int SWMM_Nperiods; // number of reporting periods int SWMM_FlowUnits; // flow units code int SWMM_Nsubcatch; // number of subcatchments int SWMM_Nnodes; // number of drainage system nodes int SWMM_Nlinks; // number of drainage system links int SWMM_Npolluts; // number of pollutants tracked double SWMM_StartDate; // start date of simulation int SWMM_ReportStep; // reporting time step (seconds) int RunSwmmExe(char* cmdLine); int RunSwmmDll(char* inpFile, char* rptFile, char* outFile); int OpenSwmmOutFile(char* outFile); int GetSwmmResult(int iType, int iIndex, int vIndex, int period, float* value); void CloseSwmmOutFile(void); static const int SUBCATCH = 0; static const int NODE = 1; static const int LINK = 2; static const int SYS = 3; static const int RECORDSIZE = 4; // number of bytes per file record static int SubcatchVars; // number of subcatch reporting variables static int NodeVars; // number of node reporting variables static int LinkVars; // number of link reporting variables static int SysVars; // number of system reporting variables static FILE* Fout; // file handle static int StartPos; // file position where results start static int BytesPerPeriod; // bytes used for results in each period static void ProcessMessages(void); //----------------------------------------------------------------------------- int RunSwmmExe(char* cmdLine) //----------------------------------------------------------------------------- { int exitCode; STARTUPINFO si; PROCESS_INFORMATION pi; // --- initialize data structures memset(&si, 0, sizeof(si)); memset(&pi, 0, sizeof(pi)); si.cb = sizeof(si); si.wShowWindow = SW_SHOWNORMAL; // --- launch swmm5.exe exitCode = CreateProcess(NULL, cmdLine, NULL, NULL, 0, 0, NULL, NULL, &si, &pi); // --- wait for program to end exitCode = WaitForSingleObject(pi.hProcess, INFINITE); // --- retrieve the error code produced by the program GetExitCodeProcess(pi.hProcess, &exitCode); // --- release handles CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return exitCode; } //----------------------------------------------------------------------------- int RunSwmmDll(char* inpFile, char* rptFile, char* outFile) //----------------------------------------------------------------------------- { int err; double elapsedTime; // --- open a SWMM project err = swmm_open(inpFile, rptFile, outFile); if (!err) { // --- initialize all processing systems err = swmm_start(1); if (err == 0) { // --- step through the simulation do { // --- allow Windows to process any pending events ProcessMessages(); // --- extend the simulation by one routing time step err = swmm_step(&elapsedTime); ///////////////////////////////////////////// // --- call progress reporting function here, // using elapsedTime as an argument ///////////////////////////////////////////// } while (elapsedTime > 0.0 && err == 0); // --- close all processing systems swmm_end(); } } // --- close the project swmm_close(); return err; } //----------------------------------------------------------------------------- void ProcessMessages(void) //----------------------------------------------------------------------------- { /**** Only use this function with a Win32 application ***** MSG msg; while (TRUE) { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) break; else { TranslateMessage(&msg); DispatchMessage(&msg); } } else break; } ***********************************************************/ } //----------------------------------------------------------------------------- int OpenSwmmOutFile(char* outFile) //----------------------------------------------------------------------------- { int magic1, magic2, errCode, offset, offset0, version; int err; // --- open the output file Fout = fopen(outFile, "rb"); if (Fout == NULL) return 2; // --- check that file contains at least 14 records fseek(Fout, 0L, SEEK_END); if (ftell(Fout) < 14*RECORDSIZE) { fclose(Fout); return 1; } // --- read parameters from end of file fseek(Fout, -5*RECORDSIZE, SEEK_END); fread(&offset0, RECORDSIZE, 1, Fout); fread(&StartPos, RECORDSIZE, 1, Fout); fread(&SWMM_Nperiods, RECORDSIZE, 1, Fout); fread(&errCode, RECORDSIZE, 1, Fout); fread(&magic2, RECORDSIZE, 1, Fout); // --- read magic number from beginning of file fseek(Fout, 0L, SEEK_SET); fread(&magic1, RECORDSIZE, 1, Fout); // --- perform error checks if (magic1 != magic2) err = 1; else if (errCode != 0) err = 1; else if (SWMM_Nperiods == 0) err = 1; else err = 0; // --- quit if errors found if (err > 0 ) { fclose(Fout); Fout = NULL; return err; } // --- otherwise read additional parameters from start of file fread(&version, RECORDSIZE, 1, Fout); fread(&SWMM_FlowUnits, RECORDSIZE, 1, Fout); fread(&SWMM_Nsubcatch, RECORDSIZE, 1, Fout); fread(&SWMM_Nnodes, RECORDSIZE, 1, Fout); fread(&SWMM_Nlinks, RECORDSIZE, 1, Fout); fread(&SWMM_Npolluts, RECORDSIZE, 1, Fout); // Skip over saved subcatch/node/link input values offset = (SWMM_Nsubcatch+2) * RECORDSIZE // Subcatchment area + (3*SWMM_Nnodes+4) * RECORDSIZE // Node type, invert & max depth + (5*SWMM_Nlinks+6) * RECORDSIZE; // Link type, z1, z2, max depth & length offset = offset0 + offset; fseek(Fout, offset, SEEK_SET); // Read number & codes of computed variables fread(&SubcatchVars, RECORDSIZE, 1, Fout); // # Subcatch variables fseek(Fout, SubcatchVars*RECORDSIZE, SEEK_CUR); fread(&NodeVars, RECORDSIZE, 1, Fout); // # Node variables fseek(Fout, NodeVars*RECORDSIZE, SEEK_CUR); fread(&LinkVars, RECORDSIZE, 1, Fout); // # Link variables fseek(Fout, LinkVars*RECORDSIZE, SEEK_CUR); fread(&SysVars, RECORDSIZE, 1, Fout); // # System variables // --- read data just before start of output results offset = StartPos - 3*RECORDSIZE; fseek(Fout, offset, SEEK_SET); fread(&SWMM_StartDate, sizeof(double), 1, Fout); fread(&SWMM_ReportStep, RECORDSIZE, 1, Fout); // --- compute number of bytes of results values used per time period BytesPerPeriod = 2*RECORDSIZE + // date value (a double) (SWMM_Nsubcatch*SubcatchVars + SWMM_Nnodes*NodeVars+ SWMM_Nlinks*LinkVars + SysVars)*RECORDSIZE; // --- return with file left open return err; } //----------------------------------------------------------------------------- int GetSwmmResult(int iType, int iIndex, int vIndex, int period, float* value) //----------------------------------------------------------------------------- { int offset; // --- compute offset into output file *value = 0.0; offset = StartPos + (period-1)*BytesPerPeriod + 2*RECORDSIZE; if ( iType == SUBCATCH ) { offset += RECORDSIZE*(iIndex*SubcatchVars + vIndex); } else if (iType == NODE) { offset += RECORDSIZE*(SWMM_Nsubcatch*SubcatchVars + iIndex*NodeVars + vIndex); } else if (iType == LINK) { offset += RECORDSIZE*(SWMM_Nsubcatch*SubcatchVars + SWMM_Nnodes*NodeVars + iIndex*LinkVars + vIndex); } else if (iType == SYS) { offset += RECORDSIZE*(SWMM_Nsubcatch*SubcatchVars + SWMM_Nnodes*NodeVars + SWMM_Nlinks*LinkVars + vIndex); } else return 0; // --- re-position the file and read the result fseek(Fout, offset, SEEK_SET); fread(value, RECORDSIZE, 1, Fout); return 1; } //----------------------------------------------------------------------------- void CloseSwmmOutFile(void) //----------------------------------------------------------------------------- { if (Fout != NULL) { fclose(Fout); Fout = NULL; } } [/code] _______________________________________________ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: http://mail.python.org/mailman/listinfo/tutor