Saturday, December 28, 2024

SWMM5 Forcemain.c Summary

Below is an explanation of what each function in forcemain.c does, why it’s there, and how it fits into SWMM’s hydraulic calculations for pressurized force mains. This file handles Hazen-Williams and Darcy-Weisbach friction equations under force main conditions—i.e., when pipes are pressurized and do not follow standard Manning’s equation.


1. Background: Force Mains in SWMM

  • In typical open-channel flow, SWMM uses Manning’s equation to model headloss.

  • However, a force main is a pressurized conduit (often from a pump), where flow is not necessarily open-channel. In that scenario, many engineers use:

    • Hazen-Williams equation (common in North America for water distribution), or
    • Darcy-Weisbach equation (a more universal approach, used in many hydraulic contexts).
  • SWMM’s user can choose either Hazen-Williams (H_W) or Darcy-Weisbach (D_W) for force mains. The code in forcemain.c provides the specialized calculations for friction losses, Reynolds number, friction factors, etc.


2. The Main Functions

2.1 forcemain_getEquivN(...)

double forcemain_getEquivN(int j, int k)

Purpose: Computes an “equivalent Manning’s n” for a force main flowing full under fully turbulent conditions, using the user’s chosen equation (Hazen-Williams or Darcy-Weisbach).

  1. Inputs:
    • j = link index in SWMM’s data structures
    • k = conduit index
    • The conduit’s geometry is accessed via Link[j].xsect and Conduit[k].
  2. Logic:
    • If Hazen-Williams:
      return 1.067 / xsect.rBot * pow(d/Conduit[k].slope, 0.04);
      
      • d is yFull (full diameter or full depth).
      • xsect.rBot here is repurposed to store the Hazen-Williams “C” factor.
      • The constant 1.067 and exponent 0.04 come from deriving an approximate equivalence between Hazen-Williams and Manning’s formula when the pipe is completely full.
    • If Darcy-Weisbach:
      f = forcemain_getFricFactor(xsect.rBot, d/4.0, 1.0e12);
      return sqrt(f/185.0) * pow(d, (1./6.));
      
      • xsect.rBot is used here to store the roughness height (e) for Darcy-Weisbach.
      • It calls forcemain_getFricFactor(...) with re = 1.0e12—effectively a giant Reynolds number—to ensure fully turbulent regime.
      • Then it converts that friction factor into an “equivalent Manning’s n.”
    • If neither (i.e., normal Manning’s is used), it just returns the conduit’s normal roughness.
  3. Why do this?
    • Internally, SWMM might do normal flow checks or partial flow logic that sometimes calls on Manning’s equation. This function helps “fake” a Manning’s n that yields the same full-flow result as Hazen-Williams or Darcy-Weisbach.

2.2 forcemain_getRoughFactor(...)

double forcemain_getRoughFactor(int j, double lengthFactor)

Purpose: Computes an adjustment factor for the pipe’s roughness that compensates for any artificial lengthening the user or the model might impose. Sometimes, a pipe is artificially lengthened to maintain stability in the SWMM solver (i.e., if a pipe is too short, you might virtually lengthen it but keep the slope the same).

  1. Inputs:
    • j = link index
    • lengthFactor = factor by which a pipe is “artificially lengthened.” (If the pipe length is doubled artificially, lengthFactor might be 2.0.)
  2. Logic:
    • If Hazen-Williams (H_W):
      r = 1.318*xsect.rBot*pow(lengthFactor, 0.54);
      return GRAVITY / pow(r, 1.852);
      
      • xsect.rBot is the Hazen-Williams C-factor again.
      • The 1.318 and exponents 0.54, 1.852 come from the Hazen-Williams formula.
    • If Darcy-Weisbach (D_W):
      return 1.0/8.0/lengthFactor;
      
      • This modifies the friction factor for the artificial length.
  3. Why do this?
    • If you artificially lengthen a pipe, you need to adjust the friction or roughness so that the final headloss is physically consistent with the original “real” pipe.

2.3 forcemain_getFricSlope(...)

double forcemain_getFricSlope(int j, double v, double hrad)

Purpose: Computes the headloss per unit length (i.e., friction slope SfS_f) in the dynamic wave flow routing for a pressurized force main. It uses either Hazen-Williams or Darcy-Weisbach, depending on ForceMainEqn.

  1. Inputs:
    • j = link index
    • v = flow velocity (ft/s)
    • hrad = hydraulic radius (ft) (for a full pipe, hrad = diameter/4, but if partially pressurized, might differ).
  2. Logic:
    • If Hazen-Williams:
      return xsect.sBot * pow(v, 0.852) / pow(hrad, 1.1667);
      
      • The code previously stored a “roughness factor” in xsect.sBot (during conduit validation), so that it can just multiply by v^0.852 / hrad^1.1667.
    • If Darcy-Weisbach:
      re = forcemain_getReynolds(v, hrad);
      f = forcemain_getFricFactor(xsect.rBot, hrad, re);
      return f * xsect.sBot * v / hrad;
      
      • First calculates Reynolds number.
      • Then obtains the friction factor f.
      • Then friction slope = f * sBot * (v / hrad).
  3. Why do this?
    • SWMM’s dynamic wave solver needs friction slope (or friction headloss per length) at each time step. This is the crux of how SWMM calculates energy losses in pressure flow.

2.4 forcemain_getReynolds(...)

double forcemain_getReynolds(double v, double hrad)

Purpose: Computes the flow’s Reynolds number:

Re=4×(hydraulic radius)×vν\text{Re} = \frac{4 \times \text{(hydraulic radius)} \times v}{\nu}

Here, ν=VISCOS=1.1×105ft2/s\nu = \text{VISCOS} = 1.1 \times 10^{-5} \,\text{ft}^2/\text{s} is the kinematic viscosity of water at 20°C.

  1. Formula:
    return 4.0 * hrad * v / VISCOS;
    
  2. Why: Reynolds number tells us if the flow is laminar, transitional, or turbulent, which the code then uses to pick the right friction factor formula.

2.5 forcemain_getFricFactor(...)

double forcemain_getFricFactor(double e, double hrad, double re)

Purpose: Computes the Darcy-Weisbach friction factor ff for a force main using the Swamee-Jain approximation to the Colebrook-White equation.

  1. Inputs:
    • e: the roughness height (ft). In SWMM, this might be set by the user or derived from the “rBot” for Darcy-Weisbach.
    • hrad: hydraulic radius.
    • re: Reynolds number.
  2. Logic:
    • Check for extremely low Re: if re < 10.0, set re = 10.0 artificially.
    • Laminar regime (Re <= 2000):
      f = 64.0 / re;
      
    • Transitional (2000 < Re < 4000):
      // recursively calls forcemain_getFricFactor with re=4000, then
      // linearly blend from f=0.032 up to that friction factor
      
      Actually, the code calls itself for Re=4000, gets that friction factor, and does a linear interpolation.
    • Turbulent (Re >= 4000):
      f = e/3.7/(4.0*hrad);
      if (re < 1.0e10) f += 5.74/pow(re, 0.9);
      f = log10(f);
      f = 0.25 / (f*f);
      
      • This is the Swamee-Jain formula: f=0.25/[log10(e/(3.7D)+5.74Re0.9)]2f = 0.25 \Big/ \Big[\log_{10}\big(\frac{e/(3.7 D)} + \frac{5.74}{Re^{0.9}}\big)\Big]^2 but here D is approximated as 4 * hrad if it’s a circular pipe.
  3. Why:
    • The friction factor is crucial for Darcy-Weisbach calculations. The Swamee-Jain approximation is a direct (non-iterative) way to estimate friction factor from Colebrook-White.

3. Putting It All Together

  1. Selecting Equation:

    • SWMM’s global setting ForceMainEqn is either H_W (Hazen-Williams) or D_W (Darcy-Weisbach).
    • Each force main (pressurized conduit) is flagged to use one or the other.
  2. During Simulation:

    1. Initialization:
      • SWMM calls forcemain_getEquivN() at validation time to store a stand-in Manning’s n for certain normal-flow checks.
      • It also calls forcemain_getRoughFactor(...) to store the pipe’s friction coefficient in xsect.sBot.
    2. Every Time Step (Dynamic Wave):
      • SWMM calculates velocity v, hydraulic radius hrad, etc.
      • Then calls forcemain_getFricSlope(...) to get friction slope, which goes into the momentum equation.
      • Inside that function, if Darcy-Weisbach is chosen, the code calls:
        • forcemain_getReynolds(...) to get Re,
        • forcemain_getFricFactor(...) for Darcy-Weisbach’s friction factor.
      • This friction slope is used in the St. Venant equations for unsteady flow.
  3. Result:

    • The code ensures force main headloss is modeled with either H-W or D-W.
    • The user sees more accurate pressurized-flow behavior than if SWMM were just forcing a Manning’s formula.

4. Key Takeaways

  1. Hazen-Williams (H_W) vs. Darcy-Weisbach (D_W)

    • H_W: simpler, widely used in water distribution, but less general for different fluids/temperatures.
    • D_W: more universal, uses friction factor ff derived from roughness and Reynolds number (Colebrook-White/Swamee-Jain).
  2. Equivalent Manning’s n

    • Because SWMM’s internal logic often uses Manning-based checks, the code calculates a “fake n” that yields the same full-flow rate as the chosen force main formula under ideal conditions.
  3. Friction Factor

    • The code includes transitional laminar/turbulent handling.
    • Swamee-Jain is a closed-form approximation to Colebrook-White, avoiding iterative solutions for friction factor.
  4. Artificial Pipe Lengthening

    • The user can artificially lengthen a short pipe for numerical stability. The code corrects friction to preserve real-world headloss.

Overall, forcemain.c is the specialized module that overrides normal Manning’s friction for pressurized pipes in SWMM, using either Hazen-Williams or Darcy-Weisbach—complete with Reynolds-number-based friction factors—so that force mains in your model behave more realistically than if they used open-channel Manning’s equations.

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