Low-Level Reactor with multiple Processes: ASM3 with Aeration

Note

This example is basically the same as the corresponding one with the high-level interface. This allows for directly comparing the two interfaces.

For this system, it becomes obvious how the high-level interface simplifies the model definition and one can imagine how this applies to even more complex systems.

This example shows how multiple processes are combined in a single reactor using the low-level interface. For this, we use an exemplary system of a single aerated reactor with ASM3 and constant input:

TikzPicture(
     """;
    options = ">=stealth, auto, node distance=2cm, scale=2, background rectangle/.style={fill=white}, show background rectangle",
Example block output

Combining two processes in a single reactor is an excellent example where the split between the Reactor and the Process comes in handy (see Low-Level: Reactors vs. Processes for details): Being provided as external signals to the Reactor, the reaction rates of the different processes can simply be added by using external connections. Now this can be represented as:

TikzPicture(
   """;
    options = ">=stealth, auto, scale=2, background rectangle/.style={fill=white}, show background rectangle",
Example block output

For setting this up, an adder block is needed. Luckily, this can be taken from the ModelingToolkitStandardLibrary as ModelingToolkitStandardLibrary.Blocks.Add where the compatibility systems provided in this library will support us.

There is only one caveat left: The two processes do not need the same states and also do not provide the same rates. Instead, the Aeration needs only the dissolved oxygen state as input and also provides only a rate for the dissolved oxygen. This makes the combination more complex. However, this can be solved again using the standard library compatibility systems as they act as kind of a multiplexer: they split the ports into their individual signals and they can also assemble individual signals into the corresponding port.

Now, let's start the example of how to actually do this.

Setup

As always, the first step is the setup. Note that now also the ModelingToolkitStandardLibrary is loaded for the adder system and the bookkeeping variables are also introduced.

using BioChemicalTreatment # This package :)
using ModelingToolkit # Basic modeling framework. Takes, e.g., care of simplification of the equations
using ModelingToolkitStandardLibrary.Blocks # Standard library for MTK. Provides, e.g., simple math operations (adder, product...), controllers (PID) and more
using DifferentialEquations # Solve the equations
using Plots # Plotting

sys = System[]
eqs = Equation[]

Creating the Processes and Reactor

Then, as usual, first the processes (in this case two of them) are created.

@named asm = Process("ASM3") # Use the matrix-defined version with default parameters
@named aer = Aeration() # The aeration process
append!(sys, [asm, aer]) # Bookkeeping

@named react = CSTR(
    1000, unknowns(states(asm)); initial_states = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) # Volume of 1000, initial_states of all 1 (the default of all 0 yields infinity, check the model yourself)
push!(sys, react) # Bookkeeping
nameof.(sys) # Show all added systems

# output

3-element Vector{Symbol}:
 :asm
 :aer
 :react

For the reactor, only the states of the ASM3 are used, as those superset the states of the aeration.

Creating the Systems for the Combination

For the combination of the processes, a series of other helper systems is needed. First the state of the reactor needs to be split into single ports

@named reactor_state_to_single_ports = StateInputToRealOutput(unknowns(states(react))) # note the use of the states of the reactor here as the reactor state port is to be split
push!(sys, reactor_state_to_single_ports)
nameof.(sys) # Show all added systems

# output

4-element Vector{Symbol}:
 :asm
 :aer
 :react
 :reactor_state_to_single_ports

And then the aeration state needs to be reassembled from it:

@named single_ports_to_aeration_states = RealInputToStateOutput(unknowns(states(aer))) # Similarly here, aeration state is to be built -> use unknowns(states(aer))
push!(sys, single_ports_to_aeration_states)
nameof.(sys) # Show all added systems

# output

5-element Vector{Symbol}:
 :asm
 :aer
 :react
 :reactor_state_to_single_ports
 :single_ports_to_aeration_states

Now the state inputs for both processes are available (for the ASM3 directly the state from the reactor can be taken). So it's time to look at the other side of the rates. There, first the rate outputs of both processes have to be split apart

@named asm_rates_to_single_ports = ReactionInputToRealOutput(unknowns(rates(asm))) # asm rates is to be split -> unknowns(rates(asm))
@named aeration_rates_to_single_ports = ReactionInputToRealOutput(unknowns(rates(aer))) # aeration rates is to be split -> unknowns(rates(aer))
append!(sys, [asm_rates_to_single_ports, aeration_rates_to_single_ports])
nameof.(sys) # Show all added systems

# output

7-element Vector{Symbol}:
 :asm
 :aer
 :react
 :reactor_state_to_single_ports
 :single_ports_to_aeration_states
 :asm_rates_to_single_ports
 :aeration_rates_to_single_ports

Then, an adder is needed to add the rates of the dissolved oxygen.

@named add_aeration_rate = ModelingToolkitStandardLibrary.Blocks.Add()
push!(sys, add_aeration_rate)
nameof.(sys) # Show all added systems

# output

8-element Vector{Symbol}:
 :asm
 :aer
 :react
 :reactor_state_to_single_ports
 :single_ports_to_aeration_states
 :asm_rates_to_single_ports
 :aeration_rates_to_single_ports
 :add_aeration_rate

And finally, the rates port has to be reassembled to be able to provide it to the reactor:

@named single_ports_to_reaction_output = RealInputToReactionOutput(unknowns(rates(react))) # reactor rates is to be built -> unknowns(rates(react))
push!(sys, single_ports_to_reaction_output)
nameof.(sys) # Show all added systems

# output

9-element Vector{Symbol}:
 :asm
 :aer
 :react
 :reactor_state_to_single_ports
 :single_ports_to_aeration_states
 :asm_rates_to_single_ports
 :aeration_rates_to_single_ports
 :add_aeration_rate
 :single_ports_to_reaction_output

Creating the Other Needed Systems

Now, most of the needed systems have been created, but two more are missing. Do you figure out which?

They are the influent and an aeration strength input for the aeration. The aeration process models the aeration, but it needs an input of the oxygen transfer coefficient, which allows it to be controlled (e.g., to hold a constant level of dissolved oxygen). See the docs of the aeration for details.

As influent and this control input, constant values are assumed for simplicity. For the influent, the stabilization from the BSM1 is taken:

@named influent = Influent(
    [7.0, 30.0, 0.0, 31.56, 6.95, 0.0, 69.5, 0.0, 28.17, 51.20, 202.32, 216.393, 0.0],
    unknowns(states(asm)), flowrate = 18446) # This is the stabilization influent from BSM1
push!(sys, influent)
nameof.(sys) # Show all added systems

# output

10-element Vector{Symbol}:
 :asm
 :aer
 :react
 :reactor_state_to_single_ports
 :single_ports_to_aeration_states
 :asm_rates_to_single_ports
 :aeration_rates_to_single_ports
 :add_aeration_rate
 :single_ports_to_reaction_output
 :influent

And for the control input, a value of 240 1/d is assumed. This port is a ModelingToolkitStandardLibrary.Blocks.RealInput as this port can directly be connected to the systems from there, e.g., the PID controller. Luckily, the library there also features a constant, which is used to specify this constant input:

@named aeration_ctrl = Constant(; k = 240)
push!(sys, aeration_ctrl)
nameof.(sys) # Show all added systems

# output

11-element Vector{Symbol}:
 :asm
 :aer
 :react
 :reactor_state_to_single_ports
 :single_ports_to_aeration_states
 :asm_rates_to_single_ports
 :aeration_rates_to_single_ports
 :add_aeration_rate
 :single_ports_to_reaction_output
 :influent
 :aeration_ctrl

Connecting

We start by connecting the current state of the reactor to the processes. As the ASM3 has the same states as the reactor this works as usual:

push!(eqs, connect(states(react), states(asm)))

For the Aeration, which only needs the dissolved oxygen concentration, first the port is split into its individual values to extract the dissolved oxygen, which is then fed to the system assembling the state port for the Aeration process and then to the process itself:

push!(eqs, connect(states(react), states(reactor_state_to_single_ports))) # First the reactor states to the splitting system
push!(eqs,
    connect(exogenous_outputs(reactor_state_to_single_ports, :S_O2),
        exogenous_inputs(single_ports_to_aeration_states, :S_O))) # Then the split up dissolved oxygen to the disassembly system
push!(eqs, connect(states(single_ports_to_aeration_states), states(aer))) # Then the disassembly system to the aeration states
Warning

Note the different names of the dissolved oxygen in the two processes, S_O vs S_O2. This is unfortunate, but comes from the fact that there are multiple naming conventions out there, the one from the original ASM1 (Henze et al., 1987) (used by the Aeration system) and the ASM3. If ASM1 (using ASM1() or Process("ASM1")) would have been used, both variables would be called S_O. The variable naming in this package is still work in progress and it might be unified at some point in the future. However, this does not hinder the combination of two processes.

This implies, however, that arbitrary process rates can be added and combined like this. Thus the user must pay attention that the correct rates are connected!

Then, the other side of adding and connecting the rates is tackled. For this, first the rate outputs of both systems have to be split up:

push!(eqs, connect(rates(asm), rates(asm_rates_to_single_ports)))
push!(eqs, connect(rates(aer), rates(aeration_rates_to_single_ports)))

And then, the dissolved oxygen rates can be summed up by connection to the addition system:

push!(eqs,
    connect(exogenous_outputs(asm_rates_to_single_ports, :S_O2), add_aeration_rate.input1))
push!(eqs,
    connect(
        exogenous_outputs(aeration_rates_to_single_ports, :S_O), add_aeration_rate.input2))

It is continued by assembling the combined rates port by connecting all single signals from the split ASM3 rates port and the summed up rate for dissolved oxygen to the reassembly system:

append!(eqs,
    [
     # First the summed up aeration rate
     connect(add_aeration_rate.output,
         exogenous_inputs(single_ports_to_reaction_output, :S_O2))
     # Then all others directly from the splitted asm rates 
     connect(exogenous_outputs(asm_rates_to_single_ports, :S_ALK),
         exogenous_inputs(single_ports_to_reaction_output, :S_ALK))
     connect(exogenous_outputs(asm_rates_to_single_ports, :S_I),
         exogenous_inputs(single_ports_to_reaction_output, :S_I))
     connect(exogenous_outputs(asm_rates_to_single_ports, :S_N2),
         exogenous_inputs(single_ports_to_reaction_output, :S_N2))
     connect(exogenous_outputs(asm_rates_to_single_ports, :S_NH4),
         exogenous_inputs(single_ports_to_reaction_output, :S_NH4))
     connect(exogenous_outputs(asm_rates_to_single_ports, :S_NOX),
         exogenous_inputs(single_ports_to_reaction_output, :S_NOX))
     connect(exogenous_outputs(asm_rates_to_single_ports, :S_S),
         exogenous_inputs(single_ports_to_reaction_output, :S_S))
     connect(exogenous_outputs(asm_rates_to_single_ports, :X_A),
         exogenous_inputs(single_ports_to_reaction_output, :X_A))
     connect(exogenous_outputs(asm_rates_to_single_ports, :X_H),
         exogenous_inputs(single_ports_to_reaction_output, :X_H))
     connect(exogenous_outputs(asm_rates_to_single_ports, :X_I),
         exogenous_inputs(single_ports_to_reaction_output, :X_I))
     connect(exogenous_outputs(asm_rates_to_single_ports, :X_S),
         exogenous_inputs(single_ports_to_reaction_output, :X_S))
     connect(exogenous_outputs(asm_rates_to_single_ports, :X_SS),
         exogenous_inputs(single_ports_to_reaction_output, :X_SS))
     connect(exogenous_outputs(asm_rates_to_single_ports, :X_STO),
         exogenous_inputs(single_ports_to_reaction_output, :X_STO))])

And finally, the assembled rates to the reactor:

push!(eqs, connect(rates(single_ports_to_reaction_output), rates(react)))

With this, the reactor and process are connected. Now adding the influent and the control input, and then the system is ready to be simulated:

push!(eqs, connect(outflows(influent, 1), inflows(react, 1)))
push!(eqs, connect(exogenous_inputs(aer, :k_La), aeration_ctrl.output))

Simulation and Plotting

Before simulating, the model must be built and simplified. For demonstration purposes later, we do it in two steps instead of directly using @mtkcompile:

@named model = System(eqs, t, systems = sys)
model_simplified = mtkcompile(model)
Note

Incredibly, the simplification process was able to simplify all of this to 13 differential equations, one for each state in the ASM3. And the dissolved oxygen has indeed the rates terms of the ASM and the aeration!

Check it yourself:

Number of equations of the original model:

julia> length(equations(model))
162

Number of equations of the simplified model:

julia> length(equations(model_simplified))
13

Check the equations of the simplified model yourself using

full_equations(model_simplified)

\[ \begin{align} \frac{\mathrm{d} \mathtt{react.states.X\_STO}\left( t \right)}{\mathrm{d}t} &= \frac{ - \mathtt{asm.K\_O2} \mathtt{asm.eta\_NOX} \mathtt{asm.mu\_H} \mathtt{react.states.S\_NH4}\left( t \right) \mathtt{react.states.S\_ALK}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right) \mathtt{react.states.X\_STO}\left( t \right)}{\left( \mathtt{asm.K\_ALK} + \mathtt{react.states.S\_ALK}\left( t \right) \right) \left( \mathtt{asm.K\_NH4} + \mathtt{react.states.S\_NH4}\left( t \right) \right) \left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_STO} + \frac{\mathtt{react.states.X\_STO}\left( t \right)}{\mathtt{react.states.X\_H}\left( t \right)} \right) \mathtt{asm.Y\_HNOX}} + \frac{ - \mathtt{asm.mu\_H} \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.S\_NH4}\left( t \right) \mathtt{react.states.S\_ALK}\left( t \right) \mathtt{react.states.X\_STO}\left( t \right)}{\left( \mathtt{asm.K\_ALK} + \mathtt{react.states.S\_ALK}\left( t \right) \right) \left( \mathtt{asm.K\_NH4} + \mathtt{react.states.S\_NH4}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_STO} + \frac{\mathtt{react.states.X\_STO}\left( t \right)}{\mathtt{react.states.X\_H}\left( t \right)} \right) \mathtt{asm.Y\_HO2}} + \frac{ - \mathtt{asm.K\_O2} \mathtt{asm.b\_STONOX} \mathtt{react.states.S\_NOX}\left( t \right) \mathtt{react.states.X\_STO}\left( t \right)}{\left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right)} + \frac{\mathtt{influent.X\_STO\_const.k} \mathtt{influent.q\_const.k}}{\mathtt{react.V}} + \frac{ - \mathtt{influent.q\_const.k} \mathtt{react.states.X\_STO}\left( t \right)}{\mathtt{react.V}} + \frac{ - \mathtt{asm.b\_STOO2} \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.X\_STO}\left( t \right)}{\mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right)} + \frac{\mathtt{asm.K\_O2} \mathtt{asm.Y\_STONOX} \mathtt{asm.eta\_NOX} \mathtt{asm.k\_STO} \mathtt{react.states.S\_S}\left( t \right) \mathtt{react.states.X\_H}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right)}{\left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_S} + \mathtt{react.states.S\_S}\left( t \right) \right)} + \frac{\mathtt{asm.Y\_STOO2} \mathtt{asm.k\_STO} \mathtt{react.states.S\_S}\left( t \right) \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.X\_H}\left( t \right)}{\left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_S} + \mathtt{react.states.S\_S}\left( t \right) \right)} \\ \frac{\mathrm{d} \mathtt{react.states.X\_SS}\left( t \right)}{\mathrm{d}t} &= \frac{\mathtt{asm.i\_SSBM} \mathtt{asm.mu\_A} \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.S\_NH4}\left( t \right) \mathtt{react.states.S\_ALK}\left( t \right) \mathtt{react.states.X\_A}\left( t \right)}{\left( \mathtt{asm.K\_AALK} + \mathtt{react.states.S\_ALK}\left( t \right) \right) \left( \mathtt{asm.K\_ANH4} + \mathtt{react.states.S\_NH4}\left( t \right) \right) \left( \mathtt{asm.K\_AO2} + \mathtt{react.states.S\_O2}\left( t \right) \right)} + \frac{\mathtt{asm.b\_AO2} \left( - \mathtt{asm.i\_SSBM} + \mathtt{asm.f\_XI} \mathtt{asm.i\_SSXI} \right) \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.X\_A}\left( t \right)}{\mathtt{asm.K\_AO2} + \mathtt{react.states.S\_O2}\left( t \right)} + \frac{\mathtt{asm.b\_HO2} \left( - \mathtt{asm.i\_SSBM} + \mathtt{asm.f\_XI} \mathtt{asm.i\_SSXI} \right) \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.X\_H}\left( t \right)}{\mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right)} + \frac{\mathtt{asm.K\_O2} \mathtt{asm.b\_HNOX} \left( - \mathtt{asm.i\_SSBM} + \mathtt{asm.f\_XI} \mathtt{asm.i\_SSXI} \right) \mathtt{react.states.X\_H}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right)}{\left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right)} + \frac{ - \mathtt{asm.b\_STOO2} \mathtt{asm.i\_SSSTO} \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.X\_STO}\left( t \right)}{\mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right)} + \frac{\mathtt{asm.Y\_STOO2} \mathtt{asm.i\_SSSTO} \mathtt{asm.k\_STO} \mathtt{react.states.S\_S}\left( t \right) \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.X\_H}\left( t \right)}{\left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_S} + \mathtt{react.states.S\_S}\left( t \right) \right)} + \frac{ - \mathtt{influent.q\_const.k} \mathtt{react.states.X\_SS}\left( t \right)}{\mathtt{react.V}} + \frac{\left( \mathtt{asm.i\_SSBM} + \frac{ - \mathtt{asm.i\_SSSTO}}{\mathtt{asm.Y\_HO2}} \right) \mathtt{asm.mu\_H} \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.S\_NH4}\left( t \right) \mathtt{react.states.S\_ALK}\left( t \right) \mathtt{react.states.X\_STO}\left( t \right)}{\left( \mathtt{asm.K\_ALK} + \mathtt{react.states.S\_ALK}\left( t \right) \right) \left( \mathtt{asm.K\_NH4} + \mathtt{react.states.S\_NH4}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_STO} + \frac{\mathtt{react.states.X\_STO}\left( t \right)}{\mathtt{react.states.X\_H}\left( t \right)} \right)} + \frac{ - \mathtt{asm.K\_O2} \mathtt{asm.b\_STONOX} \mathtt{asm.i\_SSSTO} \mathtt{react.states.S\_NOX}\left( t \right) \mathtt{react.states.X\_STO}\left( t \right)}{\left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right)} + \frac{ - \mathtt{asm.i\_SSXS} \mathtt{asm.k\_H} \mathtt{react.states.X\_S}\left( t \right)}{\mathtt{asm.K\_X} + \frac{\mathtt{react.states.X\_S}\left( t \right)}{\mathtt{react.states.X\_H}\left( t \right)}} + \frac{\mathtt{influent.X\_SS\_const.k} \mathtt{influent.q\_const.k}}{\mathtt{react.V}} + \frac{\mathtt{asm.K\_AO2} \mathtt{asm.b\_ANOX} \left( - \mathtt{asm.i\_SSBM} + \mathtt{asm.f\_XI} \mathtt{asm.i\_SSXI} \right) \mathtt{react.states.X\_A}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right)}{\left( \mathtt{asm.K\_AO2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right)} + \frac{\mathtt{asm.K\_O2} \mathtt{asm.eta\_NOX} \left( \mathtt{asm.i\_SSBM} + \frac{ - \mathtt{asm.i\_SSSTO}}{\mathtt{asm.Y\_HNOX}} \right) \mathtt{asm.mu\_H} \mathtt{react.states.S\_NH4}\left( t \right) \mathtt{react.states.S\_ALK}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right) \mathtt{react.states.X\_STO}\left( t \right)}{\left( \mathtt{asm.K\_ALK} + \mathtt{react.states.S\_ALK}\left( t \right) \right) \left( \mathtt{asm.K\_NH4} + \mathtt{react.states.S\_NH4}\left( t \right) \right) \left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_STO} + \frac{\mathtt{react.states.X\_STO}\left( t \right)}{\mathtt{react.states.X\_H}\left( t \right)} \right)} + \frac{\mathtt{asm.K\_O2} \mathtt{asm.Y\_STONOX} \mathtt{asm.eta\_NOX} \mathtt{asm.i\_SSSTO} \mathtt{asm.k\_STO} \mathtt{react.states.S\_S}\left( t \right) \mathtt{react.states.X\_H}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right)}{\left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_S} + \mathtt{react.states.S\_S}\left( t \right) \right)} \\ \frac{\mathrm{d} \mathtt{react.states.X\_S}\left( t \right)}{\mathrm{d}t} &= \frac{\mathtt{influent.X\_S\_const.k} \mathtt{influent.q\_const.k}}{\mathtt{react.V}} + \frac{ - \mathtt{influent.q\_const.k} \mathtt{react.states.X\_S}\left( t \right)}{\mathtt{react.V}} + \frac{ - \mathtt{asm.k\_H} \mathtt{react.states.X\_S}\left( t \right)}{\mathtt{asm.K\_X} + \frac{\mathtt{react.states.X\_S}\left( t \right)}{\mathtt{react.states.X\_H}\left( t \right)}} \\ \frac{\mathrm{d} \mathtt{react.states.X\_I}\left( t \right)}{\mathrm{d}t} &= \frac{\mathtt{influent.X\_I\_const.k} \mathtt{influent.q\_const.k}}{\mathtt{react.V}} + \frac{\mathtt{asm.K\_AO2} \mathtt{asm.b\_ANOX} \mathtt{asm.f\_XI} \mathtt{react.states.X\_A}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right)}{\left( \mathtt{asm.K\_AO2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right)} + \frac{\mathtt{asm.b\_AO2} \mathtt{asm.f\_XI} \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.X\_A}\left( t \right)}{\mathtt{asm.K\_AO2} + \mathtt{react.states.S\_O2}\left( t \right)} + \frac{ - \mathtt{influent.q\_const.k} \mathtt{react.states.X\_I}\left( t \right)}{\mathtt{react.V}} + \frac{\mathtt{asm.b\_HO2} \mathtt{asm.f\_XI} \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.X\_H}\left( t \right)}{\mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right)} + \frac{\mathtt{asm.K\_O2} \mathtt{asm.b\_HNOX} \mathtt{asm.f\_XI} \mathtt{react.states.X\_H}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right)}{\left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right)} \\ \frac{\mathrm{d} \mathtt{react.states.X\_H}\left( t \right)}{\mathrm{d}t} &= \frac{ - \mathtt{asm.b\_HO2} \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.X\_H}\left( t \right)}{\mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right)} + \frac{ - \mathtt{asm.K\_O2} \mathtt{asm.b\_HNOX} \mathtt{react.states.X\_H}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right)}{\left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right)} + \frac{\mathtt{asm.K\_O2} \mathtt{asm.eta\_NOX} \mathtt{asm.mu\_H} \mathtt{react.states.S\_NH4}\left( t \right) \mathtt{react.states.S\_ALK}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right) \mathtt{react.states.X\_STO}\left( t \right)}{\left( \mathtt{asm.K\_ALK} + \mathtt{react.states.S\_ALK}\left( t \right) \right) \left( \mathtt{asm.K\_NH4} + \mathtt{react.states.S\_NH4}\left( t \right) \right) \left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_STO} + \frac{\mathtt{react.states.X\_STO}\left( t \right)}{\mathtt{react.states.X\_H}\left( t \right)} \right)} + \frac{\mathtt{asm.mu\_H} \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.S\_NH4}\left( t \right) \mathtt{react.states.S\_ALK}\left( t \right) \mathtt{react.states.X\_STO}\left( t \right)}{\left( \mathtt{asm.K\_ALK} + \mathtt{react.states.S\_ALK}\left( t \right) \right) \left( \mathtt{asm.K\_NH4} + \mathtt{react.states.S\_NH4}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_STO} + \frac{\mathtt{react.states.X\_STO}\left( t \right)}{\mathtt{react.states.X\_H}\left( t \right)} \right)} + \frac{\mathtt{influent.X\_H\_const.k} \mathtt{influent.q\_const.k}}{\mathtt{react.V}} + \frac{ - \mathtt{influent.q\_const.k} \mathtt{react.states.X\_H}\left( t \right)}{\mathtt{react.V}} \\ \frac{\mathrm{d} \mathtt{react.states.X\_A}\left( t \right)}{\mathrm{d}t} &= \frac{ - \mathtt{influent.q\_const.k} \mathtt{react.states.X\_A}\left( t \right)}{\mathtt{react.V}} + \frac{ - \mathtt{asm.b\_AO2} \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.X\_A}\left( t \right)}{\mathtt{asm.K\_AO2} + \mathtt{react.states.S\_O2}\left( t \right)} + \frac{\mathtt{influent.X\_A\_const.k} \mathtt{influent.q\_const.k}}{\mathtt{react.V}} + \frac{\mathtt{asm.mu\_A} \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.S\_NH4}\left( t \right) \mathtt{react.states.S\_ALK}\left( t \right) \mathtt{react.states.X\_A}\left( t \right)}{\left( \mathtt{asm.K\_AALK} + \mathtt{react.states.S\_ALK}\left( t \right) \right) \left( \mathtt{asm.K\_ANH4} + \mathtt{react.states.S\_NH4}\left( t \right) \right) \left( \mathtt{asm.K\_AO2} + \mathtt{react.states.S\_O2}\left( t \right) \right)} + \frac{ - \mathtt{asm.K\_AO2} \mathtt{asm.b\_ANOX} \mathtt{react.states.X\_A}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right)}{\left( \mathtt{asm.K\_AO2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right)} \\ \frac{\mathrm{d} \mathtt{react.states.S\_S}\left( t \right)}{\mathrm{d}t} &= \frac{ - \mathtt{asm.k\_STO} \mathtt{react.states.S\_S}\left( t \right) \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.X\_H}\left( t \right)}{\left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_S} + \mathtt{react.states.S\_S}\left( t \right) \right)} + \frac{ - \mathtt{asm.K\_O2} \mathtt{asm.eta\_NOX} \mathtt{asm.k\_STO} \mathtt{react.states.S\_S}\left( t \right) \mathtt{react.states.X\_H}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right)}{\left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_S} + \mathtt{react.states.S\_S}\left( t \right) \right)} + \frac{\mathtt{influent.S\_S\_const.k} \mathtt{influent.q\_const.k}}{\mathtt{react.V}} + \frac{ - \left( -1 + \mathtt{asm.f\_SI} \right) \mathtt{asm.k\_H} \mathtt{react.states.X\_S}\left( t \right)}{\mathtt{asm.K\_X} + \frac{\mathtt{react.states.X\_S}\left( t \right)}{\mathtt{react.states.X\_H}\left( t \right)}} + \frac{ - \mathtt{influent.q\_const.k} \mathtt{react.states.S\_S}\left( t \right)}{\mathtt{react.V}} \\ \frac{\mathrm{d} \mathtt{react.states.S\_O2}\left( t \right)}{\mathrm{d}t} &= \frac{\mathtt{influent.S\_O2\_const.k} \mathtt{influent.q\_const.k}}{\mathtt{react.V}} + \frac{ - \mathtt{influent.q\_const.k} \mathtt{react.states.S\_O2}\left( t \right)}{\mathtt{react.V}} + \mathtt{add\_aeration\_rate.k1} \left( \frac{\left( -1 + \mathtt{asm.Y\_HO2} \right) \mathtt{asm.mu\_H} \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.S\_NH4}\left( t \right) \mathtt{react.states.S\_ALK}\left( t \right) \mathtt{react.states.X\_STO}\left( t \right)}{\left( \mathtt{asm.K\_ALK} + \mathtt{react.states.S\_ALK}\left( t \right) \right) \left( \mathtt{asm.K\_NH4} + \mathtt{react.states.S\_NH4}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_STO} + \frac{\mathtt{react.states.X\_STO}\left( t \right)}{\mathtt{react.states.X\_H}\left( t \right)} \right) \mathtt{asm.Y\_HO2}} + \frac{\left( \mathtt{asm.Y\_A} + \mathtt{asm.i\_CODNO3} \right) \mathtt{asm.mu\_A} \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.S\_NH4}\left( t \right) \mathtt{react.states.S\_ALK}\left( t \right) \mathtt{react.states.X\_A}\left( t \right)}{\left( \mathtt{asm.K\_AALK} + \mathtt{react.states.S\_ALK}\left( t \right) \right) \left( \mathtt{asm.K\_ANH4} + \mathtt{react.states.S\_NH4}\left( t \right) \right) \left( \mathtt{asm.K\_AO2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \mathtt{asm.Y\_A}} + \frac{\mathtt{asm.b\_HO2} \left( -1 + \mathtt{asm.f\_XI} \right) \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.X\_H}\left( t \right)}{\mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right)} + \frac{\left( -1 + \mathtt{asm.Y\_STOO2} \right) \mathtt{asm.k\_STO} \mathtt{react.states.S\_S}\left( t \right) \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.X\_H}\left( t \right)}{\left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_S} + \mathtt{react.states.S\_S}\left( t \right) \right)} + \frac{ - \mathtt{asm.b\_STOO2} \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.X\_STO}\left( t \right)}{\mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right)} + \frac{\mathtt{asm.b\_AO2} \left( -1 + \mathtt{asm.f\_XI} \right) \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.X\_A}\left( t \right)}{\mathtt{asm.K\_AO2} + \mathtt{react.states.S\_O2}\left( t \right)} \right) + \mathtt{add\_aeration\_rate.k2} \mathtt{aeration\_ctrl.k} \left( \mathtt{aer.S\_O\_max} - \mathtt{react.states.S\_O2}\left( t \right) \right) \\ \frac{\mathrm{d} \mathtt{react.states.S\_NOX}\left( t \right)}{\mathrm{d}t} &= \frac{ - \mathtt{asm.K\_AO2} \mathtt{asm.b\_ANOX} \left( 1 - \mathtt{asm.f\_XI} \right) \mathtt{react.states.X\_A}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right)}{\left( \mathtt{asm.K\_AO2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \mathtt{asm.i\_NO3N2}} + \frac{\mathtt{asm.K\_O2} \mathtt{asm.b\_HNOX} \left( -1 + \mathtt{asm.f\_XI} \right) \mathtt{react.states.X\_H}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right)}{\left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \mathtt{asm.i\_NO3N2}} + \frac{\mathtt{asm.K\_O2} \left( -1 + \mathtt{asm.Y\_HNOX} \right) \mathtt{asm.eta\_NOX} \mathtt{asm.mu\_H} \mathtt{react.states.S\_NH4}\left( t \right) \mathtt{react.states.S\_ALK}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right) \mathtt{react.states.X\_STO}\left( t \right)}{\left( \mathtt{asm.K\_ALK} + \mathtt{react.states.S\_ALK}\left( t \right) \right) \left( \mathtt{asm.K\_NH4} + \mathtt{react.states.S\_NH4}\left( t \right) \right) \left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_STO} + \frac{\mathtt{react.states.X\_STO}\left( t \right)}{\mathtt{react.states.X\_H}\left( t \right)} \right) \mathtt{asm.Y\_HNOX} \mathtt{asm.i\_NO3N2}} + \frac{\mathtt{influent.S\_NOX\_const.k} \mathtt{influent.q\_const.k}}{\mathtt{react.V}} + \frac{ - \mathtt{asm.K\_O2} \mathtt{asm.b\_STONOX} \mathtt{react.states.S\_NOX}\left( t \right) \mathtt{react.states.X\_STO}\left( t \right)}{\left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \mathtt{asm.i\_NO3N2}} + \frac{ - \mathtt{influent.q\_const.k} \mathtt{react.states.S\_NOX}\left( t \right)}{\mathtt{react.V}} + \frac{\mathtt{asm.K\_O2} \left( -1 + \mathtt{asm.Y\_STONOX} \right) \mathtt{asm.eta\_NOX} \mathtt{asm.k\_STO} \mathtt{react.states.S\_S}\left( t \right) \mathtt{react.states.X\_H}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right)}{\left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_S} + \mathtt{react.states.S\_S}\left( t \right) \right) \mathtt{asm.i\_NO3N2}} + \frac{\mathtt{asm.mu\_A} \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.S\_NH4}\left( t \right) \mathtt{react.states.S\_ALK}\left( t \right) \mathtt{react.states.X\_A}\left( t \right)}{\left( \mathtt{asm.K\_AALK} + \mathtt{react.states.S\_ALK}\left( t \right) \right) \left( \mathtt{asm.K\_ANH4} + \mathtt{react.states.S\_NH4}\left( t \right) \right) \left( \mathtt{asm.K\_AO2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \mathtt{asm.Y\_A}} \\ \frac{\mathrm{d} \mathtt{react.states.S\_NH4}\left( t \right)}{\mathrm{d}t} &= \frac{\mathtt{asm.i\_NSS} \mathtt{asm.k\_STO} \mathtt{react.states.S\_S}\left( t \right) \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.X\_H}\left( t \right)}{\left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_S} + \mathtt{react.states.S\_S}\left( t \right) \right)} + \frac{\mathtt{asm.K\_O2} \mathtt{asm.b\_HNOX} \left( \mathtt{asm.i\_NBM} - \mathtt{asm.f\_XI} \mathtt{asm.i\_NXI} \right) \mathtt{react.states.X\_H}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right)}{\left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right)} + \frac{ - \mathtt{asm.K\_O2} \mathtt{asm.eta\_NOX} \mathtt{asm.i\_NBM} \mathtt{asm.mu\_H} \mathtt{react.states.S\_NH4}\left( t \right) \mathtt{react.states.S\_ALK}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right) \mathtt{react.states.X\_STO}\left( t \right)}{\left( \mathtt{asm.K\_ALK} + \mathtt{react.states.S\_ALK}\left( t \right) \right) \left( \mathtt{asm.K\_NH4} + \mathtt{react.states.S\_NH4}\left( t \right) \right) \left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_STO} + \frac{\mathtt{react.states.X\_STO}\left( t \right)}{\mathtt{react.states.X\_H}\left( t \right)} \right)} + \frac{ - \mathtt{influent.q\_const.k} \mathtt{react.states.S\_NH4}\left( t \right)}{\mathtt{react.V}} + \frac{\mathtt{asm.K\_O2} \mathtt{asm.eta\_NOX} \mathtt{asm.i\_NSS} \mathtt{asm.k\_STO} \mathtt{react.states.S\_S}\left( t \right) \mathtt{react.states.X\_H}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right)}{\left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_S} + \mathtt{react.states.S\_S}\left( t \right) \right)} + \frac{\left( - \mathtt{asm.i\_NBM} + \frac{-1}{\mathtt{asm.Y\_A}} \right) \mathtt{asm.mu\_A} \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.S\_NH4}\left( t \right) \mathtt{react.states.S\_ALK}\left( t \right) \mathtt{react.states.X\_A}\left( t \right)}{\left( \mathtt{asm.K\_AALK} + \mathtt{react.states.S\_ALK}\left( t \right) \right) \left( \mathtt{asm.K\_ANH4} + \mathtt{react.states.S\_NH4}\left( t \right) \right) \left( \mathtt{asm.K\_AO2} + \mathtt{react.states.S\_O2}\left( t \right) \right)} + \frac{\mathtt{influent.S\_NH4\_const.k} \mathtt{influent.q\_const.k}}{\mathtt{react.V}} + \frac{\mathtt{asm.b\_AO2} \left( \mathtt{asm.i\_NBM} - \mathtt{asm.f\_XI} \mathtt{asm.i\_NXI} \right) \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.X\_A}\left( t \right)}{\mathtt{asm.K\_AO2} + \mathtt{react.states.S\_O2}\left( t \right)} + \frac{ - \mathtt{asm.i\_NBM} \mathtt{asm.mu\_H} \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.S\_NH4}\left( t \right) \mathtt{react.states.S\_ALK}\left( t \right) \mathtt{react.states.X\_STO}\left( t \right)}{\left( \mathtt{asm.K\_ALK} + \mathtt{react.states.S\_ALK}\left( t \right) \right) \left( \mathtt{asm.K\_NH4} + \mathtt{react.states.S\_NH4}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_STO} + \frac{\mathtt{react.states.X\_STO}\left( t \right)}{\mathtt{react.states.X\_H}\left( t \right)} \right)} + \frac{\mathtt{asm.K\_AO2} \mathtt{asm.b\_ANOX} \left( \mathtt{asm.i\_NBM} - \mathtt{asm.f\_XI} \mathtt{asm.i\_NXI} \right) \mathtt{react.states.X\_A}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right)}{\left( \mathtt{asm.K\_AO2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right)} + \frac{\left( \mathtt{asm.i\_NXS} - \mathtt{asm.f\_SI} \mathtt{asm.i\_NSI} + \left( -1 + \mathtt{asm.f\_SI} \right) \mathtt{asm.i\_NSS} \right) \mathtt{asm.k\_H} \mathtt{react.states.X\_S}\left( t \right)}{\mathtt{asm.K\_X} + \frac{\mathtt{react.states.X\_S}\left( t \right)}{\mathtt{react.states.X\_H}\left( t \right)}} + \frac{\mathtt{asm.b\_HO2} \left( \mathtt{asm.i\_NBM} - \mathtt{asm.f\_XI} \mathtt{asm.i\_NXI} \right) \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.X\_H}\left( t \right)}{\mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right)} \\ \frac{\mathrm{d} \mathtt{react.states.S\_N2}\left( t \right)}{\mathrm{d}t} &= \frac{ - \mathtt{asm.K\_O2} \left( -1 + \mathtt{asm.Y\_STONOX} \right) \mathtt{asm.eta\_NOX} \mathtt{asm.k\_STO} \mathtt{react.states.S\_S}\left( t \right) \mathtt{react.states.X\_H}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right)}{\left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_S} + \mathtt{react.states.S\_S}\left( t \right) \right) \mathtt{asm.i\_NO3N2}} + \frac{\mathtt{asm.K\_O2} \mathtt{asm.b\_STONOX} \mathtt{react.states.S\_NOX}\left( t \right) \mathtt{react.states.X\_STO}\left( t \right)}{\left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \mathtt{asm.i\_NO3N2}} + \frac{ - \mathtt{asm.K\_O2} \left( -1 + \mathtt{asm.Y\_HNOX} \right) \mathtt{asm.eta\_NOX} \mathtt{asm.mu\_H} \mathtt{react.states.S\_NH4}\left( t \right) \mathtt{react.states.S\_ALK}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right) \mathtt{react.states.X\_STO}\left( t \right)}{\left( \mathtt{asm.K\_ALK} + \mathtt{react.states.S\_ALK}\left( t \right) \right) \left( \mathtt{asm.K\_NH4} + \mathtt{react.states.S\_NH4}\left( t \right) \right) \left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_STO} + \frac{\mathtt{react.states.X\_STO}\left( t \right)}{\mathtt{react.states.X\_H}\left( t \right)} \right) \mathtt{asm.Y\_HNOX} \mathtt{asm.i\_NO3N2}} + \frac{ - \mathtt{influent.q\_const.k} \mathtt{react.states.S\_N2}\left( t \right)}{\mathtt{react.V}} + \frac{\mathtt{influent.S\_N2\_const.k} \mathtt{influent.q\_const.k}}{\mathtt{react.V}} + \frac{\mathtt{asm.K\_O2} \mathtt{asm.b\_HNOX} \left( 1 - \mathtt{asm.f\_XI} \right) \mathtt{react.states.X\_H}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right)}{\left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \mathtt{asm.i\_NO3N2}} + \frac{\mathtt{asm.K\_AO2} \mathtt{asm.b\_ANOX} \left( 1 - \mathtt{asm.f\_XI} \right) \mathtt{react.states.X\_A}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right)}{\left( \mathtt{asm.K\_AO2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \mathtt{asm.i\_NO3N2}} \\ \frac{\mathrm{d} \mathtt{react.states.S\_I}\left( t \right)}{\mathrm{d}t} &= \frac{ - \mathtt{influent.q\_const.k} \mathtt{react.states.S\_I}\left( t \right)}{\mathtt{react.V}} + \frac{\mathtt{asm.f\_SI} \mathtt{asm.k\_H} \mathtt{react.states.X\_S}\left( t \right)}{\mathtt{asm.K\_X} + \frac{\mathtt{react.states.X\_S}\left( t \right)}{\mathtt{react.states.X\_H}\left( t \right)}} + \frac{\mathtt{influent.S\_I\_const.k} \mathtt{influent.q\_const.k}}{\mathtt{react.V}} \\ \frac{\mathrm{d} \mathtt{react.states.S\_ALK}\left( t \right)}{\mathrm{d}t} &= \frac{\mathtt{influent.S\_ALK\_const.k} \mathtt{influent.q\_const.k}}{\mathtt{react.V}} + \frac{\mathtt{asm.b\_AO2} \mathtt{asm.i\_ChargeSNHx} \mathtt{asm.v11\_SNHx} \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.X\_A}\left( t \right)}{\mathtt{asm.K\_AO2} + \mathtt{react.states.S\_O2}\left( t \right)} + \frac{\mathtt{asm.K\_AO2} \mathtt{asm.b\_ANOX} \left( \mathtt{asm.i\_ChargeSNHx} \mathtt{asm.v12\_SNHx} + \mathtt{asm.i\_ChargeSNOx} \mathtt{asm.v12\_SNOx} \right) \mathtt{react.states.X\_A}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right)}{\left( \mathtt{asm.K\_AO2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right)} + \frac{\mathtt{asm.K\_O2} \mathtt{asm.eta\_NOX} \left( \mathtt{asm.i\_ChargeSNHx} \mathtt{asm.v5\_SNHx} + \mathtt{asm.i\_ChargeSNOx} \mathtt{asm.v5\_SNOx} \right) \mathtt{asm.mu\_H} \mathtt{react.states.S\_NH4}\left( t \right) \mathtt{react.states.S\_ALK}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right) \mathtt{react.states.X\_STO}\left( t \right)}{\left( \mathtt{asm.K\_ALK} + \mathtt{react.states.S\_ALK}\left( t \right) \right) \left( \mathtt{asm.K\_NH4} + \mathtt{react.states.S\_NH4}\left( t \right) \right) \left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_STO} + \frac{\mathtt{react.states.X\_STO}\left( t \right)}{\mathtt{react.states.X\_H}\left( t \right)} \right)} + \frac{\mathtt{asm.i\_ChargeSNHx} \mathtt{asm.k\_STO} \mathtt{asm.v2\_SNHx} \mathtt{react.states.S\_S}\left( t \right) \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.X\_H}\left( t \right)}{\left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_S} + \mathtt{react.states.S\_S}\left( t \right) \right)} + \frac{ - \mathtt{influent.q\_const.k} \mathtt{react.states.S\_ALK}\left( t \right)}{\mathtt{react.V}} + \frac{ - \left( - \mathtt{asm.i\_ChargeSNHx} \mathtt{asm.v10\_SNHx} - \mathtt{asm.i\_ChargeSNOx} \mathtt{asm.v10\_SNOx} \right) \mathtt{asm.mu\_A} \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.S\_NH4}\left( t \right) \mathtt{react.states.S\_ALK}\left( t \right) \mathtt{react.states.X\_A}\left( t \right)}{\left( \mathtt{asm.K\_AALK} + \mathtt{react.states.S\_ALK}\left( t \right) \right) \left( \mathtt{asm.K\_ANH4} + \mathtt{react.states.S\_NH4}\left( t \right) \right) \left( \mathtt{asm.K\_AO2} + \mathtt{react.states.S\_O2}\left( t \right) \right)} + \frac{\mathtt{asm.K\_O2} \mathtt{asm.b\_HNOX} \left( \mathtt{asm.i\_ChargeSNHx} \mathtt{asm.v7\_SNHx} + \mathtt{asm.i\_ChargeSNOx} \mathtt{asm.v7\_SNOx} \right) \mathtt{react.states.X\_H}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right)}{\left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right)} + \frac{\mathtt{asm.i\_ChargeSNHx} \mathtt{asm.mu\_H} \mathtt{asm.v4\_SNHx} \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.S\_NH4}\left( t \right) \mathtt{react.states.S\_ALK}\left( t \right) \mathtt{react.states.X\_STO}\left( t \right)}{\left( \mathtt{asm.K\_ALK} + \mathtt{react.states.S\_ALK}\left( t \right) \right) \left( \mathtt{asm.K\_NH4} + \mathtt{react.states.S\_NH4}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_STO} + \frac{\mathtt{react.states.X\_STO}\left( t \right)}{\mathtt{react.states.X\_H}\left( t \right)} \right)} + \frac{\mathtt{asm.K\_O2} \mathtt{asm.eta\_NOX} \left( \mathtt{asm.i\_ChargeSNHx} \mathtt{asm.v3\_SNHx} + \mathtt{asm.i\_ChargeSNOx} \mathtt{asm.v3\_SNOx} \right) \mathtt{asm.k\_STO} \mathtt{react.states.S\_S}\left( t \right) \mathtt{react.states.X\_H}\left( t \right) \mathtt{react.states.S\_NOX}\left( t \right)}{\left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right) \left( \mathtt{asm.K\_S} + \mathtt{react.states.S\_S}\left( t \right) \right)} + \frac{\mathtt{asm.K\_O2} \mathtt{asm.b\_STONOX} \mathtt{asm.i\_ChargeSNOx} \mathtt{asm.v9\_SNOx} \mathtt{react.states.S\_NOX}\left( t \right) \mathtt{react.states.X\_STO}\left( t \right)}{\left( \mathtt{asm.K\_NOX} + \mathtt{react.states.S\_NOX}\left( t \right) \right) \left( \mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right) \right)} + \frac{\mathtt{asm.i\_ChargeSNHx} \mathtt{asm.k\_H} \mathtt{asm.v1\_SNHx} \mathtt{react.states.X\_S}\left( t \right)}{\mathtt{asm.K\_X} + \frac{\mathtt{react.states.X\_S}\left( t \right)}{\mathtt{react.states.X\_H}\left( t \right)}} + \frac{\mathtt{asm.b\_HO2} \mathtt{asm.i\_ChargeSNHx} \mathtt{asm.v6\_SNHx} \mathtt{react.states.S\_O2}\left( t \right) \mathtt{react.states.X\_H}\left( t \right)}{\mathtt{asm.K\_O2} + \mathtt{react.states.S\_O2}\left( t \right)} \end{align} \]

Then, the problem can be built and solved:

ode_prob = ODEProblem(model_simplified, [], (0, 1))
sol = solve(ode_prob)

And the solution plotted:

plot(sol, title = "CSTR with ASM3 and aeration", legend = :topright)
Example block output

Indeed, it is visible that there is some oxygen in the tank and as well some heterotrophs (which need oxygen to grow) seem to be present. But, let's have a look at the oxygen concentrations:

plot(sol, idxs = [inflows(react, 1).S_O2, outflows(react, 1).S_O2],
    label = ["Reactor Inflow" "Reactor Outflow"],
    title = "Dissolved oxygen concentration", legend = :right)
plot(sol, idxs = [inflows(react, 1).S_O2, outflows(react, 1).S_O2],
    label = ["Reactor Inflow" "Reactor Outflow"],
Example block output

This makes it evident that the aeration works and oxygen is supplied. However, it might be interesting to have a look at the rates of the dissolved oxygen, the total one in the reactor and as well the contributions of the two processes. It is also possible to plot those:

plot(sol, idxs = [rates(react).S_O2, rates(asm).S_O2, rates(aer).S_O],
    label = ["Total Rate" "Rate from ASM3" "Rate from Aeration"],
    title = "Dissolved oxygen reaction rates", legend = :topright)
plot(sol, idxs = [rates(react).S_O2, rates(asm).S_O2, rates(aer).S_O],
    label = ["Total Rate" "Rate from ASM3" "Rate from Aeration"],
Example block output

And as expected, the two individual rates sum up to the total rate in the reactor.