Saturday, December 28, 2024

Summary of exfil.c in EPA SWMM5

 Below is a step‐by‐step explanation of how exfil.c in EPA SWMM5 processes exfiltration for storage units. The main idea is to handle infiltration (seepage) from the base and sloped banks of a storage node into the surrounding soil—using either a simple constant exfiltration rate or a Green‐Ampt approach.


1. Overview: Storage Node Exfiltration in SWMM

  • Storage nodes can lose water through their bottom and sidewalls. This is called exfiltration.

  • SWMM provides the option for:

    1. Constant infiltration (Ksat) – If you only specify a saturated hydraulic conductivity.
    2. Green–Ampt infiltration – If you provide suction head, saturated hydraulic conductivity, and initial moisture deficit (IMD).
  • The Green-Ampt formulation is the same as used for subcatchments, except it’s applied to the bottom and bank areas of a storage node.


2. Key Data Structures

  1. TExfil

    • Found in exfil.h, this struct holds two TGrnAmpt objects:
      • btmExfil: infiltration parameters for the bottom of the storage unit.
      • bankExfil: infiltration parameters for the banks (sloped side).
    • Also stores btmArea, bankMinDepth, bankMaxDepth, bankMaxArea—the geometry parameters describing the bottom area and side areas.
  2. Storage[k].exfil

    • Each storage node k has an optional pointer exfil to a TExfil. If non-NULL, we can compute infiltration through it.
  3. TGrnAmpt

    • Data structure for Green-Ampt infiltration parameters (suction head, Ks, IMDmax), plus state variables tracking how much infiltration has occurred so far.

3. Function-by-Function Explanation

3.1 exfil_readStorageParams(...)

int exfil_readStorageParams(int k, char* tok[], int ntoks, int n)
  • Reads exfiltration parameters from an input line for storage node k.
  • Tokens might contain:
    • Just one value (Ksat).
    • Or three values (suction head, Ksat, IMDmax) for Green-Ampt infiltration.
  • Steps:
    1. Checks how many tokens remain after n.
    2. If only one token, it interprets it as the saturated conductivity Ksat.
    3. Else, it reads three tokens as suction head, Ksat, and IMDmax.
    4. If Ksat = 0.0, no exfiltration is created (returns 0).
    5. Otherwise, it calls createStorageExfil(...) to actually build a TExfil object and store these parameters.

Why: This parses the user’s input for infiltration/exfiltration parameters and decides if infiltration is constant or if we use a Green-Ampt approach.


3.2 exfil_initState(...)

void exfil_initState(int k)
  • Called at the start of a simulation (or re-initialization) for a storage node k.

  • What it does:

    1. If Storage[k].exfil is not NULL, it calls grnampt_initState on both btmExfil and bankExfil to reset infiltration states (like cumulative infiltration, wetting front depth, etc.).

    2. Determines the geometry of the bottom area and bank area depending on the storage shape:

      • TABULAR shape:

        • Uses the user-defined “Storage Curve” in Curve[i].
        • Looks up area at 0 ft depth to get the bottom area.
        • Then scans the table entries to find the “bank” min depth, max depth, and max area.
        • Converts these from user units to internal units.
      • FUNCTIONAL shape:

        • btmArea = Storage[k].a0 plus optionally a1 if a2 = 0.0.
        • No real max depth or max area, so sets them to BIG.
      • CYLINDRICAL, CONICAL, PYRAMIDAL shapes:

        • btmArea = a0, sets bank depth/area to BIG.
  • Why: This sets up the baseline geometry—bottom area used for infiltration, plus the range of depths/areas for the “banks” infiltration.


3.3 exfil_getLoss(...)

double exfil_getLoss(TExfil* exfil, double tStep, double depth, double area)
  • Main infiltration logic: how much water exfiltrates (cfs) in the current time step.
  • Steps:
    1. Bottom infiltration:
      • If IMDmax == 0, we assume a constant infiltration rate = Ksat * Adjust.hydconFactor.
        • Adjust.hydconFactor is a monthly/temperature adjustment for hydraulic conductivity.
      • Else, calls grnampt_getInfil(...) with the bottom infiltration parameters to get the infiltration rate (ft/s).
      • Multiply that infiltration rate by exfil->btmArea to get a flow (cfs).
    2. Bank infiltration (for side slopes):
      • Only if water depth > exfil->bankMinDepth.
      • The bank area is min(area, exfil->bankMaxArea) - btmArea.
        • i.e., total water surface area minus the bottom area, but capped at bankMaxArea.
      • If IMDmax == 0, infiltration is just area × Ksat.
      • Else, we approximate the average depth above the bank using either:
        • If actual depth > bankMaxDepth, we do depth = depth - bankMaxDepth + (bankMaxDepth - bankMinDepth)/2.
        • If below top of bank, depth = (depth - bankMinDepth)/2.
      • Then calls grnampt_getInfil(...) again with bankExfil parameters and multiplies by the side bank area.
    3. Returns the total exfiltration rate (cfs).

Why: A storage node can have infiltration from both the bottom and the side banks, and the code uses Green-Ampt or constant infiltration to estimate these losses.


3.4 createStorageExfil(...)

int createStorageExfil(int k, double x[])
  • Builds a new TExfil object for storage node k.
  • Steps:
    1. Allocates memory for TExfil if not already created.
    2. Allocates two TGrnAmpt objects: one for bottom infiltration, one for bank infiltration.
    3. Calls grnampt_setParams(...) on both with the array x[] (suction head, Ksat, IMDmax).
    4. If memory allocation fails, sets error code.
  • Why: This is how SWMM sets up the infiltration (exfiltration) mechanism for a particular storage node.

4. Putting It All Together

  1. Reading Input: The user’s input line for a storage node might say “Green-Ampt parameters” or just a single Ksat. SWMM calls exfil_readStorageParams(...), which might create a TExfil if Ksat > 0.
  2. Initialization: During exfil_initState(...), we determine the bottom area and potential bank area for infiltration, set initial infiltration states to zero, etc.
  3. Every Time Step:
    • For each storage node with an exfil object, SWMM calls exfil_getLoss(...) to compute infiltration outflow.
    • That infiltration rate is subtracted from the water volume in the node, thus lowering the node’s depth over time.

The net effect is that storage nodes in SWMM can slowly lose water into the ground, either with a constant infiltration or a Green–Ampt infiltration approach that depends on soil suction, conductivity, and moisture deficit—applied separately to bottom and bank areas.


5. Key Highlights & Design Choices

  1. Two Infiltration Regions

    • Bottom: Horizontal infiltration area.
    • Banks: Sloped infiltration area, which might vary with water depth.
  2. Green‐Ampt vs. Constant

    • If IMDmax == 0.0, infiltration is simply constant Ksat × area.
    • Otherwise, the modified Green–Ampt approach is used.
  3. Monthly/Temperature Adjustments

    • Adjust.hydconFactor is a multiplier that can be changed monthly in SWMM’s advanced settings (e.g., water temperature effect on viscosity/conductivity).
  4. Shapes

    • For TABULAR storage shapes, the curve can show how cross-sectional area increases with depth—this code identifies the “bottom area” at depth = 0 and the portion of the surface area that could be considered “bank.”
  5. Performance

    • Everything is done each time step for each storage node. This approach is straightforward but must be carefully handled if many storage nodes exist.

Overall, exfil.c is the part of SWMM that converts infiltration input parameters into actual water losses from storage nodes, integrating a Green‐Ampt infiltration model (or a simpler Ksat-based approach) into the dynamic routing of stored water.

No comments:

SWMM5 Delphi GUI Dbackdrp.pas Summary

 The Dbackdrp unit provides a dialog form for selecting a backdrop image for the study area map within the SWMM (Storm Water Management Mod...