Skip to content

plantperformance

PlantPerformance

PlantPerformance(pp_par)

Creates a PlantPerformance object.

Parameters:

Name Type Description Default
pp_par ndarray(17)

Plant performance parameters.

[TOTALCODEMAX, TOTALNEMAX, SNHEMAX, TSSEMAX, BOD5EMAX, BSS, BCOD, BNKJ, BNO, BBOD5, PF_QINTR, PF_QR, PF_QW, PF_QPU, PF_QTU, PF_QDO, ME_AD_UNIT]

required
Source code in src/bsm2_python/bsm2/plantperformance.py
def __init__(self, pp_par):
    self.pp_par = pp_par

aerationenergy_step

aerationenergy_step(kla, vol, sosat)

Returns the aeration energy of the plant during the evaluation time.

Parameters:

Name Type Description Default
kla ndarray

KLa values of all activated sludge reactor compartments at every time step of the evaluation time [d⁻¹].

[KLA1, KLA2, KLA3,...]

required
vol ndarray

Volume of each activated sludge reactor compartment [m³].

[VOL1, VOL2, VOL3,...]

required
sosat ndarray

Oxygen saturation concentration in each activated sludge reactor compartment [%].

[SOSAT1, SOSAT2, SOSAT3,...]

required

Returns:

Name Type Description
aerationenergy float

Aeration energy during the evaluation time [kW].

Source code in src/bsm2_python/bsm2/plantperformance.py
@staticmethod
def aerationenergy_step(kla, vol, sosat):
    """Returns the aeration energy of the plant during the evaluation time.

    Parameters
    ----------
    kla : np.ndarray
        KLa values of all activated sludge reactor compartments at every time step of the evaluation time [d⁻¹]. \n
        [KLA1, KLA2, KLA3,...]
    vol : np.ndarray
        Volume of each activated sludge reactor compartment [m³]. \n
        [VOL1, VOL2, VOL3,...]
    sosat : np.ndarray
        Oxygen saturation concentration in each activated sludge reactor compartment [%]. \n
        [SOSAT1, SOSAT2, SOSAT3,...]

    Returns
    -------
    aerationenergy : float
        Aeration energy during the evaluation time [kW].
    """

    aerationenergy = sum(sosat * vol * kla) / (1.8 * 1000) / 24
    return aerationenergy

pumpingenergy_step

pumpingenergy_step(flows, pumpfactor)

Returns the pumping energy of the plant during the evaluation time.

Parameters:

Name Type Description Default
flows ndarray(n)

Flow rates at every time step of the evaluation time
[m³ ⋅ d⁻¹].

For BSM2: [Q_INTR, Q_R, Q_W, Q_PU, Q_TU, Q_DO] For BSM1: [Q_INTR, Q_R, Q_W]

required
pumpfactor ndarray(n)

Pumping energy factor for each flow [kWh ⋅ m⁻³].

For BSM2: [PF_QINTR, PF_QR, PF_QW, PF_QPU, PF_QTU, PF_QDO] For BSM1: [PF_QINTR, PF_QR, PF_QW]

required

Returns:

Name Type Description
pe float

Pumping energy during the evaluation time [kW].

Source code in src/bsm2_python/bsm2/plantperformance.py
@staticmethod
def pumpingenergy_step(flows, pumpfactor):
    """Returns the pumping energy of the plant during the evaluation time.

    Parameters
    ----------
    flows : np.ndarray(n)
        Flow rates at every time step of the evaluation time <br>[m³ ⋅ d⁻¹]. \n
        For BSM2: [Q_INTR, Q_R, Q_W, Q_PU, Q_TU, Q_DO]
        For BSM1: [Q_INTR, Q_R, Q_W]
    pumpfactor : np.ndarray(n)
        Pumping energy factor for each flow [kWh ⋅ m⁻³]. \n
        For BSM2: [PF_QINTR, PF_QR, PF_QW, PF_QPU, PF_QTU, PF_QDO]
        For BSM1: [PF_QINTR, PF_QR, PF_QW]

    Returns
    -------
    pe : float
        Pumping energy during the evaluation time [kW].
    """

    # sum of relevant flows * their pumpfactors in kWh/d, divided by 24 to get kW
    pe = sum(flows * pumpfactor) / 24
    return pe

mixingenergy_step

mixingenergy_step(kla, vol, me_ad=None)

Returns the mixing energy of the plant during the evaluation time.

Parameters:

Name Type Description Default
kla ndarray

KLa values of all activated sludge reactor compartments at every time step of the evaluation time [d⁻¹].

[KLA1, KLA2, KLA3,...]

required
vol ndarray

Volume of each activated sludge reactor compartment, including the anaerobic digester unit [m³].

[VOL1, VOL2, VOL3,..., ADM1_VOL_LIQ]

required
me_ad float(optional)

Mixing energy factor for the anaerobic digester unit. If not provided, anaerobic digestion is ignored
[kWh ⋅ m⁻³].

None

Returns:

Name Type Description
me float

Mixing energy during the evaluation time [kW].

Source code in src/bsm2_python/bsm2/plantperformance.py
@staticmethod
def mixingenergy_step(kla, vol, me_ad: float | None = None):
    """Returns the mixing energy of the plant during the evaluation time.

    Parameters
    ----------
    kla : np.ndarray
        KLa values of all activated sludge reactor compartments at every time step of the evaluation time [d⁻¹]. \n
        [KLA1, KLA2, KLA3,...]
    vol : np.ndarray
        Volume of each activated sludge reactor compartment, including the anaerobic digester unit [m³]. \n
        [VOL1, VOL2, VOL3,..., ADM1_VOL_LIQ]
    me_ad : float (optional)
        Mixing energy factor for the anaerobic digester unit. If not provided, anaerobic digestion is ignored <br>
        [kWh ⋅ m⁻³].

    Returns
    -------
    me : float
        Mixing energy during the evaluation time [kW].
    """

    lim = 20
    me_asm = 0.005 * sum((kla[i] < lim) * vol[i] for i in range(len(kla)))
    me_adm = me_ad * vol[5] if me_ad is not None else 0
    me = me_asm + me_adm
    return me

violation_step

violation_step(arr_eff, limit)

Returns the time and percentage of time in which a certain component is over the limit value during the evaluation time.

Parameters:

Name Type Description Default
arr_eff float

Concentration of the component in the effluent at every time step of the evaluation time [g(COMP) ⋅ m⁻³].

required
limit float

Limit value of the component. Must have the same unit as the component [g(COMP) ⋅ m⁻³].

required

Returns:

Name Type Description
violationvalues bool

Array containing if a certain component is over the limit value during the evaluation time.

Source code in src/bsm2_python/bsm2/plantperformance.py
def violation_step(self, arr_eff, limit):
    """Returns the time and percentage of time in which a certain component is over the limit value during
    the evaluation time.

    Parameters
    ----------
    arr_eff : float
        Concentration of the component in the effluent at every time step of the evaluation time [g(COMP) ⋅ m⁻³].
    limit : float
        Limit value of the component. Must have the same unit as the component [g(COMP) ⋅ m⁻³].

    Returns
    -------
    violationvalues : bool
        Array containing if a certain component
        is over the limit value during the evaluation time.
    """

    arr_eff = self._reshape_if_float(arr_eff)
    # True if the component is over the limit value:
    violationvalues = np.array([arr_eff > limit])

    return violationvalues[0]

advanced_quantities

advanced_quantities(arr_eff, components=('kjeldahlN', 'totalN', 'COD', 'BOD5', 'BOD5e', 'X_TSS'), asm1par=asm1init.PAR1)

Takes an ASM1 array (single timestep or multiple timesteps) and returns advanced quantities of the effluent.

Currently supports the following components:

  • kjeldahlN: Total Kjeldahl nitrogen [g(N) ⋅ m⁻³]
  • totalN: Total nitrogen [g(N) ⋅ m⁻³]
  • COD: Chemical oxygen demand [g(COD) ⋅ m⁻³]
  • BOD5: Biological oxygen demand (5 days) [g(BOD) ⋅ m⁻³]
  • X_TSS: Total suspended solids [g(SS) ⋅ m⁻³]

Parameters:

Name Type Description Default
arr_eff ndarray(21) or ndarray(n, 21)

Array in ASM1 format.

[SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP, SD1, SD2, SD3, XD4, XD5]

required
components list[str](optional)

List of components to be calculated. Defaults to ['kjeldahlN', 'totalN', 'COD', 'BOD5', 'BOD5e', 'X_TSS']

('kjeldahlN', 'totalN', 'COD', 'BOD5', 'BOD5e', 'X_TSS')
asm1par ndarray(24)

Parameters for the activated sludge reactor.

[MU_H, K_S, K_OH, K_NO, B_H, MU_A, K_NH, K_OA, B_A, NY_G, K_A, K_H,K_X, NY_H, Y_H, Y_A, F_P, I_XB, I_XP, X_I2TSS, X_S2TSS, X_BH2TSS, X_BA2TSS, X_P2TSS]

PAR1

Returns:

Name Type Description
adv_eff ndarray

Array containing the choosen advanced quantities of the effluent.

Source code in src/bsm2_python/bsm2/plantperformance.py
def advanced_quantities(
    self, arr_eff, components=('kjeldahlN', 'totalN', 'COD', 'BOD5', 'BOD5e', 'X_TSS'), asm1par=asm1init.PAR1
):
    """Takes an ASM1 array (single timestep or multiple timesteps) and returns
    advanced quantities of the effluent.

    Currently supports the following components: \n
    - `kjeldahlN`: Total Kjeldahl nitrogen [g(N) ⋅ m⁻³]
    - `totalN`: Total nitrogen [g(N) ⋅ m⁻³]
    - `COD`: Chemical oxygen demand [g(COD) ⋅ m⁻³]
    - `BOD5`: Biological oxygen demand (5 days) [g(BOD) ⋅ m⁻³]
    - `X_TSS`: Total suspended solids [g(SS) ⋅ m⁻³]

    Parameters
    ----------
    arr_eff : np.ndarray(21) or np.ndarray(n, 21)
        Array in ASM1 format. \n
        [SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP,
        SD1, SD2, SD3, XD4, XD5]
    components : list[str] (optional)
        List of components to be calculated.
        Defaults to ['kjeldahlN', 'totalN', 'COD', 'BOD5', 'BOD5e', 'X_TSS']
    asm1par : np.ndarray(24)
        Parameters for the activated sludge reactor. \n
        [MU_H, K_S, K_OH, K_NO, B_H, MU_A, K_NH, K_OA, B_A, NY_G, K_A, K_H,K_X, NY_H,
        Y_H, Y_A, F_P, I_XB, I_XP, X_I2TSS, X_S2TSS, X_BH2TSS, X_BA2TSS, X_P2TSS]

    Returns
    -------
    adv_eff : np.ndarray
        Array containing the choosen advanced quantities of the effluent.
    """

    arr_eff = self._reshape_if_1d(arr_eff)
    adv_eff = np.zeros((arr_eff.shape[0], len(components)))

    for idx, component in enumerate(components):
        if component == 'kjeldahlN':
            adv_eff[:, idx] = (
                arr_eff[:, SNH]
                + arr_eff[:, SND]
                + arr_eff[:, XND]
                + asm1par[17] * (arr_eff[:, XBH] + arr_eff[:, XBA])
                + asm1par[18] * (arr_eff[:, XP] + arr_eff[:, XI])
            )
        elif component == 'totalN':
            adv_eff[:, idx] = (
                arr_eff[:, SNH]
                + arr_eff[:, SND]
                + arr_eff[:, XND]
                + asm1par[17] * (arr_eff[:, XBH] + arr_eff[:, XBA])
                + asm1par[18] * (arr_eff[:, XP] + arr_eff[:, XI])
                + arr_eff[:, SNO]
            )
        elif component == 'COD':
            adv_eff[:, idx] = (
                arr_eff[:, SS]
                + arr_eff[:, SI]
                + arr_eff[:, XS]
                + arr_eff[:, XI]
                + arr_eff[:, XBH]
                + arr_eff[:, XBA]
                + arr_eff[:, XP]
            )
        elif component == 'BOD5':
            adv_eff[:, idx] = 0.65 * (
                arr_eff[:, SS] + arr_eff[:, XS] + (1 - asm1par[16]) * (arr_eff[:, XBH] + arr_eff[:, XBA])
            )
        elif component == 'BOD5e':
            adv_eff[:, idx] = 0.25 * (
                arr_eff[:, SS] + arr_eff[:, XS] + (1 - asm1par[16]) * (arr_eff[:, XBH] + arr_eff[:, XBA])
            )
        elif component == 'X_TSS':
            adv_eff[:, idx] = 0.75 * (
                arr_eff[:, XS] + arr_eff[:, XP] + arr_eff[:, XI] + arr_eff[:, XBH] + arr_eff[:, XBA]
            )
        else:
            err = f"Component '{component}' not supported"
            raise ValueError(err)

    return adv_eff

iqi

iqi(y_in)

Returns the influent quality index (IQI).

Parameters:

Name Type Description Default
y_in ndarray(21) or ndarray(n, 21)

Array containing the values of the 21 components (13 ASM1 components, TSS, Q, T and 5 dummy states) of the influent to BSM1.

[SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP, SD1, SD2, SD3, XD4, XD5]

required

Returns:

Name Type Description
iqi float or ndarray

The value of the influent quality index of the stream
[kg(Pollution Units) ⋅ d⁻¹].

Source code in src/bsm2_python/bsm2/plantperformance.py
def iqi(self, y_in):
    """Returns the influent quality index (IQI).

    Parameters
    ----------
    y_in : np.ndarray(21) or np.ndarray(n, 21)
        Array containing the values of the 21 components
        (13 ASM1 components, TSS, Q, T and 5 dummy states) of the influent to BSM1. \n
        [SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP,
        SD1, SD2, SD3, XD4, XD5]

    Returns
    -------
    iqi : float or np.ndarray
        The value of the influent quality index of the stream <br>
        [kg(Pollution Units) ⋅ d⁻¹].
    """

    y_in = self._reshape_if_1d(y_in)

    adv_quant = self.advanced_quantities(y_in, ('kjeldahlN', 'totalN', 'COD', 'BOD5', 'X_TSS'))
    iqi = (
        (
            self.pp_par[BSS] * y_in[:, TSS]
            + self.pp_par[BCOD] * adv_quant[:, 2]
            + self.pp_par[BNKJ] * adv_quant[:, 0]
            + self.pp_par[BNO] * y_in[:, SNO]
            + self.pp_par[BBOD5] * adv_quant[:, 3]
        )
        * y_in[:, Q]
        / 1000
    )

    return iqi

eqi

eqi(ys_of, y_plant_bp=None, y_as_bp_c_eff=None)

Returns the effluent quality index (EQI).

Parameters:

Name Type Description Default
ys_of ndarray(21) or ndarray(n, 21)

Array containing the values of the 21 components (13 ASM1 components, TSS, Q, T and 5 dummy states) after the fifth ASM reactor.

[SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP, SD1, SD2, SD3, XD4, XD5]

required
y_plant_bp ndarray(21) or ndarray(n, 21)(optional)

Array containing the values of the 21 components. If not provided, the plant bypass is assumed to be 0.

(13 ASM1 components, TSS, Q, T and 5 dummy states) after the plant bypass.

[SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP, SD1, SD2, SD3, XD4, XD5]

None
y_as_bp_c_eff ndarray(21) or ndarray(n, 21)

Array containing the values of the 21 components If not provided, the reactor bypass is assumed to be 0.

(13 ASM1 components, TSS, Q, T and 5 dummy states) after the ASM bypass.

[SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP, SD1, SD2, SD3, XD4, XD5]

None

Returns:

Name Type Description
eqi float or ndarray

The value of the effluent quality index of the stream
[kg(Pollution Units) ⋅ d⁻¹].

Source code in src/bsm2_python/bsm2/plantperformance.py
def eqi(self, ys_of: np.ndarray, y_plant_bp: np.ndarray | None = None, y_as_bp_c_eff: np.ndarray | None = None):
    """Returns the effluent quality index (EQI).

    Parameters
    ----------
    ys_of : np.ndarray(21) or np.ndarray(n, 21)
        Array containing the values of the 21 components
        (13 ASM1 components, TSS, Q, T and 5 dummy states) after the fifth ASM reactor. \n
        [SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP,
        SD1, SD2, SD3, XD4, XD5]
    y_plant_bp : np.ndarray(21) or np.ndarray(n, 21) (optional)
        Array containing the values of the 21 components.
        If not provided, the plant bypass is assumed to be 0. \n
        (13 ASM1 components, TSS, Q, T and 5 dummy states) after the plant bypass. \n
        [SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP,
        SD1, SD2, SD3, XD4, XD5]
    y_as_bp_c_eff : np.ndarray(21) or np.ndarray(n, 21)
        Array containing the values of the 21 components
        If not provided, the reactor bypass is assumed to be 0. \n
        (13 ASM1 components, TSS, Q, T and 5 dummy states) after the ASM bypass. \n
        [SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP,
        SD1, SD2, SD3, XD4, XD5]

    Returns
    -------
    eqi: float or np.ndarray
        The value of the effluent quality index of the stream <br>[kg(Pollution Units) ⋅ d⁻¹].
    """
    ys_of = self._reshape_if_1d(ys_of)
    y_plant_bp = np.zeros(ys_of.shape) if y_plant_bp is None else self._reshape_if_1d(y_plant_bp)
    y_as_bp_c_eff = np.zeros(ys_of.shape) if y_as_bp_c_eff is None else self._reshape_if_1d(y_as_bp_c_eff)

    y_out5_aq = self.advanced_quantities(ys_of, ('kjeldahlN', 'totalN', 'COD', 'BOD5e', 'X_TSS'))
    y_p_bp_aq = self.advanced_quantities(y_plant_bp, ('kjeldahlN', 'totalN', 'COD', 'BOD5', 'X_TSS'))
    y_bp_as_aq = self.advanced_quantities(y_as_bp_c_eff, ('kjeldahlN', 'totalN', 'COD', 'BOD5', 'X_TSS'))

    qe = ys_of[:, Q] + y_plant_bp[:, Q] + y_as_bp_c_eff[:, Q]
    tsse = (
        ys_of[:, TSS] * ys_of[:, Q]
        + y_plant_bp[:, TSS] * y_plant_bp[:, Q]
        + y_as_bp_c_eff[:, TSS] * y_as_bp_c_eff[:, Q]
    ) / qe
    cod = (
        y_out5_aq[:, 2] * ys_of[:, Q] + y_p_bp_aq[:, 2] * y_plant_bp[:, Q] + y_bp_as_aq[:, 2] * y_as_bp_c_eff[:, Q]
    ) / qe
    nkje = (
        y_out5_aq[:, 0] * ys_of[:, Q] + y_p_bp_aq[:, 0] * y_plant_bp[:, Q] + y_bp_as_aq[:, 0] * y_as_bp_c_eff[:, Q]
    ) / qe
    snoe = (
        ys_of[:, SNO] * ys_of[:, Q]
        + y_plant_bp[:, SNO] * y_plant_bp[:, Q]
        + y_as_bp_c_eff[:, SNO] * y_as_bp_c_eff[:, Q]
    ) / qe
    bod5e = (
        y_out5_aq[:, 3] * ys_of[:, Q] + y_p_bp_aq[:, 3] * y_plant_bp[:, Q] + y_bp_as_aq[:, 3] * y_as_bp_c_eff[:, Q]
    ) / qe

    eqi = (
        (
            self.pp_par[BSS] * tsse
            + self.pp_par[BCOD] * cod
            + self.pp_par[BNKJ] * nkje
            + self.pp_par[BNO] * snoe
            + self.pp_par[BBOD5] * bod5e
        )
        * qe
        / 1000
    )
    return eqi

tss_mass

tss_mass(y_out, vol)

Calculates the total suspended solids (TSS) mass of a reactor.

Parameters:

Name Type Description Default
y_out ndarray

The effluent of the reactor.

required
vol ndarray

The volume of the reactor [m³].

required

Returns:

Name Type Description
tss_mass float

Mass of total suspended solids (TSS) [kg].

Source code in src/bsm2_python/bsm2/plantperformance.py
def tss_mass(self, y_out, vol):
    """Calculates the total suspended solids (TSS) mass of a reactor.

    Parameters
    ----------
    y_out : np.ndarray
        The effluent of the reactor.
    vol : np.ndarray
        The volume of the reactor [m³].

    Returns
    -------
    tss_mass : float
        Mass of total suspended solids (TSS) [kg].
    """

    y_out = self._reshape_if_1d(y_out)

    tss_mass = y_out[:, TSS] * vol / 1000  # kg

    return tss_mass

tss_flow

tss_flow(y_out)

Calculates the total suspended solids (TSS) flow out of a reactor.

Parameters:

Name Type Description Default
y_out ndarray

The effluent of the reactor.

required

Returns:

Name Type Description
tss_flow ndarray

Mass flow of total suspende solids (TSS) [kg(SS) ⋅ d⁻¹].

Source code in src/bsm2_python/bsm2/plantperformance.py
def tss_flow(self, y_out):
    """Calculates the total suspended solids (TSS) flow out of a reactor.

    Parameters
    ----------
    y_out : np.ndarray
        The effluent of the reactor.

    Returns
    -------
    tss_flow : np.ndarray
        Mass flow of total suspende solids (TSS) [kg(SS) ⋅ d⁻¹].
    """

    y_out = self._reshape_if_1d(y_out)
    tss_flow = sum(y_out[:, TSS] * y_out[:, Q]) / 1000  # kg/d

    return tss_flow

tss_mass_bsm2

tss_mass_bsm2(yp_of, yp_uf, yp_internal, y_out1, y_out2, y_out3, y_out4, y_out5, ys_tss_internal, yd_out, yst_out, yst_vol)

Calculates the sludge production of the BSM2 plant setup.

Parameters:

Name Type Description Default
yp_of ndarray(21)

Primary clarifier overflow (effluent) concentrations of the 21 components (13 ASM1 components, TSS, Q, T and 5 dummy states).

[SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP, SD1, SD2, SD3, XD4, XD5]

required
yp_uf ndarray(21)

Primary clarifier underflow (sludge) concentrations of the 21 components (13 ASM1 components, TSS, Q, T and 5 dummy states).

[SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP, SD1, SD2, SD3, XD4, XD5]

required
yp_internal ndarray(21)

Primary clarifier internal (basically influent) concentrations of the 21 components (13 ASM1 components, TSS, Q, T and 5 dummy states). Only for evaluation purposes.

[SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP, SD1, SD2, SD3, XD4, XD5]

required
y_out1 ndarray(21)

Concentrations of the 21 components after the first ASM reactor.

[SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP, SD1, SD2, SD3, XD4, XD5]

required
y_out2 ndarray(21)

Concentrations of the 21 components after the second ASM reactor.

[SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP, SD1, SD2, SD3, XD4, XD5]

required
y_out3 ndarray(21)

Concentrations of the 21 components after the third ASM reactor.

[SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP, SD1, SD2, SD3, XD4, XD5]

required
y_out4 ndarray(21)

Concentrations of the 21 components after the fourth ASM reactor.

[SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP, SD1, SD2, SD3, XD4, XD5]

required
y_out5 ndarray(21)

Concentrations of the 21 components after the fifth ASM reactor.

[SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP, SD1, SD2, SD3, XD4, XD5]

required
ys_tss_internal

Total suspended solids (TSS) concentrations of the internals of the settler [g(TSS) ⋅ m⁻³].

[TSS_LAY1, TSS_LAY2, TSS_LAY3,...]

required
yd_out ndarray(51)

Concentrations of the 51 components and gas phase parameters after the digester.

[S_su, S_aa, S_fa, S_va, S_bu, S_pro, S_ac, S_h2, S_ch4, S_IC, S_IN, S_I, X_xc, X_ch, X_pr, X_li, X_su, X_aa, X_fa, X_c4, X_pro, X_ac, X_h2, X_I, S_cat, S_an, Q_D, T_D, S_D1_D, S_D2_D, S_D3_D, X_D4_D, X_D5_D, pH, S_H_ion, S_hva, S_hbu, S_hpro, S_hac, S_hco3, S_CO2, S_nh3, S_NH4+, S_gas_h2, S_gas_ch4, S_gas_co2, p_gas_h2, p_gas_ch4, p_gas_co2, P_gas, q_gas]

required
yst_out ndarray(21)

Concentrations of the 21 components (13 ASM1 components, TSS, Q, T and 5 dummy states) in the effluent of the storage tank.

[SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP, SD1, SD2, SD3, XD4, XD5]

required
yst_vol float

Current volume of the storage tank [m³].

required

Returns:

Name Type Description
tss_mass float

Sludge production [kg ⋅ d⁻¹].

Source code in src/bsm2_python/bsm2/plantperformance.py
def tss_mass_bsm2(
    self,
    yp_of,
    yp_uf,
    yp_internal,
    y_out1,
    y_out2,
    y_out3,
    y_out4,
    y_out5,
    ys_tss_internal,
    yd_out,
    yst_out,
    yst_vol,
):
    """Calculates the sludge production of the BSM2 plant setup.

    Parameters
    ----------
    yp_of : np.ndarray(21)
        Primary clarifier overflow (effluent) concentrations of the 21 components
        (13 ASM1 components, TSS, Q, T and 5 dummy states). \n
        [SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP,
        SD1, SD2, SD3, XD4, XD5]
    yp_uf : np.ndarray(21)
        Primary clarifier underflow (sludge) concentrations of the 21 components
        (13 ASM1 components, TSS, Q, T and 5 dummy states). \n
        [SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP,
        SD1, SD2, SD3, XD4, XD5]
    yp_internal : np.ndarray(21)
        Primary clarifier internal (basically influent) concentrations of the 21 components
        (13 ASM1 components, TSS, Q, T and 5 dummy states).
        Only for evaluation purposes. \n
        [SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP,
        SD1, SD2, SD3, XD4, XD5]
    y_out1 : np.ndarray(21)
        Concentrations of the 21 components after the first ASM reactor. \n
        [SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP,
        SD1, SD2, SD3, XD4, XD5]
    y_out2 : np.ndarray(21)
        Concentrations of the 21 components after the second ASM reactor. \n
        [SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP,
        SD1, SD2, SD3, XD4, XD5]
    y_out3 : np.ndarray(21)
        Concentrations of the 21 components after the third ASM reactor. \n
        [SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP,
        SD1, SD2, SD3, XD4, XD5]
    y_out4 : np.ndarray(21)
        Concentrations of the 21 components after the fourth ASM reactor. \n
        [SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP,
        SD1, SD2, SD3, XD4, XD5]
    y_out5 : np.ndarray(21)
        Concentrations of the 21 components after the fifth ASM reactor. \n
        [SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP,
        SD1, SD2, SD3, XD4, XD5]
    ys_tss_internal: np.ndarray(nooflayers)
        Total suspended solids (TSS) concentrations of the internals of the settler [g(TSS) ⋅ m⁻³]. \n
        [TSS_LAY1, TSS_LAY2, TSS_LAY3,...]
    yd_out : np.ndarray(51)
        Concentrations of the 51 components and gas phase parameters after the digester. \n
        [S_su, S_aa, S_fa, S_va, S_bu, S_pro, S_ac, S_h2, S_ch4, S_IC, S_IN, S_I, X_xc,
        X_ch, X_pr, X_li, X_su, X_aa, X_fa, X_c4, X_pro, X_ac, X_h2, X_I, S_cat, S_an,
        Q_D, T_D, S_D1_D, S_D2_D, S_D3_D, X_D4_D, X_D5_D, pH, S_H_ion, S_hva, S_hbu,
        S_hpro, S_hac, S_hco3, S_CO2, S_nh3, S_NH4+, S_gas_h2, S_gas_ch4, S_gas_co2,
        p_gas_h2, p_gas_ch4, p_gas_co2, P_gas, q_gas]
    yst_out : np.ndarray(21)
        Concentrations of the 21 components (13 ASM1 components, TSS, Q, T and 5 dummy states)
        in the effluent of the storage tank. \n
        [SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP,
        SD1, SD2, SD3, XD4, XD5]
    yst_vol : float
        Current volume of the storage tank [m³].

    Returns
    -------
    tss_mass : float
        Sludge production [kg ⋅ d⁻¹].
    """

    # reshape if 1D for all input streams
    yp_of = self._reshape_if_1d(yp_of)
    yp_uf = self._reshape_if_1d(yp_uf)
    yp_internal = self._reshape_if_1d(yp_internal)
    y_out1 = self._reshape_if_1d(y_out1)
    y_out2 = self._reshape_if_1d(y_out2)
    y_out3 = self._reshape_if_1d(y_out3)
    y_out4 = self._reshape_if_1d(y_out4)
    y_out5 = self._reshape_if_1d(y_out5)
    ys_tss_internal = self._reshape_if_1d(ys_tss_internal)
    yd_out = self._reshape_if_1d(yd_out)
    yst_out = self._reshape_if_1d(yst_out)

    yst_vol = self._reshape_if_float(yst_vol)

    m_tss_yp_internal = self.tss_mass(yp_internal, primclarinit.VOL_P)
    m_tss_y_out1 = self.tss_mass(y_out1, asm1init.VOL1)
    m_tss_y_out2 = self.tss_mass(y_out2, asm1init.VOL2)
    m_tss_y_out3 = self.tss_mass(y_out3, asm1init.VOL3)
    m_tss_y_out4 = self.tss_mass(y_out4, asm1init.VOL4)
    m_tss_y_out5 = self.tss_mass(y_out5, asm1init.VOL5)
    m_tss_asm1 = m_tss_y_out1 + m_tss_y_out2 + m_tss_y_out3 + m_tss_y_out4 + m_tss_y_out5

    ys_vol = settler1dinit.DIM[0] * settler1dinit.DIM[1]  # assumption: all layers have the same volume
    m_tss_ys_internal = np.sum(ys_tss_internal, axis=1) / settler1dinit.LAYER[1] * ys_vol / 1000  # kg

    m_tss_yd_out = self.tss_mass(yd_out, adm1init.V_LIQ)

    m_tss_yst_out = self.tss_mass(yst_out, yst_vol[0])

    tss_mass = m_tss_yp_internal + m_tss_asm1 + m_tss_ys_internal + m_tss_yd_out + m_tss_yst_out  # + e_load_ydw_s

    tss_mass = self._reshape_if_1_element(tss_mass)

    return tss_mass

added_carbon_mass

added_carbon_mass(carb, concentration)

Calculates the total added carbon mass.

Parameters:

Name Type Description Default
carb float or ndarray

The carbon flow added to the system
[kg(COD) ⋅ d⁻¹].

required
concentration float or ndarray

The concentration of the carbon flow
[g(COD) ⋅ m⁻³].

[CARB_CONC1, CARB_CONC2, CARB_CONC3,...]

required

Returns:

Name Type Description
carbon_mass float or ndarray

The total added carbon mass [kg(COD) ⋅ d⁻¹].

Source code in src/bsm2_python/bsm2/plantperformance.py
@staticmethod
def added_carbon_mass(carb, concentration):
    """Calculates the total added carbon mass.

    Parameters
    ----------
    carb : float or np.ndarray
        The carbon flow added to the system <br>[kg(COD) ⋅ d⁻¹].
    concentration : float or np.ndarray
        The concentration of the carbon flow <br>[g(COD) ⋅ m⁻³]. \n
        [CARB_CONC1, CARB_CONC2, CARB_CONC3,...]

    Returns
    -------
    carbon_mass : float or np.ndarray
        The total added carbon mass [kg(COD) ⋅ d⁻¹].
    """
    # if carb is a np.ndarray, sum the rows
    if isinstance(carb, np.ndarray) and carb.ndim == 1:
        carb = np.sum(carb)

    carbon_mass = carb * concentration / 1000

    return carbon_mass

gas_production

gas_production(yd_out, t_op, p_atm=1.013)

Calculates the gas production of the digester.

Parameters:

Name Type Description Default
yd_out ndarray(51)

Concentrations of 51 ADM1 components and gas phase parameters after the digester.

[S_su, S_aa, S_fa, S_va, S_bu, S_pro, S_ac, S_h2, S_ch4, S_IC, S_IN, S_I, X_xc, X_ch, X_pr, X_li, X_su, X_aa, X_fa, X_c4, X_pro, X_ac, X_h2, X_I, S_cat, S_an, Q_D, T_D, S_D1_D, S_D2_D, S_D3_D, X_D4_D, X_D5_D, pH, S_H_ion, S_hva, S_hbu, S_hpro, S_hac, S_hco3, S_CO2, S_nh3, S_NH4+, S_gas_h2, S_gas_ch4, S_gas_co2, p_gas_h2, p_gas_ch4, p_gas_co2, P_gas, q_gas]

required
p_atm float

The atmospheric pressure [bar].

1.013
t_op float

Operational temperature of the anaerobic digester [K].

required

Returns:

Name Type Description
ch4 float

Methane production of the anaerobic digester [kg ⋅ d⁻¹].

h2 float

Hydrogen production of the anaerobic digester [kg ⋅ d⁻¹].

co2 float

Carbon dioxide production of the anaerobic digester [kg ⋅ d⁻¹].

q_gas float

Total gas flow rate of the anaerobic digester [m³ ⋅ d⁻¹].

Source code in src/bsm2_python/bsm2/plantperformance.py
def gas_production(self, yd_out, t_op, p_atm=1.0130):
    """Calculates the gas production of the digester.

    Parameters
    ----------
    yd_out : np.ndarray(51)
        Concentrations of 51 ADM1 components and
        gas phase parameters after the digester. \n
        [S_su, S_aa, S_fa, S_va, S_bu, S_pro, S_ac, S_h2, S_ch4, S_IC, S_IN, S_I, X_xc,
        X_ch, X_pr, X_li, X_su, X_aa, X_fa, X_c4, X_pro, X_ac, X_h2, X_I, S_cat, S_an,
        Q_D, T_D, S_D1_D, S_D2_D, S_D3_D, X_D4_D, X_D5_D, pH, S_H_ion, S_hva, S_hbu,
        S_hpro, S_hac, S_hco3, S_CO2, S_nh3, S_NH4+, S_gas_h2, S_gas_ch4, S_gas_co2,
        p_gas_h2, p_gas_ch4, p_gas_co2, P_gas, q_gas]
    p_atm : float
        The atmospheric pressure [bar].
    t_op : float
        Operational temperature of the anaerobic digester [K].

    Returns
    -------
    ch4 : float
        Methane production of the anaerobic digester [kg ⋅ d⁻¹].
    h2 : float
        Hydrogen production of the anaerobic digester [kg ⋅ d⁻¹].
    co2 : float
        Carbon dioxide production of the anaerobic digester [kg ⋅ d⁻¹].
    q_gas : float
        Total gas flow rate of the anaerobic digester [m³ ⋅ d⁻¹].
    """

    r = 0.0831  # kJ/(mol*K)
    yd_out = self._reshape_if_1d(yd_out)
    # bar/bar * bar * g/mol / (kJ/mol) * m^3/d = kg/d
    ch4 = yd_out[:, 47] / yd_out[:, 49] * p_atm * 16 / (r * t_op) * yd_out[:, 50]
    h2 = yd_out[:, 46] / yd_out[:, 49] * p_atm * 2 / (r * t_op) * yd_out[:, 50]
    co2 = yd_out[:, 48] / yd_out[:, 49] * p_atm * 44 / (r * t_op) * yd_out[:, 50]
    q_gas = yd_out[:, 50]
    ch4 = self._reshape_if_1_element(ch4)
    h2 = self._reshape_if_1_element(h2)
    co2 = self._reshape_if_1_element(co2)
    q_gas = self._reshape_if_1_element(q_gas)
    return ch4, h2, co2, q_gas

heat_demand_step

heat_demand_step(y_in, t_op)

Calculates the heating demand of the sludge flow to the anaerobic digester.

Parameters:

Name Type Description Default
y_in ndarray(21)

Influent concentrations of the 21 standard components (13 ASM1 components, TSS, Q, T and 5 dummy states) before the anaerobic digester.

[SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP, SD1, SD2, SD3, XD4, XD5]

required
t_op float

Operational temperature of the anaerobic digester [K].

required

Returns:

Name Type Description
heat_demand ndarray

Heating demand of the sludge flow to the anaerobic digester [kW].

Source code in src/bsm2_python/bsm2/plantperformance.py
def heat_demand_step(self, y_in, t_op):
    """Calculates the heating demand of the sludge flow to the anaerobic digester.

    Parameters
    ----------
    y_in : np.ndarray(21)
        Influent concentrations of the 21 standard components
        (13 ASM1 components, TSS, Q, T and 5 dummy states) before the anaerobic digester. \n
        [SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, TEMP,
        SD1, SD2, SD3, XD4, XD5]
    t_op : float
        Operational temperature of the anaerobic digester [K].

    Returns
    -------
    heat_demand : np.ndarray
        Heating demand of the sludge flow to the anaerobic digester [kW].
    """

    rho = H2O.rho_l  # kg/m^3 (density of water)
    cp = H2O.cp_l  # kJ/kg*K (specific heat capacity of water)
    y_in = self._reshape_if_1d(y_in)
    flow = y_in[:, 14]
    t = t_op - (y_in[:, 15] + 273.15)
    heat_demand = flow / 86400 * rho * cp * t  # m^3/d / s/d * kg/m^3 * kJ/kg*K * K = kW
    return heat_demand

get_t_op

get_t_op(heat, yd_in, yd_out, vol_fermenter)

Calculates the operating temperature of the anaerobic digestor reactor based on the heat input.

Parameters:

Name Type Description Default
heat float

Heat input to the anaerobic digester [kW].

required
yd_in ndarray(51)

Influent concentrations of 51 ADM1 components and gas phase parameters before the digester.

[S_su, S_aa, S_fa, S_va, S_bu, S_pro, S_ac, S_h2, S_ch4, S_IC, S_IN, S_I, X_xc, X_ch, X_pr, X_li, X_su, X_aa, X_fa, X_c4, X_pro, X_ac, X_h2, X_I, S_cat, S_an, Q_D, T_D, S_D1_D, S_D2_D, S_D3_D, X_D4_D, X_D5_D, pH, S_H_ion, S_hva, S_hbu, S_hpro, S_hac, S_hco3, S_CO2, S_nh3, S_NH4+, S_gas_h2, S_gas_ch4, S_gas_co2, p_gas_h2, p_gas_ch4, p_gas_co2, P_gas, q_gas]

required
yd_out ndarray(51)

Effluent concentrations of 51 ADM1 components and gas phase parameters after the digester.

[S_su, S_aa, S_fa, S_va, S_bu, S_pro, S_ac, S_h2, S_ch4, S_IC, S_IN, S_I, X_xc, X_ch, X_pr, X_li, X_su, X_aa, X_fa, X_c4, X_pro, X_ac, X_h2, X_I, S_cat, S_an, Q_D, T_D, S_D1_D, S_D2_D, S_D3_D, X_D4_D, X_D5_D, pH, S_H_ion, S_hva, S_hbu, S_hpro, S_hac, S_hco3, S_CO2, S_nh3, S_NH4+, S_gas_h2, S_gas_ch4, S_gas_co2, p_gas_h2, p_gas_ch4, p_gas_co2, P_gas, q_gas]

required
vol_fermenter float

Volume of the anaerobic digester [m³].

required

Returns:

Name Type Description
t_op float

Operating temperature of the reactor [K].

Source code in src/bsm2_python/bsm2/plantperformance.py
def get_t_op(self, heat, yd_in, yd_out, vol_fermenter):
    """Calculates the operating temperature of the anaerobic digestor reactor based on the heat input.

    Parameters
    ----------
    heat : float
        Heat input to the anaerobic digester [kW].
    yd_in : np.ndarray(51)
        Influent concentrations of 51 ADM1 components and
        gas phase parameters before the digester. \n
        [S_su, S_aa, S_fa, S_va, S_bu, S_pro, S_ac, S_h2, S_ch4, S_IC, S_IN, S_I, X_xc,
        X_ch, X_pr, X_li, X_su, X_aa, X_fa, X_c4, X_pro, X_ac, X_h2, X_I, S_cat, S_an,
        Q_D, T_D, S_D1_D, S_D2_D, S_D3_D, X_D4_D, X_D5_D, pH, S_H_ion, S_hva, S_hbu,
        S_hpro, S_hac, S_hco3, S_CO2, S_nh3, S_NH4+, S_gas_h2, S_gas_ch4, S_gas_co2,
        p_gas_h2, p_gas_ch4, p_gas_co2, P_gas, q_gas]
    yd_out : np.ndarray(51)
        Effluent concentrations of 51 ADM1 components and
        gas phase parameters after the digester. \n
        [S_su, S_aa, S_fa, S_va, S_bu, S_pro, S_ac, S_h2, S_ch4, S_IC, S_IN, S_I, X_xc,
        X_ch, X_pr, X_li, X_su, X_aa, X_fa, X_c4, X_pro, X_ac, X_h2, X_I, S_cat, S_an,
        Q_D, T_D, S_D1_D, S_D2_D, S_D3_D, X_D4_D, X_D5_D, pH, S_H_ion, S_hva, S_hbu,
        S_hpro, S_hac, S_hco3, S_CO2, S_nh3, S_NH4+, S_gas_h2, S_gas_ch4, S_gas_co2,
        p_gas_h2, p_gas_ch4, p_gas_co2, P_gas, q_gas]
    vol_fermenter : float
        Volume of the anaerobic digester [m³].

    Returns
    -------
    t_op : float
        Operating temperature of the reactor [K].
    """

    yd_in = self._reshape_if_1d(yd_in)
    # kJ/(m^3*K) * m^3 * K = kW
    cp_fermenter = 4.2  # kJ/(m^3*K)
    temp_fermenter = 35  # old_temp
    heat_fermenter = temp_fermenter * vol_fermenter * cp_fermenter  # kJ
    heat_outflow = temp_fermenter * yd_out[Q] * cp_fermenter  # kJ
    heat_inflow = heat  # kJ
    current_heat = heat_fermenter + heat_inflow - heat_outflow  # kJ
    t_op = current_heat / (vol_fermenter * cp_fermenter)

    return t_op

oci

oci(pe, ae, me, tss, cm, he, mp)

Calculates the operational cost index of the plant.

Parameters:

Name Type Description Default
pe float

Pumping energy of the plant [kWh ⋅ d⁻¹].

required
ae float

Aeration energy of the plant [kWh ⋅ d⁻¹].

required
me float

Mixing energy of the plant [kWh ⋅ d⁻¹].

required
tss float

Total suspended solids production of the plant [kWh ⋅ d⁻¹].

required
cm float

Added carbon mass of the plant [kWh ⋅ d⁻¹].

required
he float

Heating demand of the plant [kWh ⋅ d⁻¹].

required
mp float

Methane production of the plant [kWh ⋅ d⁻¹].

required

Returns:

Name Type Description
oci float

Operational cost index of the plant [-].

Source code in src/bsm2_python/bsm2/plantperformance.py
@staticmethod
def oci(pe, ae, me, tss, cm, he, mp):
    """Calculates the operational cost index of the plant.

    Parameters
    ----------
    pe : float
        Pumping energy of the plant [kWh ⋅ d⁻¹].
    ae : float
        Aeration energy of the plant [kWh ⋅ d⁻¹].
    me : float
        Mixing energy of the plant [kWh ⋅ d⁻¹].
    tss : float
        Total suspended solids production of the plant [kWh ⋅ d⁻¹].
    cm : float
        Added carbon mass of the plant [kWh ⋅ d⁻¹].
    he : float
        Heating demand of the plant [kWh ⋅ d⁻¹].
    mp : float
        Methane production of the plant [kWh ⋅ d⁻¹].

    Returns
    -------
    oci : float
        Operational cost index of the plant [-].
    """

    tss_cost = 3 * tss
    ae_cost = ae
    me_cost = me
    pe_cost = pe
    cm_cost = 3 * cm
    he_cost = max(0.0, he - 7 * mp)
    mp_income = 6 * mp

    return tss_cost + ae_cost + me_cost + pe_cost + cm_cost + he_cost - mp_income