Saturday, December 28, 2024

SWMM5 iface.c Summary

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 or Foutflows.

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() if Foutflows.mode == SAVE_FILE.
  • Calls openFileForInput() if Finflows.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 = currentDate - OldIfaceDateNewIfaceDate - OldIfaceDate\frac{\text{currentDate - OldIfaceDate}}{\text{NewIfaceDate - OldIfaceDate}} 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 with IfaceFrac.

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:
    NodeID Year Mon Day Hr Min Sec Flow Pollut1 Pollut2 ...
    
    but is read ignoring 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

  1. 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.
  2. 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.
  3. Writing outflows for outlet nodes:
    • The output file is also textual.
    • Each row contains date/time, node ID, flow, plus pollutant concentrations.
  4. This mechanism is how SWMM can couple with other models (e.g., to provide boundary conditions or to export results).

No comments:

A comprehensive explanation of how minimum travel distance relates to link length in InfoSewer

In hydraulic modeling of sewer networks, the minimum travel distance is a fundamental parameter that affects how accurately the model can si...