'JFergus: here it is! Not the best algorithm but works!
'It was a learning process
'VBA FUNCTIONS FOR PARTIAL FLOW IN CIRCULAR PIPE
Option Explicit
Global Const Pi = 3.141592654
Function radFt(diaFt As Double)
'radius in Feet
radFt = diaFt / 2
End Function
Function circm(diaFt As Double)
'circumference
circm = Pi * diaFt
End Function
Function area(diaFt As Double)
'Cross sectional area
area = Pi * diaFt * diaFt / 4
End Function
Function theta(diaFt As Double, Y As Double)
'theta radians = half of angle at the center
'y = partial fill depth
Dim R As Double
R = radFt(diaFt)
'Four possibilities
'case 1: y<R
If Y < R Then
theta = Atn((diaFt * Y - Y * Y) ^ (0.5) / (R - Y))
Else
'case 2: y=R
If Y = R Then
theta = Pi / 2
Else
'case 3: 2R>y>R
If Y > R And Y < diaFt Then
theta = Pi + Atn((diaFt * Y - Y * Y) ^ (0.5) / (R - Y))
Else
'case 4: y>=2R
theta = Pi
End If
End If
End If
End Function
Function wetP(diaFt As Double, Y As Double)
'Wetted Perimeter
wetP = theta(diaFt, Y) * diaFt
End Function
Private Function tArea(diaFt As Double)
'cross sectional area
'also defined earlier as area()
tArea = Pi * diaFt * diaFt / 4
End Function
Function flowArea(diaFt As Double, Y As Double)
'Partial Flow Area
Dim R As Double
R = radFt(diaFt)
Dim sect As Double 'sectoral area
Dim tri As Double 'triangular area
sect = theta(diaFt, Y) * tArea(diaFt) / (Pi)
tri = Abs(R - Y) * (Abs(Y * diaFt - Y * Y)) ^ 0.5
'Four conditions
If Y < R Then
flowArea = sect - tri
Else
If Y = R Then
flowArea = sect
Else
If Y > R And Y < diaFt Then
flowArea = sect + tri
Else
'If y >= diaFt Then flowArea = sect
flowArea = sect
End If
End If
End If
End Function
Function hydR(diaFt As Double, Y As Double)
'Hydraulic Radius
If Y = 0 Then
hydR = 0
Else
hydR = flowArea(diaFt, Y) / wetP(diaFt, Y)
End If
End Function
Function fullQ(diaFt As Double, n As Double, s As Double)
'Full bore flow using Manning's Eqn
'Unit cfs
fullQ = 1.486 / n * tArea(diaFt) * (diaFt / 4) ^ (2 / 3) * s ^ 0.5
End Function
Function partialQ(diaFt As Double, Y As Double, n As Double, s As Double)
'Partially filled flows as open channel
'Manning's Eqn
'Unit cfs
partialQ = 1.486 / n * flowArea(diaFt, Y) * hydR(diaFt, Y) ^ (2 / 3) * s ^ 0.5
End Function
Function topWid(diaFt As Double, Y As Double)
'Top free surface width
Dim R As Double
R = radFt(diaFt)
'Four cases
If Y <= R Then
topWid = 2 * (R ^ 2 - (R - Y) ^ 2) ^ 0.5
Else
If Y > R And Y < diaFt Then
topWid = 2 * (Y * diaFt - Y * Y) ^ 0.5
Else
'If y > diaFt Then topWid = 0
topWid = 0
End If
End If
End Function
Function vel(diaFt As Double, Y As Double, n As Double, s As Double)
'Velocity for a particular depth for partial Flow
If Y = 0 Then
vel = 0
Else
vel = partialQ(diaFt, Y, n, s) / flowArea(diaFt, Y)
End If
End Function
Function Froude(diaFt As Double, Y As Double, n As Double, s As Double)
'Froude's Number for a given depth of flow
'Froude=partialQ^2*topWid/32.2/flowArea^3
Dim Q As Double
Dim T As Double
Dim a As Double
Q = partialQ(diaFt, Y, n, s) 'Partial Flow
T = topWid(diaFt, Y)
a = area(diaFt)
Froude = Q ^ 2 * T / a ^ 3 / 32.2
End Function
Function yNormal(diaFt As Double, n As Double, s As Double, givenQ As Double)
'How to converge on the answer fast?
'Normal Depth for a given flow Q
'Unit is Feet
Dim Y As Double 'Trial y
Dim calcQ As Double 'calculated Q
Dim loopCount As Double 'erase later
Dim errorQ As Double
errorQ = 0.001
Dim yMax As Double
Dim yMin As Double
yMax = diaFt 'initial assumption
yMin = 0 'initial assumption
Y = (yMax + yMin) / 2
'Normal depth has no meaning for pressurzied pipe
'Pressurized if givenQ > capacity
If givenQ > fullQ(diaFt, n, s) Then
Y = diaFt
'MsgBox "Pressurized Flow, exceeded open channel flow capacity" _
Else
Do While (Abs(partialQ(diaFt, Y, n, s) - givenQ) > errorQ)
loopCount = loopCount + 1
calcQ = partialQ(diaFt, Y, n, s)
'Three Conditions
'(calcQ>givenQ) or (calcQ<givenQ) or both equal
If calcQ = givenQ Then
'go out of loop
Else
If (calcQ > givenQ) Then
'y solution is smaller than y assumed
yMax = Y
yMin = yMin
Else
'y solution is greater than y assumed
yMax = yMax
yMin = Y
End If
Y = (yMax + yMin) / 2
End If
Loop
End If
'MsgBox "loopCount for yNormal = " & loopCount
yNormal = Y 'Return result
End Function
Function poly(diaFt As Double, anyQ As Double, assumedY As Double)
poly = flowArea(diaFt, assumedY) ^ 3 / topWid(diaFt, assumedY) - anyQ ^ 2 / 32.2
End Function
Function polySolve(P As Double, diaFt As Double, givenQ As Double)
'solve equation poly for P
' poly

=P: find y
Dim loopCount As Double
Dim Y As Double
Dim yMax As Double
Dim yMin As Double
Dim error As Double
'Initialize
error = 0.00001
yMax = diaFt
yMin = 0
Y = (yMax + yMin) / 2
If loopCount > 5000 Then
polySolve = 999 'flagging error
Else
Do While (Abs(poly(diaFt, givenQ, Y)) > error)
loopCount = loopCount + 1
If poly(diaFt, givenQ, Y) > 0 Then
yMax = Y
Else
yMin = Y
End If
Y = (yMax + yMin) / 2
Loop
End If
' MsgBox "loop count = " & loopCount
polySolve = Y
End Function
Function Froude1(diaFt As Double, yTest As Double, knownQ As Double)
'Used for yc calculation
'Froude1: Froude Number for given dia, known Q but test depth
'only to be called by function to calculate the critical depth
Froude1 = (knownQ ^ 2 * topWid(diaFt, yTest) / flowArea(diaFt, yTest) ^ 3 / 32.2) ^ (0.5)
End Function
Public Function yc(diaFt As Double, knownQ As Double)
'better use this to calc critical depth
Dim max As Double
Dim min As Double
Dim yTry As Double
Dim loopCount As Integer
max = diaFt
min = 0
yTry = (max + min) / 2
If knownQ <= 0 Then
yc = 0
Else
Do While (Abs(Froude1(diaFt, yTry, knownQ) - 1) > 0.000001) And loopCount < 100
loopCount = loopCount + 1
If Froude1(diaFt, yTry, knownQ) < 1 Then
max = yTry
Else
min = yTry
End If
yTry = (max + min) / 2
Loop
'MsgBox "loop count = " & loopCount
yc = yTry
End If
End Function
Sub examples()
Dim msg As String
'example 1
msg = "Full Flow example 1 = " & fullQ(1.5, 0.013, 0.027) & " cfs"
MsgBox msg
msg = "Partial Flow example 2 = " & partialQ(1.5, 0.5, 0.013, 0.027) & " cfs"
MsgBox msg
msg = "Froude# example 3 = " & Froude(1.5, 0.6, 0.013, 0.035)
MsgBox msg
msg = "Velocity example 4 = " & vel(1.5, 0.5, 0.013, 0.027) & " ft/sec"
MsgBox msg
End Sub