Below is a step‐by‐step explanation of iface.c
, which manages routing interface files in EPA SWMM5. These files store node flow and pollutant concentration data at specific time intervals, typically used to integrate external or separate simulation results into SWMM's routing process or to export SWMM results to other systems.
1. Purpose
// iface.c
// Routing interface file functions.
- SWMM can read inflows from an external file (
Finflows
) and write outflows to a file (Foutflows
) at specified intervals. - It’s commonly used to couple SWMM with other models or to use prior simulation results as inflows for the current simulation.
2. Key Global Variables
Below are the main static variables that iface.c
manages:
static int IfaceFlowUnits; // Flow units (CFS, CMS, etc.) in interface file
static int IfaceStep; // Time step (sec) used by the inflows file
static int NumIfacePolluts; // Number of pollutants on interface file (excluding flow)
static int* IfacePolluts; // Array mapping project's pollutants to file pollutants
static int NumIfaceNodes; // Number of nodes with flow/quality data in inflows file
static int* IfaceNodes; // Mapping of file node index to project node index
static double** OldIfaceValues; // Node flow & WQ from the previous file time
static double** NewIfaceValues; // Node flow & WQ from the next file time
static double IfaceFrac; // Fraction of time between old & new interface data
static DateTime OldIfaceDate; // Date/time of OldIfaceValues
static DateTime NewIfaceDate; // Date/time of NewIfaceValues
These variables track how the interface data is read and interpolated over time. For instance, OldIfaceValues[i]
and NewIfaceValues[i]
contain the flow and pollutant concentrations for node i
at two bracketing times. Then IfaceFrac
is used to interpolate for the current time step.
3. Reading File Parameters
3.1 iface_readFileParams(tok, ntoks)
int iface_readFileParams(char* tok[], int ntoks)
- Reads a line of input specifying whether SWMM should USE or SAVE a particular type of interface file (rainfall, runoff, hotstart, RDII, inflows, outflows).
- For instance:
USE INFLOWS <filename> SAVE OUTFLOWS <filename>
- If
USE INFLOWS
, it means we want to read node flows/quality from<filename>
. - If
SAVE OUTFLOWS
, it means we want to write node outflows/quality to<filename>
. - The result is stored in the appropriate global file variable: e.g.,
Finflows
orFoutflows
.
4. Opening and Closing Routing Interface Files
4.1 iface_openRoutingFiles()
void iface_openRoutingFiles()
{
// Initialize variables
// If outflows file is to be saved, openFileForOutput()
// If inflows file is to be used, openFileForInput()
}
- Initializes the static global variables.
- Checks if the same file name is used for both inflows and outflows => error.
- Calls
openFileForOutput()
ifFoutflows.mode == SAVE_FILE
. - Calls
openFileForInput()
ifFinflows.mode == USE_FILE
.
4.2 iface_closeRoutingFiles()
void iface_closeRoutingFiles()
{
// free memory for IfacePolluts, IfaceNodes, OldIfaceValues, NewIfaceValues
// close Finflows.file & Foutflows.file
}
- Releases all memory allocated for the node/pollut arrays and data matrices.
- Closes the inflows/outflows files if they were open.
5. Accessing Interface Inflows During Routing
5.1 iface_getNumIfaceNodes(currentDate)
int iface_getNumIfaceNodes(DateTime currentDate)
{
// check if OldIfaceDate > currentDate => no data
// while NewIfaceDate < currentDate => shift OldIface -> NewIface, read next
// compute IfaceFrac = fraction of time between OldIfaceDate & NewIfaceDate
// return NumIfaceNodes
}
- Called at each routing time step to ensure we have up‐to‐date interface inflows.
- If the simulation time has advanced beyond the next interface time, it reads the next record from the interface file.
IfaceFrac
= is used for linear interpolation of flow/quality data.- Returns the number of nodes for which inflow data is available.
5.2 iface_getIfaceNode(index)
int iface_getIfaceNode(int index)
{
if (index in [0..NumIfaceNodes-1]) return IfaceNodes[index];
else return -1;
}
- Maps an interface file node index
0..NumIfaceNodes-1
to the actual SWMM node index.
5.3 iface_getIfaceFlow(index)
double iface_getIfaceFlow(int index)
{
// Interpolates flow between OldIfaceValues[index][0] and NewIfaceValues[index][0]
return (1.0 - IfaceFrac)*q1 + IfaceFrac*q2;
}
- For node
index
, obtains the old and new flows and interpolates them withIfaceFrac
.
5.4 iface_getIfaceQual(index, pollut)
double iface_getIfaceQual(int index, int pollut)
{
// find j = IfacePolluts[pollut], then interpolate OldIfaceValues[index][j+1]
// and NewIfaceValues[index][j+1]
return ...
}
- Similarly interpolates pollutant concentration.
6. Saving Outflows
6.1 iface_saveOutletResults(reportDate, file)
void iface_saveOutletResults(DateTime reportDate, FILE* file)
{
// For each node i:
// if node is an outlet:
// write node ID, reportDate, flow, and pollutants to file
}
- Called at each reporting time in SWMM.
- Writes the node ID, date/time, flow, and each pollutant concentration.
6.2 openFileForOutput()
void openFileForOutput()
{
// open Foutflows.name for writing text
// write a header:
// "SWMM5 Interface File"
// project Title
// the ReportStep
// number of constituents: 1 + #pollutants
// each pollutant's ID & units
// number of nodes that are "outlets"
// each outlet node's name
// column headings
// if start date == report start date, save initial outflows
}
7. Reading Interface Inflows
7.1 openFileForInput()
void openFileForInput()
{
// open Finflows.name for reading
// check first line for "SWMM5"
// read IfaceStep
// read # of constituents (Flow + pollutants) => parse pollutant names
// read # of interface nodes => parse node names
// allocate memory for OldIfaceValues, NewIfaceValues
// readNewIfaceValues() => sets NewIfaceDate
// OldIfaceDate = NewIfaceDate
}
- The file is ASCII text, not binary. The first line must contain “SWMM5”.
IfaceFlowUnits
is set based on the textual units.- If we can’t find matching pollutants or nodes, we raise an error.
7.2 readNewIfaceValues()
void readNewIfaceValues()
{
// read lines for each interface node
// parse date/time (yr, mon, day, hr, min, sec)
// parse flow => convert to SWMM's flow units
// parse pollutant concentrations
// store them in NewIfaceValues[i]
// update NewIfaceDate from parsed date/time
}
- The interface file lines have a format like:
but is read ignoringNodeID Year Mon Day Hr Min Sec Flow Pollut1 Pollut2 ...
NodeID
since we already have node order established. - Finally,
NewIfaceDate
is updated to the date/time on that line.
7.3 setOldIfaceValues()
void setOldIfaceValues()
{
OldIfaceDate = NewIfaceDate;
copy NewIfaceValues[][] into OldIfaceValues[][]
}
- After a new set of data is read from file, the previous “new” values become the “old” ones for the next time step.
8. Checking for Outlet Nodes
int isOutletNode(int i)
{
// If dynamic wave, only outfalls are outlets
if (RouteModel == DW) return (Node[i].type == OUTFALL);
else return (Node[i].degree == 0);
}
- If using dynamic wave, only outfall nodes are considered “outlets.”
- Otherwise, a node with zero outflow links is an outlet.
9. Summary
iface.c
allows SWMM to read node flows & pollutant data from an external file, or write outflow results to an external file at each reporting interval.- Reading the inflows file:
- We parse a header to get time step, pollutants, node IDs, and store them in arrays.
- We read lines for each node in order, each line representing a single time step’s data.
- We interpolate between the “old” and “new” data rows so that we can provide a continuous flow/time correlation to SWMM’s time steps.
- Writing outflows for outlet nodes:
- The output file is also textual.
- Each row contains date/time, node ID, flow, plus pollutant concentrations.
- This mechanism is how SWMM can couple with other models (e.g., to provide boundary conditions or to export results).
No comments:
Post a Comment