Below is a step‐by‐step explanation of how swmm_output.c works. It is a C library that reads from a SWMM (Storm Water Management Model) binary output file, providing functions to:
- Open/Close the output file,
- Retrieve metadata (time steps, units, number of elements), and
- Extract time‐series or snapshot data (for subcatchments, nodes, links, and system).
It also manages an error mechanism via errormanager.h.
1. Purpose
/*
* swmm_output.c - SWMM Output API
*
* Author: Colleen Barr, ...
* Modified by: Michael E. Tryby, Bryant McDonnell
*/
This file defines a higher‐level API for reading SWMM’s binary results. A SWMM run produces a file containing flows, depths, water quality, etc. This API:
- Opens that file,
- Verifies it’s a valid SWMM output file,
- Reads the internal file structure (metadata, offsets),
- Retrieves data for subcatchments, nodes, links, pollutants, system variables, etc.
The main interface is via an opaque handle (SMO_Handle), which the library user requests and manipulates through the various SMO_* functions.
2. Data Structures
2.1 data_t
An internal struct that holds:
- File Info: path,
FILE* file, - Element Info:
Nsubcatch,Nnodes,Nlinks,Npolluts, number of time periodsNperiods, etc. - Positions/Offsets: for file sections (object IDs, results, etc.).
- An array
elementNamesstoring strings for each subcatch/node/link/pollut. - An embedded
error_handle_tused for error management.
This struct is not exposed externally. Instead, callers see a SMO_Handle pointer (which is cast to data_t* internally).
2.2 File Format Constants
INT4,REAL4: 32-bit int/float types.F_OFF: 64-bit integer type for large file support (off_tor__int64).RECORDSIZE 4: data is stored in 4-byte increments for integers or floats.DATESIZE 8: date/time is stored in an 8-byte double.NELEMENTTYPES 5: subcatch, node, link, system, pollutant sets?
3. Key Functions
3.1 Initialization / Cleanup
-
SMO_init(SMO_Handle *p_handle)- Allocates a
data_t*, zero‐initialized withcalloc. - Creates an
error_handle_tby callingnew_errormanager(&errorLookup). - Returns
0if successful,-1if allocation fails.
- Allocates a
-
SMO_close(SMO_Handle* p_handle)- Frees resources in
data_t. - Closes the file if open, frees
elementNames[], callsdst_errormanager, then freesdata_t. - Sets the user’s
*p_handle = NULL.
- Frees resources in
3.2 Opening the SWMM Output File
int SMO_open(SMO_Handle p_handle, const char *path)
{
...
// open file in "rb" mode
// call validateFile(p_data)
// read essential metadata from the file header
...
}
validateFile()checks:- The “magic number” at start/end,
Nperiodsis > 0,- an error code from the run in the file epilogue.
- Reads counts of subcatchments, nodes, links, pollutants, plus offset positions in the file (
IDPos,ObjPropPos,ResultsPos). - Also reads
StartDate,ReportStep, and calculatesBytesPerPeriod.
3.3 Retrieving Version, Units, Project Size
SMO_getVersion(...)- Reads integer in file near offset
2 * RECORDSIZE, which indicates SWMM version (like 52000).
- Reads integer in file near offset
SMO_getProjectSize(...)- Returns an array of counts:
[Nsubcatch, Nnodes, Nlinks, 1, Npolluts].
- Returns an array of counts:
SMO_getUnits(...)orSMO_getFlowUnits(...)- Gets integer code for flow units (CFS, GPM, etc.), and sets if the system is US or SI.
SMO_getPollutantUnits(...)- Retrieves concentration units for each pollutant (mg/L, ug/L, etc.).
3.4 Getting Time Steps
SMO_getTimes(...)can query:SMO_reportStep: reporting time step in seconds,SMO_numPeriods: total number of reported periods (Nperiods).
3.5 Getting Element Names
SMO_getElementName(...)- If
p_data->elementNamesis not yet built, callsinitElementNames().initElementNames()reads fromIDPosin the file, for each object a 4‐byte length, followed by that many characters.
- Depending on
type(subcatch, node, link, pollut), it picks the correct index inelementNames[]. - Allocates a buffer for the name.
- If
3.6 Extracting Time Series
SMO_getSubcatchSeries(...)/SMO_getNodeSeries(...)/SMO_getLinkSeries(...)/SMO_getSystemSeries(...):- Return arrays of data for a particular object over a range of time indices (
startPeriodtoendPeriod). - Internally loops from
k = 0tolen, callinggetSubcatchValue(...)orgetNodeValue(...), etc.
- Return arrays of data for a particular object over a range of time indices (
3.7 Snapshot Data (Single Period, Many Elements)
SMO_getSubcatchAttribute(...)for a single period and all subcatchments.SMO_getNodeAttribute(...)for a single period and all nodes, etc.- Also variants for
SMO_getLinkAttribute(...)andSMO_getSystemAttribute(...).
3.8 Low-Level Readers: getSubcatchValue(...), getNodeValue(...), etc.
These functions compute an offset in the output file that depends on:
- The current time period (
timeIndex). - The element’s index and variable code.
- The known layout (
BytesPerPeriod, subcatch/node/link count, etc.).
They call:
_fseek(p_data->file, offset, SEEK_SET);
fread(&value, RECORDSIZE, 1, p_data->file);
to read a single float from the file.
4. Additional Utility
SMO_free(void **array): A convenience function to free memory allocated by the library for arrays (like time series). Sets pointer toNULL._fopen,_fseek,_ftell: Wrappers ensuring large file support or cross‐platform differences.
5. Error Handling
The code uses set_error(...) to store an integer code in p_data->error_handle->error_status (like 411, 422, 423, etc.). Then:
SMO_checkError(...)retrieves that code and callscheck_error(...)(which returns a message string).SMO_clearError(...)resets the code to 0.
errorLookup(...) is the local function mapping an error code to a message constant from messages.h.
6. Summary
swmm_output.c is a self-contained library to:
- Open a SWMM results file (binary),
- Check basic validity,
- Provide convenient functions to get metadata (counts, units, times),
- Read time series or snapshot data for subcatchments, nodes, links, pollutants, system,
- Return data as arrays of floats or single floats,
- Manage errors with an internal mechanism.
Hence, it abstracts the SWMM binary file format details away from the user, offering a simpler API for post-processing or analyzing SWMM results programmatically.