primclar_bsm2 ¶
PrimaryClarifier ¶
PrimaryClarifier(volume, yp0, p_par, asm1par, x_vector, tempmodel, activate)
This is an implementation of the Otterpohl/Freund primary clarifier model.
The implementation is to a large extent based on an implementation of the Otterpohl/Freund model by Dr. Jens Alex, IFAK, Magdeburg.
-
In addition to ASM1 states, the clarifier will also pass on
TSS,Q,TEMPand 5 dummy states to effluent and underflow. -
If
tempmodel== True, T(out) is a first-order equation based on the heat content of the influent, the reactor and outflow.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
volume | float | Volume of the primary clarifier [m³]. | required |
yp0 | ndarray(21) | Initial integration values of the 21 components (13 ASM1 components, TSS, Q, T and 5 dummy states). [S_I_P, S_S_P, X_I_P, X_S_P, X_BH_P, X_BA_P, X_P_P, S_O_P, S_NO_P, S_NH_P, S_ND_P, X_ND_P, S_ALK_P, TSS_P, Q_P, T_P, S_D1_P, S_D2_P, S_D3_P, X_D4_P, X_D5_P] | required |
p_par | ndarray(4) | Parameters for the primary clarifier. [F_CORR, F_X, T_M, F_PS] | required |
asm1par | ndarray(24) | ASM1 parameters. [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] | required |
x_vector | ndarray(21) | Vector with settleability of the 21 components of ASM1 [-]. [0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1] | required |
tempmodel | bool | If true, first-order equation based on the heat content of the influent, the reactor and outflow is solved, otherwise influent wastewater temperature is just passed through process reactors. | required |
activate | bool | If true, dummy states are activated, otherwise dummy states are not activated. | required |
Source code in src/bsm2_python/bsm2/primclar_bsm2.py
def __init__(self, volume, yp0, p_par, asm1par, x_vector, tempmodel, activate):
self.volume = volume
self.yp0 = yp0
self.p_par = p_par
self.asm1par = asm1par
self.x_vector = x_vector
self.tempmodel = tempmodel
self.activate = activate
output ¶
output(timestep, step, yp_in)
Returns the overflow and underflow concentrations from a primary clarifier at the current time step.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
timestep | float | Current time step [d]. | required |
step | float | Current time [d]. | required |
yp_in | ndarray(21) | Primary clarifier influent 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, T_WW, SD1, SD2, SD3, XD4, XD5] | required |
Returns:
| Name | Type | Description |
|---|---|---|
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, T_WW, SD1, SD2, SD3, XD4, XD5] |
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, T_WW, SD1, SD2, SD3, XD4, XD5] |
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, T_WW, SD1, SD2, SD3, XD4, XD5] |
Source code in src/bsm2_python/bsm2/primclar_bsm2.py
def output(self, timestep, step, yp_in):
"""Returns the overflow and underflow concentrations from a
primary clarifier at the current time step.
Parameters
----------
timestep : float
Current time step [d].
step : float
Current time [d].
yp_in : np.ndarray(21)
Primary clarifier influent 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, T_WW,
SD1, SD2, SD3, XD4, XD5]
Returns
-------
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, T_WW,
SD1, SD2, SD3, XD4, XD5]
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, T_WW,
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, T_WW,
SD1, SD2, SD3, XD4, XD5]
"""
# f_corr, f_X, t_m, f_PS = p_par
# y = yp_uf, yp_of
# u = yp_int
# x : yp_in
yp_uf = np.zeros(21)
yp_of = np.zeros(21)
yp_internal = np.zeros(21)
if not self.tempmodel:
self.yp0[15] = yp_in[15]
t_eval = np.array([step, step + timestep]) # time interval for odeint
ode = odeint(
primclarequations, self.yp0, t_eval, tfirst=True, args=(yp_in, self.p_par, self.volume, self.tempmodel)
)
yp_int = ode[1]
self.yp0 = yp_int
qu = self.p_par[3] * yp_in[Q] # underflow from primary clarifier
e = yp_in[Q] / qu # thickening factor
tt = self.volume / (yp_int[Q] + 0.001) # hydraulic retention time
# Total COD removal efficiency in primary clarifier nCOD
ncod = self.p_par[0] * (2.88 * self.p_par[1] - 0.118) * (1.45 + 6.15 * np.log(tt * 24 * 60))
# nX is removal efficiency of particulate COD in %, since assumption that soluble COD is not removed
nx = ncod / self.p_par[1]
nx = max(0, min(100, nx)) # nX is between 0 and 100
ff = 1 - self.x_vector * nx / 100
# ASM1 state outputs effluent
yp_of[0:13] = ff[0:13] * yp_int[0:13]
yp_of[yp_of < 0.0] = 0.0
# dummy state outputs effluent
yp_of[16:21] = ff[16:21] * yp_int[16:21]
yp_of[yp_of < 0.0] = 0.0
# TSS output effluent
yp_of[TSS] = (
self.asm1par[19] * yp_of[XI]
+ self.asm1par[20] * yp_of[XS]
+ self.asm1par[21] * yp_of[XBH]
+ self.asm1par[22] * yp_of[XBA]
+ self.asm1par[23] * yp_of[XP]
)
# ASM1 state outputs underflow
yp_uf[0:13] = ((1 - ff[0:13]) * e + ff[0:13]) * yp_int[0:13]
yp_uf[yp_uf < 0.0] = 0.0
# dummy state outputs underflow
yp_uf[16:21] = ((1 - ff[16:21]) * e + ff[16:21]) * yp_int[16:21]
yp_uf[yp_uf < 0.0] = 0.0
# TSS output underflow
yp_uf[TSS] = (
self.asm1par[19] * yp_uf[XI]
+ self.asm1par[20] * yp_uf[XS]
+ self.asm1par[21] * yp_uf[XBH]
+ self.asm1par[22] * yp_uf[XBA]
+ self.asm1par[23] * yp_uf[XP]
)
# only for plant performance!
# ASM1 state outputs internal
yp_internal[0:13] = yp_int[0:13]
# dummy state outputs internal
yp_internal[16:21] = yp_int[16:21]
yp_internal[yp_internal < 0.0] = 0.0
# TSS output internal
yp_internal[TSS] = (
self.asm1par[19] * yp_in[XI]
+ self.asm1par[20] * yp_in[XS]
+ self.asm1par[21] * yp_in[XBH]
+ self.asm1par[22] * yp_in[XBA]
+ self.asm1par[23] * yp_in[XP]
)
# Flow rates
yp_of[Q] = yp_in[Q] - qu # flow rate in effluent
yp_uf[Q] = qu # flow rate in underflow
yp_internal[Q] = yp_in[Q]
if not self.tempmodel:
yp_of[TEMP] = yp_in[TEMP]
yp_uf[TEMP] = yp_in[TEMP]
yp_internal[TEMP] = yp_in[TEMP]
else:
yp_of[TEMP] = yp_int[TEMP]
yp_uf[TEMP] = yp_int[TEMP]
yp_internal[TEMP] = yp_int[TEMP]
return yp_uf, yp_of, yp_internal
primclarequations ¶
primclarequations(t, yp, yp_in, p_par, volume, tempmodel)
Returns an array containing the differential equations for the primary clarifier.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
t | ndarray(2) | Time interval for integration, needed for the solver [d]. [step, step + timestep] | required |
yp | ndarray(21) | Solution of the differential equations, needed for the solver. [SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, T_WW, SD1, SD2, SD3, XD4, XD5] | required |
yp_in | ndarray(21) | Primary clarifier influent 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, T_WW, SD1, SD2, SD3, XD4, XD5] | required |
p_par | ndarray(4) | Parameters for the primary clarifier. [F_CORR, F_X, T_M, F_PS] | required |
volume | float | Volume of the primary clarifier [m³]. | required |
tempmodel | bool | If true, mass balance for the wastewater temperature is used in process rates, otherwise influent wastewater temperature is just passed through process reactors. | required |
Returns:
| Name | Type | Description |
|---|---|---|
dyp | ndarray(21) | Array containing the differential values of [SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, T_WW, SD1, SD2, SD3, XD4, XD5] |
Source code in src/bsm2_python/bsm2/primclar_bsm2.py
@jit(nopython=True, cache=True)
def primclarequations(t, yp, yp_in, p_par, volume, tempmodel):
"""Returns an array containing the differential equations for the primary clarifier.
Parameters
----------
t : np.ndarray(2)
Time interval for integration, needed for the solver [d]. \n
[step, step + timestep]
yp : np.ndarray(21)
Solution of the differential equations, needed for the solver. \n
[SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, T_WW,
SD1, SD2, SD3, XD4, XD5]
yp_in : np.ndarray(21)
Primary clarifier influent 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, T_WW,
SD1, SD2, SD3, XD4, XD5]
p_par : np.ndarray(4)
Parameters for the primary clarifier. \n
[F_CORR, F_X, T_M, F_PS]
volume : float
Volume of the primary clarifier [m³].
tempmodel : bool
If true, mass balance for the wastewater temperature is used in process rates,
otherwise influent wastewater temperature is just passed through process reactors.
Returns
-------
dyp : np.ndarray(21)
Array containing the differential values of `yp_in` based on ADM1. \n
[SI, SS, XI, XS, XBH, XBA, XP, SO, SNO, SNH, SND, XND, SALK, TSS, Q, T_WW,
SD1, SD2, SD3, XD4, XD5]
"""
# u = yp_in
# x = yp
# dx = dyp
dyp = np.zeros(21)
dyp[0:13] = 1.0 / volume * (yp_in[Q] * (yp_in[0:13] - yp[0:13])) # ASM1 states are mixing
dyp[TSS] = 0.0
dyp[Q] = (yp_in[Q] - yp[Q]) / p_par[2]
if not tempmodel:
dyp[TEMP] = 0.0
else:
dyp[TEMP] = 1.0 / volume * (yp_in[Q] * (yp_in[TEMP] - yp[TEMP]))
dyp[16:21] = 1.0 / volume * (yp_in[Q] * (yp_in[16:21] - yp[16:21])) # dummy states are mixing
return dyp