Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Addresses Issue #139 -- Code for inlets does not account for submergence #195

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions src/solver/dynwave.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//
// Project: EPA SWMM5
// Version: 5.2
// Date: 07/13/23 (Build 5.2.4)
// Date: 09/01/23 (Build 5.2.5)
// Author: L. Rossman
// M. Tryby (EPA)
// R. Dickinson (CDM)
Expand Down Expand Up @@ -47,6 +47,9 @@
// Build 5.2.4:
// - Conduit evap+seepage outflow split evenly between outflow from
// conduit's upstream and non-outfall downstream nodes.
// Build 5.2.5:
// - Modified setNodeDepth() so that Inlet receptor nodes don't surcharge
// and don't flood.
//-----------------------------------------------------------------------------
#define _CRT_SECURE_NO_DEPRECATE

Expand Down Expand Up @@ -678,7 +681,10 @@ void setNodeDepth(int i, double dt)
{
// --- ponded nodes don't surcharge
if (isPonded) isSurcharged = FALSE;


// --- street inlet capture nodes don't surcharge
else if (Node[i].inlet == CAPTURE) isSurcharged = FALSE;

// --- closed storage units that are full are in surcharge
else if (Node[i].type == STORAGE)
{
Expand Down Expand Up @@ -745,7 +751,8 @@ void setNodeDepth(int i, double dt)

// --- determine max. non-flooded depth
yMax = Node[i].fullDepth;
if ( canPond == FALSE ) yMax += Node[i].surDepth;
if (Node[i].inlet == CAPTURE) yMax += BIG;
else if ( canPond == FALSE ) yMax += Node[i].surDepth;

// --- find flooded depth & volume
if ( yNew > yMax )
Expand Down
119 changes: 108 additions & 11 deletions src/solver/inlet.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//
// Project: EPA SWMM5
// Version: 5.2
// Date: 07/13/23 (Build 5.2.4)
// Date: 09/01/23 (Build 5.2.5)
// Author: L. Rossman
//
// Street/Channel Inlet Functions
Expand All @@ -22,6 +22,8 @@
// - Fixed expression for equivalent gutter slope in getCurbInletCapture.
// - Corrected sign in equation for effective head in a curb inlet
// with an inclined throat opening in getCurbOrificeFlow.
// Build 5.2.5:
// - Modified how backflow through submerged inlets is calculated.
//-----------------------------------------------------------------------------
#define _CRT_SECURE_NO_DEPRECATE

Expand Down Expand Up @@ -252,6 +254,9 @@ static double getCurbOrificeFlow(double flowDepth, double openingHeight,
double openingLength, int throatAngle);
static double getOnSagSlottedFlow(int inletIndex, double depth);

static double getDepthAboveInlet(TInlet* inlet, double depth);
static double getOnGradeSubmergedCapturedFlow(TInlet* inlet, double flow, int j, int m);

//=============================================================================

int inlet_create(int numInlets)
Expand Down Expand Up @@ -563,7 +568,7 @@ void inlet_findCapturedFlows(double tStep)
// set but before a flow routing step has been taken.
{
int i, j, m, placement;
double q;
double q, qc;
TInlet *inlet;

// --- For non-DW routing find conduit flow into each node
Expand Down Expand Up @@ -593,30 +598,49 @@ void inlet_findCapturedFlows(double tStep)
if (InletDesigns[inlet->designIndex].type == CUSTOM_INLET)
{
q = fabs(Link[i].newFlow);
inlet->flowCapture = getCustomCapturedFlow(inlet, q, Node[j].newDepth);
qc = getCustomCapturedFlow(inlet, q, Node[j].newDepth);
}

// --- find flow captured by on-grade inlet
else if (placement == ON_GRADE)
{
q = fabs(Link[i].newFlow);
inlet->flowCapture = getOnGradeCapturedFlow(inlet, q, Node[j].newDepth);
// --- special case for submerged inlet under DW flow routing
if (RouteModel == DW &&
Node[m].invertElev + Node[m].newDepth >= Node[j].invertElev)
qc = getOnGradeSubmergedCapturedFlow(inlet, q, j, m);
else
qc = getOnGradeCapturedFlow(inlet, q, Node[j].newDepth);
}

// --- find flow captured by on-sag inlet
else
{
q = Node[j].inflow;
inlet->flowCapture = getOnSagCapturedFlow(inlet, q, Node[j].newDepth);
qc = getOnSagCapturedFlow(inlet, q, Node[j].newDepth);
}
if (fabs(inlet->flowCapture) < FUDGE) inlet->flowCapture = 0.0;
if (fabs(qc) < FUDGE) qc = 0.0;

// --- add to total flow captured by inlet's node
InletFlow[j] += inlet->flowCapture;
InletFlow[j] += qc;

// --- under DW flow routing, negative qc means there was
// backflow from capture node to bypass node
if (RouteModel == DW)
{
inlet->backflow = 0.0;
inlet->flowCapture = 0.0;
if (qc < 0.0) inlet->backflow = -qc;
else inlet->flowCapture = qc;
}
// --- otherwise capture node's overflow becomes inlet's backflow
else
{
inlet->flowCapture = qc;
inlet->backflow = Node[m].overflow * inlet->backflowRatio;
if (fabs(inlet->backflow) < FUDGE) inlet->backflow = 0.0;
}

// --- capture node's overflow becomes inlet's backflow
inlet->backflow = Node[m].overflow * inlet->backflowRatio;
if (fabs(inlet->backflow) < FUDGE) inlet->backflow = 0.0;
}

// --- make second pass through each inlet
Expand All @@ -643,6 +667,7 @@ void inlet_findCapturedFlows(double tStep)
// node, and add any backflow to bypass node)
Node[j].newLatFlow -= (inlet->flowCapture - inlet->backflow);
Node[m].newLatFlow += inlet->flowCapture;
if (RouteModel == DW) Node[m].newLatFlow -= inlet->backflow;

// --- update inlet's performance if reporting has begun
if (getDateTime(NewRoutingTime) > ReportStart)
Expand Down Expand Up @@ -1595,13 +1620,17 @@ double getOnSagCapturedFlow(TInlet* inlet, double q, double d)
if (inlet->flowLimit > 0.0)
qMax = inlet->flowLimit;

// --- get effective water depth above inlet
d = getDepthAboveInlet(inlet, d);

// --- find nominal flow captured by inlet
qCaptured = getOnSagInletCapture(designIndex, fabs(d));

// --- find actual flow captured by the inlet
qCaptured *= inlet->clogFactor;
qCaptured = MIN(qCaptured, qMax);
qCaptured *= (double)totalInlets;
if (d < 0.0) qCaptured = -qCaptured;
return qCaptured;
}

Expand Down Expand Up @@ -1934,6 +1963,16 @@ double getCustomCapturedFlow(TInlet* inlet, double q, double d)
// --- curve is captured flow v. approach flow
if (Curve[c].curveType == DIVERSION_CURVE)
{
// --- Under DW flow routing, assume no capture when
// inlet becomes submerged
if (RouteModel == DW)
{
int m1 = Link[inlet->linkIndex].node2;
int m2 = inlet->nodeIndex;
if (Node[m2].invertElev + Node[m2].newDepth >=
Node[m1].invertElev) return 0.0;
}

// --- add up incrmental capture of each replicate inlet
for (j = 1; j <= inlet->numInlets; j++)
{
Expand All @@ -1950,10 +1989,68 @@ double getCustomCapturedFlow(TInlet* inlet, double q, double d)
// --- curve is captured flow v. downstream node depth
else if (Curve[c].curveType == RATING_CURVE)
{
d = getDepthAboveInlet(inlet, d);
qCaptured = inlet->numInlets * inlet->clogFactor *
table_lookupEx(&Curve[c], d * UCF(LENGTH)) / UCF(FLOW);
table_lookupEx(&Curve[c], fabs(d) * UCF(LENGTH)) / UCF(FLOW);
if (d < 0.0) qCaptured = -qCaptured;
}
qCaptured *= sides;
}
return qCaptured;
}

//=============================================================================

double getDepthAboveInlet(TInlet* inlet, double d)
//
// Input: inlet = an inlet object placed in a conduit link
// d = water depth at conduit's bypass node (ft)
// Output: returns the effective water depth above bypass node (ft)
// Purpose: finds the net water depth at an inlet's bypass node
// that accounts for capture node's HGL.
//
{
if (RouteModel == DW)
{
// --- street & sewer node indexes
int i = inlet->linkIndex;
int j = Link[i].node2;
int m = inlet->nodeIndex;

// --- street & sewer node HGLs
double h1 = Node[j].invertElev + d;
double h2 = Node[m].invertElev + Node[m].newDepth;

// --- effective water depth above inlet
if (h2 < h1) d = h1 - MAX(h2, Node[j].invertElev);
else d = h1 - h2;
}
return d;
}
//=============================================================================

double getOnGradeSubmergedCapturedFlow(TInlet* inlet, double q, int j, int m)
//
// Input: inlet = an inlet object placed in a conduit link
// q = flow in link prior to any inlet capture (cfs)
// j = index of the inlet's street bypass node
// m = index of the inlet's sewer capture node
// Output: returns captured flow rate (cfs)
// Purpose: finds the flow captured by an on-grade inlet when sewer node
// HGL reaches street level.
//
{
double h1 = Node[j].invertElev + Node[j].newDepth; // street node HGL
double h2 = Node[m].invertElev + Node[m].newDepth; // sewer node HGL

// --- street can still send captured flow to sewer
if (h2 < h1) //
{
double q1 = getOnSagCapturedFlow(inlet, q, Node[j].newDepth);
double q2 = getOnGradeCapturedFlow(inlet, q, Node[j].newDepth);
return MIN(q1, q2);
}

// --- sewer sends backflow onto street
else return getOnSagCapturedFlow(inlet, q, Node[j].newDepth);
}
Loading