Dissolved Oxygen Simulation


Lecture 08

September 11, 2023

Review and Questions

Last Class

  • Dissolved Oxygen: essential quantity for aquatic life
  • Minimum concentration regulated
  • Used mass-balance to derive first-order equation

Processes influencing oxygen balance in moving freshwater

DO Concentration Equation

\[\begin{align} \overbrace{U \frac{dC}{dx}}^{\text{Concentration Change}} &= \overbrace{k_a (C_s - C)}^{\text{Reaeration}} + \overbrace{P - R - S_B}^{\text{Constants}} \\[0.5em] &\quad - \underbrace{k_cB_0\exp\left(\frac{-k_cx}{U}\right)}_{\text{CBOD}} - \underbrace{k_n N_0\exp\left(\frac{-k_nx}{U}\right)}_{\text{NBOD}} \end{align}\]

Questions

Poll Everywhere QR Code

Text: VSRIKRISH to 22333

URL: https://pollev.com/vsrikrish

See Results

Dissolved Oxygen Simulation

Steady-State Mass-Balance Solution

\[\begin{align} C(x) &= C_s(1 - \alpha_1) + C_0 \alpha_1 - B_0 \alpha_2 - N_0 \alpha_3 + \left(\frac{P-R-S_B}{k_a}\right) (1-\alpha_1), \\[1em] \alpha_1 &= \exp\left(-\frac{k_a x}{U}\right) \\[0.25em] \alpha_2 &= \left(\frac{k_c}{k_a-k_c}\right)\left[\exp\left(\frac{-k_c x}{U}\right) - \exp\left(\frac{-k_ax}{U}\right)\right] \\[0.25em] \alpha_3 &= \left(\frac{k_n}{k_a-k_n}\right)\left[\exp\left(\frac{-k_n x}{U}\right) - \exp\left(\frac{-k_ax}{U}\right)\right] \end{align}\]

Steady-State Mass-Balance Solution

\[\begin{align} C(x) &= C_s(1 - \alpha_1) + C_0 \alpha_1 - B_0 \alpha_2 - N_0 \alpha_3 \\[0.5em] & \qquad + \left(\frac{P-R-S_B}{k_a}\right) (1-\alpha_1), \end{align}\]

Note: Usually, these models ignore \(P\), \(R\), and \(S_B\).

Why do you think that might be?

Dissolved Oxygen “Sag” Curve

Dissolved oxygen concentrations downstream of a waste release “sag” and then start to recover as CBOD and NBOD decrease.

Figure 1: Sag curve for dissolved oxygen.

How To Simulate

So far, this is only different from our single-box airshed in terms of the number of processes.

Single equation, straightforward to evaluate across many values of \(x\) with a loop.

x = 0:x_step:x_max # array from 0 to x_max in stepsize x_step

C = zeroes(length(x)) # initialize storage
for (i, y) in pairs(x)
    C[i] = dissolved_oxygen(y, parameters)
end

Julia Sidebar: Loop Alternatives

Loops in Julia are fast and should be used freely.

But there are some more concise alternatives, which may be more readable in some cases.

Julia Sidebar: Broadcasting

But some more concise alternatives (which may be more readable) include broadcasting:

x = 0:x_step:x_max # array from 0 to x_max in stepsize x_step

# evaluate DO function over every x with fixed parameters
C = (y -> dissolved_oxygen(y, parameters)).(x) 

Broadcasting gets finicky over multiple inputs.

Julia Sidebar: Comprehensions

…And comprehensions (in-line for loops, also in Python):

x = 0:x_step:x_max # array from 0 to x_max in stepsize x_step

# evaluate DO function over every x with fixed parameters
C = [dissolved_oxygen(y, parameters) for y in x]

Can “stack” the for loops in a comprehension to nest.

Julia Sidebar: When To Use Loops?

Think about readability and ease of debugging!

  • If your code is complex and not wrapped in a function, or you have several nested loops, you should use a loop (just be careful of scope…)
  • If your code is complex, may be worth asking if you should write a function instead and use broadcasting or a comprehension.

Single-Discharge Example

Parameter River Waste General
Volume (m3/d) 100,000 10,000
DO (mg/L) 6.4 4.2
CBOD (mg/L) 5 49
NBOD (mg/L) 5 27
\(C_s\) (mg/L) 7
\(k_a\), \(k_c\), \(k_n\) 0.8, 0.5, 0.4

Single-Discharge Example: Initial Condition

How do we find the initial state (\(x=0\))?

Need to compute the mixed concentrations of DO, CBOD, and NBOD (\(Q\) is the flow volume):

\[C_0 = C_\text{mixed} = \frac{C_\text{river} \times Q_\text{river} + C_\text{waste} \times Q_\text{waste}}{Q_\text{river} + Q_\text{waste}}\]

Single-Discharge Example: Initial Condition

So the initial values:

\[C_0 = 6.2 \ \text{mg/L}\]

\[B_0 = 9 \ \text{mg/L}\]

\[N_0 = 7 \ \text{mg/L}\]

Single-Discharge Example: Simulation

Now we can compute \(C(x)\) (river velocity \(U = 5\) km/d).

function dissolved_oxygen(x, Cs, C0, B0, N0, ka, kc, kn, U)
    α1 = exp(-ka * x / U)
    α2 = (kc / (ka - kc)) * (exp(-kc * x / U) - α1)
    α3 = (kn / (ka - kn)) * (exp(-kn * x / U) - α1)
    C = (Cs * (1 - α1)) + (C0 * α1) - (B0 * α2) - (N0 * α3)
    return C
end

x = 0:0.1:20
C = (y -> dissolved_oxygen(y, Cs, C0, B0, N0, ka, kc, kn, U)).(x)

Single-Discharge Example: Simulation

Code
plot(x, C; linewidth=3, 
    label="Dissolved Oxygen", 
    tickfontsize=16, 
    guidefontsize=16, 
    legendfontsize=16)
xlabel!(L"$x$ (km)")
ylabel!("DO Concentration (mg/L)")
hline!([3], color=:red, 
    linestyle=:dash, 
    label="Regulatory Standard")
plot!(size=(500, 500))
Figure 2: Single-Release Dissolved Oxygen Example

Simulating Multiple Discharges

Multiple Discharges

What happens if we have multiple discharge sites?

Schematic for Multiple Discharge Example

Multiple Discharges

Think about this as a multi-box problem:

  • Box 1: From Release 1 to Release 2
  • Box 2: From Release 2 to End

Multiple Discharge Boxes

Multiple Discharges

  • Dynamics within each box are like single-release example;
  • Make sure to get new initial conditions from relevant outflows!

Multiple Discharge Boxes

Multiple Discharges

Question: Who would you penalize for lack of compliance?

Figure 3: Multi-Release Dissolved Oxygen Example

Key Points

Key Points

  • Simulation involves running the model over space/time.
  • Multiple sections as “multi-box” model: outflows from one box become inflows/initial conditions for another.
  • Assigning blame/responsibility in an interdependent system is not straightforward!

Simulation Framework Overview

Simulation Workflow Diagram

Upcoming Schedule

Next Classes

Wednesday/Friday: Uncertainty, Risk, and Monte Carlo

Assessments

  • HW1 released today, due 9/22.