Saturday, December 28, 2024

SWMM5 Culvert Code

Below is a step‐by‐step explanation of what this culvert.c file does, how the code is organized, and how it applies FHWA HEC‐5 culvert equations within SWMM5 to adjust flows under inlet‐control conditions. The goal is to show you how each part of the code works together to compute reduced flow due to culvert inlet control.


1. Purpose of the File

  • culvert.c is part of EPA SWMM5 (Storm Water Management Model), specifically focusing on culvert inlet control.
  • It implements FHWA HEC‐5 equations to reduce flow (relative to normal conduit flow) when a pipe or box conduit is operating under inlet control (i.e., the entrance shape and headwater conditions dominate how much water can flow through it).

Key point: under certain flow conditions (especially at high heads or shallow flows at the inlet), the effective capacity of a culvert can be reduced compared to its full conveyance capacity.


2. High-Level Flow of the Code

  1. When SWMM’s routing engine calculates flow through a conduit, it calls culvert_getInflow(...) if that conduit is flagged as a culvert.
  2. culvert_getInflow(...) checks if inlet control conditions exist by comparing the raw hydraulic flow (q0) to a flow derived from the FHWA culvert equations.
  3. If the FHWA culvert flow is less than the normal flow (q0), the code sets the flow to the lower inlet‐controlled flow, thereby “reducing” the flow to reflect inlet constraints.

3. Data Structures & Parameters

3.1 The Params Array

static const double Params[58][5] = {
    //   FORM   K       M     C        Y
    // ----------------------------------
    {0.0, 0.0,    0.0,  0.0,    0.00},
    ...
    {2.0, 0.500, 0.667, 0.0378, 0.71}
};
  • Each row in Params corresponds to a culvert type (e.g., circular concrete, corrugated metal pipe, box culvert with beveled edges, etc.).
  • There are five columns (indexed by the enum CulvertParam {FORM, K, M, C, Y}):
    • FORM – A flag (1 or 2) that indicates which inlet equation form to use.
    • K, M – Empirical coefficients for unsubmerged flow (FHWA: head‐discharge relationships).
    • C, Y – Empirical coefficients for submerged flow.

When a user configures a conduit as a culvert in SWMM, a “culvert code” (1 to 57) is assigned. That code indexes into Params[] and selects the correct (FORM, K, M, C, Y) for that culvert shape/entrance type.

3.2 The TCulvert Struct

typedef struct
{
    double  yFull;    // full depth
    double  scf;      // slope correction factor
    double  dQdH;     // derivative dQ/dH
    double  qc;       // critical flow found in iterative solution
    double  kk;       
    double  mm;       // coefficients for unsubmerged flow
    double  ad;       
    double  hPlus;    
    TXsect* xsect;    // pointer to cross section geometry
} TCulvert;
  • yFull is the full depth of the culvert.
  • scf is a slope correction factor used by some culvert equations.
  • dQdH is the derivative of flow wrt head (used in SWMM’s solver).
  • qc is an intermediate variable storing “critical flow” during an iterative solution.
  • kk, mm are assigned from the table (the K, M parameters).
  • ad is typically aFull * sqrt(yFull), used in dimensionless transformations.
  • hPlus is an intermediate expression used by “Equation Form 1.”
  • xsect is a pointer to the SWMM cross‐section object, giving methods to find area vs. depth, etc.

4. Primary Function: culvert_getInflow(...)

double culvert_getInflow(int j, double q0, double h)
  • Arguments:
    • j: The link index in SWMM’s data structures.
    • q0: The originally computed flow for that link (conduit) before applying inlet control.
    • h: The “head” at the inlet (in feet above the inlet invert).
  • Returns: The adjusted flow if inlet control is more restrictive than q0; otherwise returns q0.

4.1 Logic Flow in culvert_getInflow

  1. Check if this link is actually a culvert:

    code = culvert.xsect->culvertCode;
    if ( code <= 0 || code > MAX_CULVERT_CODE ) return q0;
    

    If there’s no valid culvert code, we do nothing.

  2. Initialize key variables:

    • culvert.yFull, culvert.ad, slope factor culvert.scf, etc.
    • Retrieve K, M, C, and Y for this culvert from Params[code].
  3. Compute the water depth y above the culvert’s inlet invert:

    y = h - (Node[Link[j].node1].invertElev + Link[j].offset1);
    

    This y can be bigger than the culvert’s full depth if the inlet is flooded.

  4. Check if flow is submerged or unsubmerged:

    • The code checks a threshold y2 for submerged flow:
      y2 = yFull * (16.0*C + Y - scf);
      if ( y >= y2 ) q = getSubmergedFlow(...);
      
    • Else if y is well below full depth, do unsubmerged:
      y1 = 0.95 * yFull;
      if ( y <= y1 ) q = getUnsubmergedFlow(...);
      else q = getTransitionFlow(...);  // if between y1 & y2
      
  5. Compare the culvert-limited flow q with the unconstrained flow q0:

    if ( q < q0 )
    {
        Link[j].inletControl = TRUE;  
        Link[j].dqdh = culvert.dQdH;   
        return q;
    }
    else return q0;
    
    • If the culvert’s inlet flow capacity q is smaller, SWMM sets the link to “inletControl = TRUE,” updates the derivative dqdh, and uses q.
    • Otherwise, we leave it at q0.

5. Supporting Functions

5.1 getUnsubmergedFlow(...)

  • Purpose: For shallow (unsubmerged) flow, compute flow using either Equation Form 1 or a simpler power law:
    if (Params[code][FORM] == 1.0)
        q = getForm1Flow(h, culvert);
    else
        q = culvert->ad * pow( arg, 1.0/culvert->mm );
    
  • Stores dQdH = derivative of Q with respect to the inlet head h.

5.2 getSubmergedFlow(...)

  • Purpose: For deeper (submerged) flow, uses the C,Y relationship:
    arg = (h/yFull - Y + scf) / C;
    q = sqrt(arg) * culvert->ad;
    dQdH = 0.5 * q / arg / yFull / C;
    
  • This is a direct application of the HEC‐5 form for submerged inlets.

5.3 getTransitionFlow(...)

  • Purpose: If h is between an “unsubmerged” threshold (h1) and a “submerged” threshold (h2), it interpolates between the unsubmerged flow q1 and the submerged flow q2:
    q = q1 + (q2 - q1) * (h - h1)/(h2 - h1);
    dQdH = (q2 - q1)/(h2 - h1);
    
  • Provides a smooth transition between the two regimes.

5.4 getForm1Flow(...) & form1Eqn(...)

  • Form 1 is a specific FHWA equation that requires solving for a “critical depth” yc inside the culvert.
  • getForm1Flow(...):
    1. Sets culvert->hPlus = h / yFull + scf.
    2. Calls findroot_Ridder(...) (a numerical root‐finding routine) to solve the Form 1 equation for yc.
    3. Uses the resulting “critical flow” to produce a final flow value for the unsubmerged condition.
  • form1Eqn(...) is the function that the root‐finder uses to compute the error term of the equation: Equation Form 1: hyfull+scf2  =  ycyfull+yh2yfull+K(qcad)M \text{Equation Form 1: } \frac{h}{y_\text{full}} + \frac{scf}{2} \;=\; \frac{y_c}{y_\text{full}} + \frac{y_h}{2\,y_\text{full}} + K \left(\frac{q_c}{a_d}\right)^M where yhy_h is the “hydraulic depth” at critical depth, qcq_c is critical flow, etc.

6. Slope Correction Factor (scf)

The code uses a slope correction factor, scf, that depends on the culvert type:

switch (code)
{
  case 5:
  case 37:
  case 46: culvert.scf = -7.0 * Conduit[k].slope; break;
  default: culvert.scf = 0.5 * Conduit[k].slope;
}
  • Usually it’s 0.5 * slope.
  • For certain codes (e.g., “mitered inlets”), it uses -7.0 * slope.

This factor modifies the head parameter in the FHWA formula so that the topography slope is accounted for in the final flow estimate.


7. Putting It All Together

  1. Identify the culvert code from the link’s cross‐section data structure.
  2. Lookup (FORM, K, M, C, Y) from the Params[] table.
  3. Compute if the inlet is unsubmerged or submerged, or in the transition region.
  4. Apply the appropriate flow equation (with possible iterative solution for Equation Form 1).
  5. Compare the result to the normal flow q0. If the culvert flow is lower, use it; otherwise remain with q0.

Essentially, SWMM’s normal conduit calculations do not by themselves account for inlet geometry constraints. This code ensures that when the wet‐well or upstream node is at certain depths, the flow is limited by the culvert entrance shape—matching the real‐world phenomenon that many culvert inlets cannot pass full pipe flow at certain depths.


8. Key Takeaways

  • HEC‐5 Inlet Control: The code implements standard FHWA formulas for different culvert shapes and entrance conditions.
  • Parameter Table: Each entrance type has empirical coefficients that define how flow is reduced under inlet control (K, M, C, Y, plus a “FORM” flag for different equations).
  • Flow Regimes: Unsubmerged, submerged, or transitional.
  • Root Finding: For “Form 1,” an iterative solution is needed to find critical depth.
  • Integration with SWMM: This code runs only if a user has assigned a “culvert code” to a conduit. If the inlet control flow is less than the normally‐computed flow, SWMM overrides with the inlet‐controlled flow and flags that link as inletControl = TRUE.

This ensures that SWMM accurately simulates culvert hydraulics where the inlet, rather than the downstream barrel capacity, is the limiting factor.

No comments:

SWMM5 Delphi GUI Dabout.pas Summary

 The Dabout.pas unit is part of the EPA SWMM (Storm Water Management Model) project and contains the logic for the "About" dialo...