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
elementNames
storing strings for each subcatch/node/link/pollut. - An embedded
error_handle_t
used 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_t
or__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_t
by callingnew_errormanager(&errorLookup)
. - Returns
0
if successful,-1
if 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,
Nperiods
is > 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->elementNames
is not yet built, callsinitElementNames()
.initElementNames()
reads fromIDPos
in 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 (
startPeriod
toendPeriod
). - Internally loops from
k = 0
tolen
, 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.
No comments:
Post a Comment