Skip to content

BSM2-base plant documentation

This documentation of BSM2-Python's base class bsm2_base.py will guide you through the source code and help you to better understand the wastewater treatment plant layout of BSM2-Python.

Initialization

The initialization of the wastewater treatment plant objects and variables takes place in the definition of the __init__.

bsm2_base.py
    def __init__(
        self,
        data_in: np.ndarray | str | None = None,
        timestep: float | None = None,
        endtime: float | None = None,
        evaltime: int | np.ndarray | None = None,
        *,
        tempmodel: bool = False,
        activate: bool = False,
        data_out: str | None = None,
    ):
        super().__init__(
            data_in=data_in,
            timestep=timestep,
            endtime=endtime,
            evaltime=evaltime,
            data_out=data_out,
        )
  • Initiates the BSM2Base object with default parameters, setting up the simulation environment for the BSM2 model
bsm2_base.py
        # definition of the objects:
        self.input_splitter = Splitter(sp_type=2)
        self.bypass_plant = Splitter()
        self.combiner_primclar_pre = Combiner()
        self.primclar = PrimaryClarifier(
            primclarinit.VOL_P,
            primclarinit.YINIT1,
            primclarinit.PAR_P,
            asm1init.PAR1,
            primclarinit.XVECTOR_P,
            tempmodel=tempmodel,
            activate=activate,
        )
        self.combiner_primclar_post = Combiner()
bsm2_base.py
        self.bypass_reactor = Splitter()
        self.combiner_reactor = Combiner()
        self.reactor1 = ASM1Reactor(
            reginit.KLA1,
            asm1init.VOL1,
            asm1init.YINIT1,
            asm1init.PAR1,
            reginit.CARB1,
            reginit.CARBONSOURCECONC,
            tempmodel=tempmodel,
            activate=activate,
        )
        self.reactor2 = ASM1Reactor(
            reginit.KLA2,
            asm1init.VOL2,
            asm1init.YINIT2,
            asm1init.PAR2,
            reginit.CARB2,
            reginit.CARBONSOURCECONC,
            tempmodel=tempmodel,
            activate=activate,
        )
        self.reactor3 = ASM1Reactor(
            reginit.KLA3,
            asm1init.VOL3,
            asm1init.YINIT3,
            asm1init.PAR3,
            reginit.CARB3,
            reginit.CARBONSOURCECONC,
            tempmodel=tempmodel,
            activate=activate,
        )
        self.reactor4 = ASM1Reactor(
            reginit.KLA4,
            asm1init.VOL4,
            asm1init.YINIT4,
            asm1init.PAR4,
            reginit.CARB4,
            reginit.CARBONSOURCECONC,
            tempmodel=tempmodel,
            activate=activate,
        )
        self.reactor5 = ASM1Reactor(
            reginit.KLA5,
            asm1init.VOL5,
            asm1init.YINIT5,
            asm1init.PAR5,
            reginit.CARB5,
            reginit.CARBONSOURCECONC,
            tempmodel=tempmodel,
            activate=activate,
        )
        self.splitter_reactor = Splitter()
        self.settler = Settler(
            settler1dinit.DIM,
            settler1dinit.LAYER,
            asm1init.QR,
            asm1init.QW,
            settler1dinit.settlerinit,
            settler1dinit.SETTLERPAR,
            asm1init.PAR1,
            tempmodel,
            settler1dinit.MODELTYPE,
        )
        self.combiner_effluent = Combiner()
bsm2_base.py
        self.thickener = Thickener(thickenerinit.THICKENERPAR)
        self.splitter_thickener = Splitter()
        self.combiner_adm1 = Combiner()
        self.adm1_reactor = ADM1Reactor(
            adm1init.DIGESTERINIT, adm1init.DIGESTERPAR, adm1init.INTERFACEPAR, adm1init.DIM_D
        )
        self.dewatering = Dewatering(dewateringinit.DEWATERINGPAR)
        self.storage = Storage(storageinit.VOL_S, storageinit.ystinit, tempmodel, activate)
        self.splitter_storage = Splitter()

Initialization of evaluation objects and variables to collect data for later evaluation.

bsm2_base.py
        self.performance = PlantPerformance(pp_init.PP_PAR)
bsm2_base.py
        self.y_in = self.data_in[:, 1:]

        self.ys_tss_internal = np.zeros(settler1dinit.LAYER[1])
        self.yd_out = np.zeros(51)
        self.yst_vol = 0
        (
            self.yst_sp_p,
            self.yt_sp_p,
            self.y_out1,
            self.y_out2,
            self.y_out3,
            self.y_out4,
            self.y_out5,
            self.ys_r,
            self.ys_was,
            self.ys_of,
            self.yp_uf,
            self.yp_of,
            self.yp_internal,
            self.yt_uf,
            self.yd_in,
            self.yi_out2,
            self.ydw_s,
            self.yst_out,
            self.yst_sp_as,
            self.yt_sp_as,
            self.y_out5_r,
            self.y_eff,
        ) = self._create_copies(self.y_in[0], 22)
  • Initializes arrays and variables for the wastewater or sludge streams that flow between the wastewater treatment plant objects

At first for every wastewater and sludge stream the influent stream y_in is used to prevent that negative flow rates are calculated.

bsm2_base.py
        self.y_in_all = np.zeros((len(self.simtime), 21))
        self.y_eff_all = np.zeros((len(self.simtime), 21))
        self.y_in_bp_all = np.zeros((len(self.simtime), 21))
        self.to_primary_all = np.zeros((len(self.simtime), 21))
        self.prim_in_all = np.zeros((len(self.simtime), 21))
        self.qpass_plant_all = np.zeros((len(self.simtime), 21))
        self.qpassplant_to_as_all = np.zeros((len(self.simtime), 21))
        self.qpassAS_all = np.zeros((len(self.simtime), 21))
        self.to_as_all = np.zeros((len(self.simtime), 21))
        self.feed_settler_all = np.zeros((len(self.simtime), 21))
        self.qthick2AS_all = np.zeros((len(self.simtime), 21))
        self.qthick2prim_all = np.zeros((len(self.simtime), 21))
        self.qstorage2AS_all = np.zeros((len(self.simtime), 21))
        self.qstorage2prim_all = np.zeros((len(self.simtime), 21))
        self.sludge_all = np.zeros((len(self.simtime), 21))

        self.y_out1_all = np.zeros((len(self.simtime), 21))
        self.y_out2_all = np.zeros((len(self.simtime), 21))
        self.y_out3_all = np.zeros((len(self.simtime), 21))
        self.y_out4_all = np.zeros((len(self.simtime), 21))
        self.y_out5_all = np.zeros((len(self.simtime), 21))
        self.ys_r_all = np.zeros((len(self.simtime), 21))
        self.ys_was_all = np.zeros((len(self.simtime), 21))
        self.ys_of_all = np.zeros((len(self.simtime), 21))
        self.ys_tss_internal_all = np.zeros((len(self.simtime), settler1dinit.LAYER[1]))
        self.yp_uf_all = np.zeros((len(self.simtime), 21))
        self.yp_of_all = np.zeros((len(self.simtime), 21))
        self.yi_out2_all = np.zeros((len(self.simtime), 21))
        self.yst_out_all = np.zeros((len(self.simtime), 21))
        self.yst_vol_all = np.zeros((len(self.simtime), 2))
        self.ydw_s_all = np.zeros((len(self.simtime), 21))
        self.yt_uf_all = np.zeros((len(self.simtime), 21))
        self.yp_internal_all = np.zeros((len(self.simtime), 21))
        self.yd_out_all = np.zeros((len(self.simtime), 51))
        self.yt_uf_all = np.zeros((len(self.simtime), 21))
  • Initializes arrays to collect data from the wastewater or sludge streams
bsm2_base.py
        self.klas = np.array([reginit.KLA1, reginit.KLA2, reginit.KLA3, reginit.KLA4, reginit.KLA5])
        # scenario 5, 75th percentile, 50% reduction when S_NH below 4g/m3
        # self.controller = ControllerOxygen(self.timestep[0], 0.75, klas, 0.5, 4)

        self.sludge_height = 0

        self.ae = 0
        self.pe = 0
        self.me = 0
        self.heat_demand = 0
        self.iqi_all = np.zeros(len(self.simtime))
        self.eqi_all = np.zeros(len(self.simtime))
        self.oci_all = np.zeros(len(self.simtime))
        self.perf_factors_all = np.zeros((len(self.simtime), 12))
        self.violation_all = np.zeros(len(self.simtime))

        self.qintr = asm1init.QINTR
        self.y_out5_r[14] = self.qintr
  • Initializes klas array with all the KLa values for every activated sludge reactor with initial parameters of reginit_bsm2

  • Initializes sludge_height variable for the continuous signal of sludge blanket level of the Settler object settler

  • Initializes variable ae, pe, me and heat_demand for collection of aeration energy, pumping energy, mixing energy and heat demand data

  • Initializes array iqi_all, eqi_all, oci_all, perf_factors_all, and violation_all for the collection of the influent quality index, effluent quality index, operation cost index, performance factors and violation data

  • Defines y_out5_r[14], the flow rate of the internal recirculation after the fifth activated sludge reactor with initial parameters of asm1init_bsm2


Simulation loop

The simulation loop is defined in the step method, where wastewater treatment plant objects are connected with each other through wastewater and sludge streams.

Most wastewater and sludge flows in BSM2 are represented in the ASM1 (Activated Sludge Model No. 1) format as an array, containing 21 standard parameters (concentrations, flow rate, temperature and dummy states) to describe the stream. For more information visit the documentation of the combiner and splitter.

bsm2_base.py
    def step(self, i: int, *args, **kwargs):
  • Defines the step method for the simulation loop

It simulates one time step of the BSM2 model with the index of the current time step i.

bsm2_base.py
        # timestep = timesteps[i]
        step: float = self.simtime[i]
        stepsize: float = self.timesteps[i]

        self.reactor1.kla, self.reactor2.kla, self.reactor3.kla, self.reactor4.kla, self.reactor5.kla = self.klas
  • Sets up the current simulation time step and the time step size stepsize for the i th iteration of the simulation

  • Updates all five reactors with the corresponding oxygen transfer coefficients (kla attributes) from the klas array

bsm2_base.py
        # get influent data that is smaller than and closest to current time step
        y_in_timestep = self.y_in[np.where(self.data_time <= step)[0][-1], :]

        iqi = self.performance.iqi(y_in_timestep)[0]
        self.iqi_all[i] = iqi
  • Defines the wastewater stream y_in_timestep that goes into the plant influent

  • Collects data of the iqi for every time step in the iqi_all array

Method PlantPerformance.iqi calculates the influent quality index

I/O Variable Description
Input y_in_timestep Wastewater stream that goes into the plant influent
Output iqi Influent quality index of the plant influent y_in_timestep
bsm2_base.py
        yp_in_c, y_in_bp = self.input_splitter.output(y_in_timestep, (0.0, 0.0), float(reginit.QBYPASS))
        y_plant_bp, y_in_as_c = self.bypass_plant.output(y_in_bp, (1 - reginit.QBYPASSPLANT, reginit.QBYPASSPLANT))

        yp_in = self.combiner_primclar_pre.output(yp_in_c, self.yst_sp_p, self.yt_sp_p)
        self.yp_uf, self.yp_of, self.yp_internal = self.primclar.output(stepsize, step, yp_in)
        y_c_as_bp = self.combiner_primclar_post.output(self.yp_of[:21], y_in_as_c)

Splitters of type 1 (default) separate streams into multiple by a given split ratio and splitters of type 2 separate single streams into two, if a given flow rate threshold is exceeded.

Method Splitter.output; Splitter after plant influent, that splits when plant influent is overflowing; Type 2 Splitter with flow rate threshold of 60000 m³/d from reginit_bsm2

I/O Variable Description
Input y_in_timestep Wastewater stream that goes into the plant influent
Output yp_in_c Wastewater stream that goes to the primary clarifier Combiner combiner_primclar_pre
Output y_in_bp Bypassed wastewater stream that goes to the Splitter bypass_plant

Method Splitter.output; Bypass splitter, that directs the overflow either to the activated sludge system or directly to the plant effluent, in case of an overflowing plant influent (default: activated sludge system); Type 1 Splitter with split ratio from reginit_bsm2

I/O Variable Description
Input y_in_bp Bypassed wastewater stream from the plant influent Splitter input_splitter
Output y_plant_bp Bypassed wastewater stream that goes to the plant effluent Combiner combiner_effluent
Output y_in_as_c Bypassed wastewater stream that goes to activated sludge system Combiner combiner_primclar_post

Method Combiner.output; Combiner before primary clarifier

I/O Variable Description
Input yp_in_c Wastewater stream from the plant influent Splitter input_splitter
Input yst_sp_p Wastewater stream from the wastewater storage Splitter splitter_storage
Input yt_sp_p Wastewater stream from the thickener Splitter splitter_thickener
Output yp_in Combined wastewater stream that goes into the PrimaryClarifier primclar

Method PrimaryClarifier.output; Separates wastewater into two streams - primary effluent (overflow) and primary sludge (underflow); Further information in the Primary Clarifier documentation

I/O Variable Description
Input yp_in Combined wastewater stream from the plant influent Combiner combiner_primclar_pre
Output yp_uf Primary sludge (underflow) that goes to the anaerobic digester Combiner combiner_adm1
Output yp_of Primary effluent (overflow) that goes to the activated sludge system Combiner combiner_primclar_post
- yp_internal Internal wastewater for evaluation purposes

Method Combiner.output; Combiner after primary clarifier

I/O Variable Description
Input yp_of Primary effluent (overflow) from the PrimaryClarifier primclar
Input y_in_as_c Bypassed wastewater stream from the plant influent Splitter bypass_plant
Output y_c_as_bp Wastewater stream that goes to the Splitter bypass_reactor
bsm2_base.py
        y_bp_as, y_as_bp_c_eff = self.bypass_reactor.output(y_c_as_bp, (1 - reginit.QBYPASSAS, reginit.QBYPASSAS))
        y_in1 = self.combiner_reactor.output(self.ys_r, y_bp_as, self.yst_sp_as, self.yt_sp_as, self.y_out5_r)
        self.y_out1 = self.reactor1.output(stepsize, step, y_in1)
        self.y_out2 = self.reactor2.output(stepsize, step, self.y_out1)
        self.y_out3 = self.reactor3.output(stepsize, step, self.y_out2)
        self.y_out4 = self.reactor4.output(stepsize, step, self.y_out3)
        self.y_out5 = self.reactor5.output(stepsize, step, self.y_out4)
        ys_in, self.y_out5_r = self.splitter_reactor.output(
            self.y_out5, (max(self.y_out5[14] - self.qintr, 0.0), float(self.qintr))
        )
        self.ys_r, self.ys_was, self.ys_of, _, self.ys_tss_internal = self.settler.output(stepsize, step, ys_in)

Method Splitter.output; Bypass splitter before activated sludge system, that bypasses the entire primary clarifier effluent to the plant effluent if activated (default: not activated); Type 1 Splitter with split ratio from reginit_bsm2

I/O Variable Description
Input y_c_as_bp Combined wastewater stream from the post primary clarifier Splitter combiner_primclar_post
Output y_bp_as Wastewater stream that goes to the activated sludge system Combiner combiner_reactor
Output y_as_bp_c_eff Bypassed wastewater stream that goes to the plant effluent Combiner combiner_effluent

Method Combiner.output; Combiner before activated sludge system

I/O Variable Description
Input ys_r Returned sludge stream from the Settler settler
Input y_bp_as Wastewater stream from the post primary clarifier Splitter combiner_primclar_post
Input yst_sp_as Wastewater stream from wastewater storage Splitter splitter_storage
Input yt_sp_as Wastewater stream from the thickener Splitter splitter_thickener
Input y_out5_r Wastewater stream from the post activated sludge system Splitter splitter_reactor
Output y_in1 Wastewater stream that goes into the first ASM1Reactor reactor1

Method ASM1Reactor.output; Activated sludge reactor with anoxic conditions (KLa = 0) for removal of nitrogen (denitrification); Further information in the Activated Sludge Reactor documentation

I/O Variable Description
Input y_in1 Combined wastewater stream from the Combiner combiner_reactor
Output y_out1 Wastewater stream that goes into the second ASM1Reactor reactor2

Method ASM1Reactor.output; Activated sludge reactor with anoxic conditions (KLa = 0) for denitrification; Further information in the Activated Sludge Reactor documentation

I/O Variable Description
Input y_out1 Wastewater stream from the first ASM1Reactor reactor1
Output y_out2 Wastewater stream that goes into the third ASM1Reactor reactor3

Method ASM1Reactor.output; Activated sludge reactor with aerobic conditions (KLa = 120) for carbon decomposition and nitrification; Further information in the Activated Sludge Reactor documentation

I/O Variable Description
Input y_out2 Wastewater stream from the second ASM1Reactor reactor2
Output y_out3 Wastewater stream that goes into the fourth ASM1Reactor reactor4

Method ASM1Reactor.output; Activated sludge reactor with aerobic conditions (KLa = 120) for carbon decomposition and nitrification; Further information in the Activated Sludge Reactor documentation

I/O Variable Description
Input y_out3 Wastewater stream from the third ASM1Reactor reactor3
Output y_out4 Wastewater stream that goes into the fifth ASM1Reactor reactor5

Method ASM1Reactor.output; Activated sludge reactor with aerobic conditions (KLa = 60) for carbon decomposition and nitrification; Further information in the Activated Sludge Reactor documentation

I/O Variable Description
Input y_out4 Wastewater stream from the fourth ASM1Reactor reactor4
Output y_out5 Wastewater stream that goes to the post activated sludge Splitter splitter_reactor

Method Splitter.output; Splitter after activated sludge system, for internal sludge recirculation; Type 1 Splitter with split ratio from qintr

I/O (21) Variable Description
Input y_out5 Wastewater stream from the fifth ASM1Reactor reactor5
Output ys_in Wastewater stream that goes into the Settler settler
Output y_out5_r Internal recirculation stream that goes back to the activated sludge system Combiner combiner_reactor

Method Settler.output; Separates wastewater into two streams - effluent (overflow) and sludge (underflow); Further information in the Settler documentation

I/O Variable Description
Input ys_in Wastewater stream from the post activated sludge Splitter splitter_reactor
Output ys_r Returned sludge stream that goes to the activated sludge system Combiner combiner_reactor
Output ys_was Waste sludge stream that goes into the Thickener thickener
Output ys_of Wastewater stream that goes to the plant effluent Combiner combiner_effluent
Output _ Sludge height for evaluation purposes (not used)
Output ys_tss_internal Internal total suspended solids (TSS) states of the settler for evaluation purposes
bsm2_base.py
        self.y_eff = self.combiner_effluent.output(y_plant_bp, y_as_bp_c_eff, self.ys_of)

        eqi = self.performance.eqi(self.ys_of, y_plant_bp, y_as_bp_c_eff)[0]
        self.eqi_all[i] = eqi

        self.yt_uf, yt_of = self.thickener.output(self.ys_was)
        self.yt_sp_p, self.yt_sp_as = self.splitter_thickener.output(
            yt_of, (1 - reginit.QTHICKENER2AS, reginit.QTHICKENER2AS)
        )
  • Collects data of the eqi for every time step in the eqi_all array

Method Combiner.output; Combiner before the plant effluent

I/O (27) Variable Description
Input y_plant_bp Bypassed wastewater stream from the plant influent Splitter bypass_plant
Input y_as_bp_c_eff Bypassed wastewater stream from the pre activated sludge system Splitter bypass_reactor
Input ys_of Wastewater stream from the Settler settler
Output y_eff Wastewater stream that goes in the plant effluent

Method PlantPerformance.eqi calculates the effluent quality index

I/O Variable Description
Input ys_of Wastewater stream from the Settler settler
Input y_plant_bp Bypassed wastewater stream from the plant influent Splitter bypass_plant
Input y_as_bp_c_eff Bypassed wastewater stream from the pre activated sludge system Splitter bypass_reactor
Output eqi Effluent quality index of the plant effluent

Method Thickener.output; Separates the stream into residual effluent (overflow) and thickened sludge (underflow); Further information in the Thickener documentation

I/O Variable Description
Input ys_was Waste sludge stream from the Settler settler
Output yt_uf Thickened sludge (underflow) that goes to the anaerobic digester Combiner combiner_adm1
Output yt_of Residual effluent (overflow) that goes to the post thickener Splitter splitter_thickener

Method Splitter.output; Splitter after thickener, that directs the entire flow either to the primary clarifier or to the activated sludge system (default: primary clarifier); Type 1 Splitter with split ratio from reginit_bsm2

I/O Variable Description
Input yt_of Residual effluent (overflow) from the Thickener thickener
Output yt_sp_p Residual effluent (overflow) that goes to the pre primary clarifier Combiner combiner_primclar_pre
Output yt_sp_as Residual effluent (overflow) that goes to the pre activated sludge system Combiner combiner_reactor
bsm2_base.py
        self.yd_in = self.combiner_adm1.output(self.yt_uf, self.yp_uf)
        self.yi_out2, self.yd_out, _ = self.adm1_reactor.output(stepsize, step, self.yd_in, reginit.T_OP)

        self.ydw_s, ydw_r = self.dewatering.output(self.yi_out2)

        self.yst_out, self.yst_vol = self.storage.output(stepsize, step, ydw_r, reginit.QSTORAGE)
        self.yst_sp_p, self.yst_sp_as = self.splitter_storage.output(
            self.yst_out, (1 - reginit.QSTORAGE2AS, reginit.QSTORAGE2AS)
        )

Method Combiner.output; Combiner before anaerobic digester

I/O Variable Description
Input yt_uf Thickened sludge (underflow) from the Thickener thickener
Input yp_uf Primary sludge (underflow) from the PrimaryClarifier primclar
Output yd_in Combined sludge stream that goes into the ADM1Reactor adm1_reactor

Method ADM1Reactor.output; Breaks down sewage sludge to produce methane gas; Further information in the Anaerobic Digester documentation

I/O Variable Description
Input yd_in Combined sludge stream from the anaerobic digester Combiner combiner_adm1
Output yi_out2 Fermented sludge stream (ASM1 format) that goes into the Dewatering dewatering
Output yd_out Fermented sludge stream (ADM1 format) for evaluation purposes
Output _ Combined sludge stream (turned in ADM1 format) from the anaerobic digester Combiner combiner_adm1 (not used)

Method Dewatering.output; Separates the stream into reject wastewater (overflow) and dewatered/waste sludge (underflow); Further information in the Dewatering documentation

I/O Variable Description
Input yi_out2 Fermented sludge stream from the ADM1Reactor adm1_reactor
Output ydw_s Dewatered/waste sludge (underflow) that leaves the plant
Output ydw_r Reject wastewater (overflow) that goes into the Storage storage

Method Storage.output; Holds reject wastewater before recycling it back to either primary clarifier or the activated sludge system; Further information in the Storage documentation

I/O Variable Description
Input ydw_r Reject wastewater (overflow) from the Dewatering dewatering
Output yst_out Stored wastewater that goes to the post storage Splitter splitter_storage
Output yst_vol Volume of the storage tank for evaluation purposes

Method Splitter.output; Splitter after wastewater storage, that directs the entire flow either to the primary clarifier or to the activated sludge system (default: primary clarifier); Type 1 Splitter with split ratio from reginit_bsm2

I/O Variable Description
Input yst_out Stored wastewater from the Storage storage
Output yst_sp_p Stored wastewater that goes to the pre primary clarifier Combiner combiner_primclar_pre
Output yst_sp_as Stored wastewater that goes to the activated sludge system Combiner combiner_reactor

In the simulation loop data is also collected from each time step to evaluate the plant performance and wastewater treatment parameters.

bsm2_base.py
        vol = np.array(
            [
                self.reactor1.volume,
                self.reactor2.volume,
                self.reactor3.volume,
                self.reactor4.volume,
                self.reactor5.volume,
                self.adm1_reactor.volume_liq,
            ]
        )
        sosat = np.array([asm1init.SOSAT1, asm1init.SOSAT2, asm1init.SOSAT3, asm1init.SOSAT4, asm1init.SOSAT5])
        self.ae = self.performance.aerationenergy_step(self.klas, vol[0:5], sosat)
        flows = np.array([self.qintr, asm1init.QR, asm1init.QW, self.yp_uf[14], self.yt_uf[14], self.ydw_s[14]])
        self.pe = self.performance.pumpingenergy_step(flows, pp_init.PP_PAR[10:16])
        self.me = self.performance.mixingenergy_step(self.klas, vol, pp_init.PP_PAR[16])
  • Initializes vol array with the volume for each activated sludge reactor and the anaerobic digester

  • Initializes sosat array with the saturated oxygen concentrations for each activated sludge reactor

  • Initializes flows array with all flow rates that are operated by a pump

Method PlantPerformance.aerationenergy_step evaluates the aeration energy of the plant during the evaluation time

I/O Variable Description
Input klas Array with all the KLa values for the activated sludge reactors
Input vol[0:5] Array with all the volumes of the activated sludge reactors
Input sosat Array with the saturated oxygen concentrations for the activated sludge reactors
Output ae Aeration energy during the evaluation time

Method PlantPerformance.pumpingenergy_step evaluates the pumping energy of the plant during the evaluation time

I/O Variable Description
Input flows Array with all the KLa values for the activated sludge reactors
Input pp_init.PP_PAR[10:16] Array with the pumping energy factors for the individual flows from plantperformanceinit_bsm2
Output pe Pumping energy during the evaluation time

Method PlantPerformance.mixingenergy_step evaluates the mixing energy of the plant during the evaluation time

I/O Variable Description
Input klas Array with all the KLa values for the activated sludge reactors and the anaerobic digester
Input vol Array with the volume for each activated sludge reactor and the anaerobic digester
Input pp_init.PP_PAR[16] Mixing energy factor for anaerobic digester unit from plantperformanceinit_bsm2
Output me Pumping energy during the evaluation time
bsm2_base.py
        tss_mass = self.performance.tss_mass_bsm2(
            self.yp_of,
            self.yp_uf,
            self.yp_internal,
            self.y_out1,
            self.y_out2,
            self.y_out3,
            self.y_out4,
            self.y_out5,
            self.ys_tss_internal,
            self.yd_out,
            self.yst_out,
            self.yst_vol,
        )

Method PlantPerformance.tss_mass_bsm2 calculates the sludge production of the BSM2 plant setup

I/O Variable Description
Input yp_of Primary clarifier overflow (effluent) concentrations
Input yp_uf Primary clarifier underflow (sludge) concentrations
Input yp_internal Primary clarifier internal (basically influent) concentrations
Input y_out1 Concentrations of the 21 components after the first ASM reactor
Input y_out2 Concentrations of the 21 components after the second ASM reactor
Input y_out3 Concentrations of the 21 components after the third ASM reactor
Input y_out4 Concentrations of the 21 components after the fourth ASM reactor
Input y_out5 Concentrations of the 21 components after the fifth ASM reactor
Input ys_tss_internal Total suspended solids (TSS) concentrations of the internals of the settler
Input yd_out Concentrations of the 51 components and gas phase parameters after the digester
Input yst_out Concentrations of the 21 components in the effluent of the storage tank
Input yst_vol Current volume of the storage tank
Output tss_mass Sludge production of the BSM2 plant setup
bsm2_base.py
        ydw_s_tss_flow = self.performance.tss_flow(self.ydw_s)
        y_eff_tss_flow = self.performance.tss_flow(self.y_eff)
        carb = reginit.CARB1 + reginit.CARB2 + reginit.CARB3 + reginit.CARB4 + reginit.CARB5
        added_carbon_mass = self.performance.added_carbon_mass(carb, reginit.CARBONSOURCECONC)
        self.heat_demand = self.performance.heat_demand_step(self.yd_in, reginit.T_OP)[0]
        ch4_prod, h2_prod, co2_prod, q_gas = self.performance.gas_production(self.yd_out, reginit.T_OP)
  • Calculates float variable carb with the sum of external carbon flow rate that goes into the activated sludge system from reginit_bsm2

Method PlantPerformance.tss_flow calculates the total suspended solids (TSS) flow out of a reactor

I/O Variable Description
Input ydw_s Waste sludge (underflow) concentrations of the dewatering unit
Output ydw_s_tss_flow Total suspended solids (TSS) flow of the dewatering waste sludge stream

Method PlantPerformance.tss_flow calculates the total suspended solids (TSS) flow out of a reactor

I/O Variable Description
Input y_eff Effluent wastewater stream
Output y_eff_tss_flow Total suspended solids (TSS) flow of the effluent stream

Method PlantPerformance.added_carbon_mass calculates the total added carbon mass

I/O Variable Description
Input carb Sum of external carbon flow rate that goes in AS system
Input reginit.CARBONSOURCECONC External carbon source concentration from reginit_bsm2
Output added_carbon_mass Total carbon mass added into the AS system

Method PlantPerformance.heat_demand_step calculates the heating demand of the sludge flow to the anaerobic digester

I/O Variable Description
Input yd_in Sludge stream that goes into the anaerobic digester
Input reginit.T_OP Operating temperature of the anaerobic digester from reginit_bsm2
Output heat_demand Heat demand of the sludge flow that goes into the anaerobic digester

Method PlantPerformance.gas_production calculates the gas production of the anaerobic digester

I/O Variable Description
Input yd_out Sludge stream that goes out of the anaerobic digester
Input reginit.T_OP Operating temperature of the anaerobic digester from reginit_bsm2
Output ch4_prod Methane production of the anaerobic digester
Output h2_prod Hydrogen production of the anaerobic digester
Output co2_prod Carbon dioxide production of the anaerobic digester
Output q_gas Total gas flow rate of the anaerobic digester
bsm2_base.py
        # This calculates an approximate oci value for each time step,
        # neglecting changes in the tss mass inside the whole plant
        self.oci_all[i] = self.performance.oci(
            self.pe * 24,
            self.ae * 24,
            self.me * 24,
            ydw_s_tss_flow,
            added_carbon_mass,
            self.heat_demand * 24,
            ch4_prod,
        )
  • Collects oci data for every time step in the oci_all array

Method PlantPerformance.oci calculates the operational cost index of the plant

I/O Variable Description
Input pe * 24 Pumping energy of the BSM2 plant setup
Input ae * 24 Aeration energy of the BSM2 plant setup
Input me * 24 Mixing energy of the BSM2 plant setup
Input ydw_s_tss_flow Total suspended solids (TSS) flow of the dewatering waste sludge stream
Input added_carbon_mass Total carbon mass added into the AS system
Input heat_demand * 24 Heat demand of the sludge flow that goes into the anaerobic digester
Input ch4_prod Methane production of the anaerobic digester
Input q_gas Total gas flow rate of the anaerobic digester
Output oci_all[i] Operational cost index of the plant
bsm2_base.py
        # These values are used to calculate the exact performance values at the end of the simulation
        self.perf_factors_all[i, :12] = [
            self.pe * 24,
            self.ae * 24,
            self.me * 24,
            ydw_s_tss_flow,
            y_eff_tss_flow,
            tss_mass,
            added_carbon_mass,
            self.heat_demand * 24,
            ch4_prod,
            h2_prod,
            co2_prod,
            q_gas,
        ]
  • Collects all performance values for each time step in perf_factors_all array
bsm2_base.py
        self.y_in_all[i] = y_in_timestep
        self.y_eff_all[i] = self.y_eff
        self.y_in_bp_all[i] = y_in_bp
        self.to_primary_all[i] = yp_in_c
        self.prim_in_all[i] = yp_in
        self.qpass_plant_all[i] = y_plant_bp
        self.qpassplant_to_as_all[i] = y_in_as_c
        self.qpassAS_all[i] = y_as_bp_c_eff
        self.to_as_all[i] = y_bp_as
        self.feed_settler_all[i] = ys_in
        self.qthick2AS_all[i] = self.yt_sp_as
        self.qthick2prim_all[i] = self.yt_sp_p
        self.qstorage2AS_all[i] = self.yst_sp_as
        self.qstorage2prim_all[i] = self.yst_sp_p
        self.sludge_all[i] = self.ydw_s

        # data for calculation of final oci
        self.violation_all[i] = self.performance.violation_step(self.y_eff[SNH], 4)[0]
        self.y_out1_all[i] = self.y_out1
        self.y_out2_all[i] = self.y_out2
        self.y_out3_all[i] = self.y_out3
        self.y_out4_all[i] = self.y_out4
        self.y_out5_all[i] = self.y_out5
        self.ys_r_all[i] = self.ys_r
        self.ys_was_all[i] = self.ys_was
        self.ys_of_all[i] = self.ys_of
        self.ys_tss_internal_all[i] = self.ys_tss_internal
        self.yp_uf_all[i] = self.yp_uf
        self.yp_of_all[i] = self.yp_of
        self.yt_uf_all[i] = self.yt_uf
        self.yd_out_all[i] = self.yd_out
        self.yi_out2_all[i] = self.yi_out2
        self.yst_out_all[i] = self.yst_out
        self.yst_vol_all[i] = self.yst_vol, step
        self.ydw_s_all[i] = self.ydw_s
        self.yp_internal_all[i] = self.yp_internal
  • Collecting all wastewater and sludge stream data for every time step in arrays

Also see the full source code
modbsm2_base.py