diff --git a/qsdsan/data/_masm2d.xlsx b/qsdsan/data/_masm2d.xlsx new file mode 100644 index 00000000..2ce17ae9 Binary files /dev/null and b/qsdsan/data/_masm2d.xlsx differ diff --git a/qsdsan/processes/_adm1_p_extension.py b/qsdsan/processes/_adm1_p_extension.py index 8db65e1c..b58896ed 100644 --- a/qsdsan/processes/_adm1_p_extension.py +++ b/qsdsan/processes/_adm1_p_extension.py @@ -21,7 +21,7 @@ from qsdsan import Component, Components, Process, Processes, CompiledProcesses from qsdsan.processes import ( create_adm1_cmps, - create_asm2d_cmps, + create_masm2d_cmps, T_correction_factor, non_compet_inhibit, grad_non_compet_inhibit, @@ -55,36 +55,56 @@ def create_adm1_p_extension_cmps(set_thermo=True): c1 = create_adm1_cmps(False) - c2d = create_asm2d_cmps(False) + c2d = create_masm2d_cmps(False) S_IP = c2d.S_PO4.copy('S_IP') - S_K = Component.from_chemical('S_K', chemical='K', - measured_as='K', - description='Potassium', - particle_size='Soluble', - degradability='Undegradable', - organic=False) + c1.S_su.i_mass = c1.X_ch.i_mass = 0.9375 + c1.S_su.f_Vmass_Totmass = c1.X_ch.f_Vmass_Totmass = 0.68 + c1.X_li.i_mass = 0.6375 + c1.X_li.f_Vmass_Totmass = 1. - S_Mg = Component.from_chemical('S_Mg', chemical='Mg', - measured_as='Mg', - description='Magnesium', - particle_size='Soluble', - degradability='Undegradable', - organic=False) + c1.S_aa.i_C = c1.X_pr.i_C = 0.36890 + c1.S_aa.i_N = c1.X_pr.i_N = 0.11065 + c1.S_aa.i_P = c1.X_pr.i_P = 0. + c1.S_aa.i_mass = c1.X_pr.i_mass = 0.737648 + c1.S_aa.f_Vmass_Totmass = c1.X_pr.f_Vmass_Totmass = 0.864 + c1.S_fa._formula = None + c1.S_fa.chem_MW = 1. + c1.S_fa.i_C = 0.25685 + # c1.S_fa.i_mass = 1/2.9200 + + c1.S_I.i_C = c1.X_I.i_C = 0.36178 + c1.S_I.i_N = c1.X_I.i_N = 0.06003 + c1.S_I.i_P = c1.X_I.i_P = 6.49e-3 + c1.S_I.i_mass = c1.X_I.i_mass = 0.75 + c1.S_I.f_Vmass_Totmass = c1.X_I.f_Vmass_Totmass = 0.85 + + for cmp in (c1.S_aa, c1.X_pr, c1.S_fa, c1.S_I, c1.X_I): + cmp.i_NOD = None + + for cmp in (c1.X_su, c1.X_aa, c1.X_fa, c1.X_c4, c1.X_pro, c1.X_ac, c1.X_h2,): + cmp.i_C = 0.36612 + cmp.i_N = 0.08615 + cmp.i_P = 0.02154 + cmp.i_mass = 0.90 + cmp.f_Vmass_Totmass = 0.85 + cmp.i_NOD = None + + c1.refresh_constants() c = [*c1] Ss = c[:11] Xs = c[13:-3] # X_c is excluded others = c[-3:] - cmps_adm1_p_extension = Components([*Ss, S_IP, c1.S_I, - *Xs, c2d.X_PHA, c2d.X_PP, c2d.X_PAO, - S_K, S_Mg, c2d.X_MeOH, c2d.X_MeP, - *others]) - cmps_adm1_p_extension.default_compile() - if set_thermo: settings.set_thermo(cmps_adm1_p_extension) - return cmps_adm1_p_extension + cmps_adm1p = Components([*Ss, S_IP, c1.S_I, *Xs, + c2d.X_PHA, c2d.X_PP, c2d.X_PAO, + c2d.S_K, c2d.S_Mg, c2d.X_MeOH, c2d.X_MeP, + *others]) + cmps_adm1p.default_compile() + if set_thermo: settings.set_thermo(cmps_adm1p) + return cmps_adm1p # create_adm1_p_extension_cmps() @@ -399,7 +419,7 @@ class ADM1_p_extension(ADM1): _biogas_IDs = ('S_h2', 'S_ch4', 'S_IC') - def __new__(cls, components=None, path=None, N_xc=2.686e-3, N_I=4.286e-3, N_aa=7e-3, + def __new__(cls, components=None, path=None, f_sI_xb=0, f_ch_xb=0.275, f_pr_xb=0.275, f_li_xb=0.350, f_fa_li=0.95, f_bu_su=0.13, f_pro_su=0.27, f_ac_su=0.41, f_va_aa=0.23, f_bu_aa=0.26, f_pro_aa=0.05, f_ac_aa=0.4, @@ -421,10 +441,6 @@ def __new__(cls, components=None, path=None, N_xc=2.686e-3, N_I=4.286e-3, N_aa=7 **kwargs): cmps = _load_components(components) - # Sure that some things are missing here! (Saumitra) - # cmps.X_c.i_N = N_xc * N_mw - cmps.X_I.i_N = cmps.S_I.i_N = N_I * N_mw - cmps.S_aa.i_N = cmps.X_pr.i_N = N_aa * N_mw if not path: path = _path self = Processes.load_from_file(path, diff --git a/qsdsan/processes/_asm2d.py b/qsdsan/processes/_asm2d.py index efcd4695..2764e6bb 100644 --- a/qsdsan/processes/_asm2d.py +++ b/qsdsan/processes/_asm2d.py @@ -9,13 +9,14 @@ Please refer to https://github.com/QSD-Group/QSDsan/blob/main/LICENSE.txt for license details. ''' - +import numpy as np from thermosteam.utils import chemicals_user from thermosteam import settings -from qsdsan import Components, Process, Processes, CompiledProcesses +from qsdsan import Component, Components, Process, Processes, CompiledProcesses from ..utils import ospath, data_path -__all__ = ('create_asm2d_cmps', 'ASM2d') +__all__ = ('create_asm2d_cmps', 'ASM2d', + 'create_masm2d_cmps', ) _path = ospath.join(data_path, 'process_data/_asm2d.tsv') _load_components = settings.get_default_chemicals @@ -70,156 +71,60 @@ def create_asm2d_cmps(set_thermo=True): # create_asm2d_cmps() - -############ Processes in ASM2d ################# -# params = ('f_SI', 'Y_H', 'f_XI_H', 'Y_PAO', 'Y_PO4', 'Y_PHA', 'f_XI_PAO', 'Y_A', 'f_XI_AUT', -# 'K_h', 'eta_NO3', 'eta_fe', 'K_O2', 'K_NO3', 'K_X', -# 'mu_H', 'q_fe', 'eta_NO3_H', 'b_H', 'K_O2_H', 'K_F', 'K_fe', 'K_A_H', -# 'K_NO3_H', 'K_NH4_H', 'K_P_H', 'K_ALK_H', -# 'q_PHA', 'q_PP', 'mu_PAO', 'eta_NO3_PAO', 'b_PAO', 'b_PP', 'b_PHA', -# 'K_O2_PAO', 'K_NO3_PAO', 'K_A_PAO', 'K_NH4_PAO', 'K_PS',' K_P_PAO', -# 'K_ALK_PAO', 'K_PP', 'K_MAX', 'K_IPP', 'K_PHA', -# 'mu_AUT', 'b_AUT', 'K_O2_AUT', 'K_NH4_AUT', 'K_ALK_AUT', 'K_P_AUT', -# 'k_PRE', 'k_RED', 'K_ALK_PRE') - -# asm2d = Processes.load_from_file(data_path, -# conserved_for=('COD', 'N', 'P', 'charge'), -# parameters=params, -# compile=False) - -# p12 = Process('anox_storage_PP', -# 'S_PO4 + [Y_PHA]X_PHA + [?]S_NO3 -> X_PP + [?]S_N2 + [?]S_NH4 + [?]S_ALK', -# ref_component='X_PP', -# rate_equation='q_PP * S_O2/(K_O2_PAO+S_O2) * S_PO4/(K_PS+S_PO4) * S_ALK/(K_ALK_PAO+S_ALK) * (X_PHA/X_PAO)/(K_PHA+X_PHA/X_PAO) * (K_MAX-X_PP/X_PAO)/(K_IPP+K_MAX-X_PP/X_PAO) * X_PAO * eta_NO3_PAO * K_O2_PAO/S_O2 * S_NO3/(K_NO3_PAO+S_NO3)', -# parameters=('Y_PHA', 'q_PP', 'K_O2_PAO', 'K_PS', 'K_ALK_PAO', 'K_PHA', 'eta_NO3_PAO', 'K_IPP', 'K_NO3_PAO'), -# conserved_for=('COD', 'N', 'P', 'NOD', 'charge')) - -# p14 = Process('PAO_anox_growth', -# '[1/Y_PAO]X_PHA + [?]S_NO3 + [?]S_PO4 -> X_PAO + [?]S_N2 + [?]S_NH4 + [?]S_ALK', -# ref_component='X_PAO', -# rate_equation='mu_PAO * S_O2/(K_O2_PAO + S_O2) * S_NH4/(K_NH4_PAO + S_NH4) * S_PO4/(K_P_PAO + S_PO4) * S_ALK/(K_ALK_PAO + S_ALK) * (X_PHA/X_PAO)/(K_PHA + X_PHA/X_PAO) * X_PAO * eta_NO3_PAO * K_O2_PAO/S_O2 * S_NO3/(K_NO3_PAO + S_NO3)', -# parameters=('Y_PAO', 'mu_PAO', 'K_O2_PAO', 'K_NH4_PAO', 'K_P_PAO', 'K_ALK_PAO', 'K_PHA', 'eta_NO3_PAO', 'K_NO3_PAO'), -# conserved_for=('COD', 'N', 'P', 'NOD', 'charge')) - -# asm2d.extend([p12, p14]) -# asm2d.compile() - -# # ASM2d typical values at 20 degree C -# asm2d.set_parameters( -# f_SI = 0, # production of soluble inerts in hydrolysis = 0.0 gCOD/gCOD -# Y_H = 0.625, # heterotrophic yield = 0.625 gCOD/gCOD -# f_XI_H=0.1, # fraction of inert COD generated in heterotrophic biomass lysis = 0.1 gCOD/gCOD -# Y_PAO = 0.625, # PAO yield = 0.625 gCOD/gCOD -# Y_PO4 = 0.4, # PP requirement (PO4 release) per PHA stored = 0.4 gP/gCOD -# Y_PHA = 0.2, # PHA requirement for PP storage = 0.2 gCOD/gP -# f_XI_PAO=0.1, # fraction of inert COD generated in PAO biomass lysis = 0.1 gCOD/gCOD -# Y_A = 0.24, # autotrophic yield = 0.24 gCOD/gN -# f_XI_AUT=0.1, # fraction of inert COD generated in autotrophic biomass lysis = 0.1 gCOD/gCOD -# K_h = 3, # hydrolysis rate constant = 3.0 d^(-1) -# eta_NO3 = 0.6, # reduction factor for anoxic hydrolysis = 0.6 -# eta_fe = 0.4, # anaerobic hydrolysis reduction factor = 0.4 -# K_O2 = 0.2, # O2 half saturation coefficient of hydrolysis = 0.2 mgO2/L -# K_NO3 = 0.5, # nitrate half saturation coefficient of hydrolysis = 0.5 mgN/L -# K_X = 0.1, # slowly biodegradable substrate half saturation coefficient for hydrolysis = 0.1 gCOD/gCOD -# mu_H = 6, # heterotrophic maximum specific growth rate = 6.0 d^(-1) -# q_fe = 3, # fermentation maximum rate = 3.0 d^(-1) -# eta_NO3_H = 0.8, # denitrification reduction factor for heterotrophic growth = 0.8 -# b_H = 0.4, # lysis and decay rate constant = 0.4 d^(-1) -# K_O2_H=0.2, # O2 half saturation coefficient of heterotrophs = 0.2 mgO2/L -# K_F = 4, # fermentable substrate half saturation coefficient for heterotrophic growth = 4.0 mgCOD/L -# K_fe = 4, # fermentable substrate half saturation coefficient for fermentation = 4.0 mgCOD/L -# K_A_H = 4, # VFA half saturation coefficient for heterotrophs = 4.0 mgCOD/L -# K_NO3_H=0.5, # nitrate half saturation coefficient = 0.5 mgN/L -# K_NH4_H = 0.05, # ammonium (nutrient) half saturation coefficient for heterotrophs = 0.05 mgN/L -# K_P_H = 0.01, # phosphorus (nutrient) half saturation coefficient for heterotrophs = 0.01 mgP/L -# K_ALK_H = 0.1*12, # alkalinity half saturation coefficient for heterotrophs = 0.1 mol(HCO3-)/m^3 = 1.2 gC/m^3 -# q_PHA = 3, # rate constant for storage of PHA = 3.0 d^(-1) -# q_PP = 1.5, # rate constant for storage of PP = 1.5 d^(-1) -# mu_PAO = 1, # PAO maximum specific growth rate = 1.0 d^(-1) -# eta_NO3_PAO=0.6, # denitrification reduction factor for PAO growth = 0.8 -# b_PAO = 0.2, # PAO lysis rate = 0.2 d^(-1) -# b_PP = 0.2, # PP lysis rate = 0.2 d^(-1) -# b_PHA = 0.2, # PHA lysis rate = 0.2 d^(-1) -# K_O2_PAO=0.2, # O2 half saturation coefficient for PAOs = 0.2 mgO2/L -# K_NO3_PAO=0.5, # nitrate half saturation coefficient for PAOs = 0.5 mgN/L -# K_A_PAO=4.0, # VFA half saturation coefficient for PAOs = 4.0 mgCOD/L -# K_NH4_PAO=0.05, # ammonium (nutrient) half saturation coefficient for PAOs = 0.05 mgN/L -# K_PS = 0.2, # phosphorus half saturation coefficient for storage of PP = 0.2 mgP/L -# K_P_PAO=0.01, # phosphorus (nutrient) half saturation coefficient for heterotrophs = 0.01 mgP/L -# K_ALK_PAO=0.1*12, # alkalinity half saturation coefficient for PAOs = 0.1 mol(HCO3-)/m^3 = 1.2 gC/m^3 -# K_PP = 0.01, # PP half saturation coefficient for storage of PHA = 0.01 gP/gCOD (?). gCOD/gCOD in GPS-X -# K_MAX = 0.34, # maximum ratio of X_PP/X_PAO = 0.34 gX_PP/gX_PAO -# K_IPP = 0.02, # inhibition coefficient for PP storage = 0.02 gP/gCOD -# K_PHA = 0.01, # PHA half saturation coefficient = 0.01 gCOD/gCOD -# mu_AUT = 1, # autotrophic maximum specific growth rate = 1.0 d^(-1) -# b_AUT = 0.15, # autotrophic decay rate = 0.15 d^(-1) -# K_O2_AUT = 0.5, # O2 half saturation coefficient for autotrophic growth = 0.5 mgO2/L -# K_NH4_AUT = 1, # ammonium (substrate) half saturation coefficient for autotrophic growth = 1.0 mgN/L -# K_ALK_AUT=0.5*12, # alkalinity half saturation coefficient for autotrophic growth = 0.5 mol(HCO3-)/m^3 = 6.0 gC/m^3 -# K_P_AUT=0.01, # phosphorus (nutrient) half saturation coefficient for autotrophic growth = 0.01 mgP/L -# k_PRE = 1, # phosphorus precipitation with MeOH rate constant = 1.0 m^3/g/d -# k_RED = 0.6, # redissoluation of phosphates rate constant = 0.6 d^(-1) -# K_ALK_PRE=0.5*12 # alkalinity half saturation coefficient for phosphate precipitation = 0.5 mol(HCO3-)/m^3 = 6.0 gC/m^3 -# ) - -# ASM2d typical values at 10 degree C -# asm2d.set_parameters( -# f_SI = 0, # production of soluble inerts in hydrolysis = 0.0 gCOD/gCOD -# Y_H = 0.625, # heterotrophic yield = 0.625 gCOD/gCOD -# f_XI_H=0.1, # fraction of inert COD generated in heterotrophic biomass lysis = 0.1 gCOD/gCOD -# Y_PAO = 0.625, # PAO yield = 0.625 gCOD/gCOD -# Y_PO4 = 0.4, # PP requirement (PO4 release) per PHA stored = 0.4 gP/gCOD -# Y_PHA = 0.2, # PHA requirement for PP storage = 0.2 gCOD/gP -# f_XI_PAO=0.1, # fraction of inert COD generated in PAO biomass lysis = 0.1 gCOD/gCOD -# Y_A = 0.24, # autotrophic yield = 0.24 gCOD/gN -# f_XI_AUT=0.1, # fraction of inert COD generated in autotrophic biomass lysis = 0.1 gCOD/gCOD -# K_h = 2, # hydrolysis rate constant = 2.0 d^(-1) -# eta_NO3 = 0.6, # reduction factor for anoxic hydrolysis = 0.6 -# eta_fe = 0.4, # anaerobic hydrolysis reduction factor = 0.4 -# K_O2 = 0.2, # O2 half saturation coefficient of hydrolysis = 0.2 mgO2/L -# K_NO3 = 0.5, # nitrate half saturation coefficient of hydrolysis = 0.5 mgN/L -# K_X = 0.1, # slowly biodegradable substrate half saturation coefficient for hydrolysis = 0.1 gCOD/gCOD -# mu_H = 3, # heterotrophic maximum specific growth rate = 3.0 d^(-1) -# q_fe = 1.5, # fermentation maximum rate = 1.5 d^(-1) -# eta_NO3_H = 0.8, # denitrification reduction factor for heterotrophic growth = 0.8 -# b_H = 0.4, # lysis and decay rate constant = 0.4 d^(-1) -# K_O2_H=0.2, # O2 half saturation coefficient of heterotrophs = 0.2 mgO2/L -# K_F = 4, # fermentable substrate half saturation coefficient for heterotrophic growth = 4.0 mgCOD/L -# K_fe = 4, # fermentable substrate half saturation coefficient for fermentation = 4.0 mgCOD/L -# K_A_H = 4, # VFA half saturation coefficient for heterotrophs = 4.0 mgCOD/L -# K_NO3_H=0.5, # nitrate half saturation coefficient = 0.5 mgN/L -# K_NH4_H = 0.05, # ammonium (nutrient) half saturation coefficient for heterotrophs = 0.05 mgN/L -# K_P_H = 0.01, # phosphorus (nutrient) half saturation coefficient for heterotrophs = 0.01 mgP/L -# K_ALK_H = 0.1*12, # alkalinity half saturation coefficient for heterotrophs = 0.1 mol(HCO3-)/m^3 = 1.2 gC/m^3 -# q_PHA = 2, # rate constant for storage of PHA = 2.0 d^(-1) -# q_PP = 1.0, # rate constant for storage of PP = 1.0 d^(-1) -# mu_PAO = 0.67, # PAO maximum specific growth rate = 0.67 d^(-1) -# eta_NO3_PAO=0.6, # denitrification reduction factor for PAO growth = 0.8 -# b_PAO = 0.1, # PAO lysis rate = 0.1 d^(-1) -# b_PP = 0.1, # PP lysis rate = 0.1 d^(-1) -# b_PHA = 0.1, # PHA lysis rate = 0.1 d^(-1) -# K_O2_PAO=0.2, # O2 half saturation coefficient for PAOs = 0.2 mgO2/L -# K_NO3_PAO=0.5, # nitrate half saturation coefficient for PAOs = 0.5 mgN/L -# K_A_PAO=4.0, # VFA half saturation coefficient for PAOs = 4.0 mgCOD/L -# K_NH4_PAO=0.05, # ammonium (nutrient) half saturation coefficient for PAOs = 0.05 mgN/L -# K_PS = 0.2, # phosphorus half saturation coefficient for storage of PP = 0.2 mgP/L -# K_P_PAO=0.01, # phosphorus (nutrient) half saturation coefficient for heterotrophs = 0.01 mgP/L -# K_ALK_PAO=0.1*12, # alkalinity half saturation coefficient for PAOs = 0.1 mol(HCO3-)/m^3 = 1.2 gC/m^3 -# K_PP = 0.01, # PP half saturation coefficient for storage of PHA = 0.01 gP/gCOD (?). gCOD/gCOD in GPS-X -# K_MAX = 0.34, # maximum ratio of X_PP/X_PAO = 0.34 gX_PP/gX_PAO -# K_IPP = 0.02, # inhibition coefficient for PP storage = 0.02 gP/gCOD -# K_PHA = 0.01, # PHA half saturation coefficient = 0.01 gCOD/gCOD -# mu_AUT = 0.35, # autotrophic maximum specific growth rate = 0.35 d^(-1) -# b_AUT = 0.05, # autotrophic decay rate = 0.05 d^(-1) -# K_O2_AUT = 0.5, # O2 half saturation coefficient for autotrophic growth = 0.5 mgO2/L -# K_NH4_AUT = 1, # ammonium (substrate) half saturation coefficient for autotrophic growth = 1.0 mgN/L -# K_ALK_AUT=0.5*12, # alkalinity half saturation coefficient for autotrophic growth = 0.5 mol(HCO3-)/m^3 = 6.0 gC/m^3 -# K_P_AUT=0.01, # phosphorus (nutrient) half saturation coefficient for autotrophic growth = 0.01 mgP/L -# k_PRE = 1, # phosphorus precipitation with MeOH rate constant = 1.0 m^3/g/d -# k_RED = 0.6, # redissoluation of phosphates rate constant = 0.6 d^(-1) -# K_ALK_PRE=0.5*12 # alkalinity half saturation coefficient for phosphate precipitation = 0.5 mol(HCO3-)/m^3 = 6.0 gC/m^3 -# ) - +def create_masm2d_cmps(set_thermo=True): + c2d = create_asm2d_cmps(False) + S_K = Component.from_chemical('S_K', chemical='K', + measured_as='K', + description='Potassium', + particle_size='Soluble', + degradability='Undegradable', + organic=False) + + S_Mg = Component.from_chemical('S_Mg', chemical='Mg', + measured_as='Mg', + description='Magnesium', + particle_size='Soluble', + degradability='Undegradable', + organic=False) + + S_IC = c2d.S_ALK.copy('S_IC') + + c2d.S_F.i_C = c2d.X_S.i_C = 0.31843 + c2d.S_F.i_N = c2d.X_S.i_N = 0.03352 + c2d.S_F.i_P = c2d.X_S.i_P = 5.59e-3 + + c2d.S_I.i_C = c2d.X_I.i_C = 0.36178 + c2d.S_I.i_N = c2d.X_I.i_N = 0.06003 + c2d.S_I.i_P = c2d.X_I.i_P = 6.49e-3 + c2d.S_F.i_mass = c2d.X_S.i_mass = c2d.S_I.i_mass = c2d.X_I.i_mass = 0.75 + c2d.S_F.f_Vmass_Totmass = c2d.X_S.f_Vmass_Totmass = c2d.S_I.f_Vmass_Totmass = c2d.X_I.f_Vmass_Totmass = 0.85 + + c2d.X_H.i_C = c2d.X_AUT.i_C = c2d.X_PAO.i_C = 0.36612 + c2d.X_H.i_N = c2d.X_AUT.i_N = c2d.X_PAO.i_N = 0.08615 + c2d.X_H.i_P = c2d.X_AUT.i_P = c2d.X_PAO.i_P = 0.02154 + c2d.X_H.i_mass = c2d.X_AUT.i_mass = c2d.X_PAO.i_mass = 0.90 + c2d.X_H.f_Vmass_Totmass = c2d.X_AUT.f_Vmass_Totmass = c2d.X_PAO.f_Vmass_Totmass = 0.85 + + c2d.X_PHA.i_C = 0.3 + c2d.X_PHA.i_mass = 0.55 + c2d.X_PHA.f_Vmass_Totmass = 0.92727 + c2d.X_PP.i_charge = 0 + + for cmp in (c2d.S_F, c2d.X_S, c2d.S_I, c2d.X_I, c2d.X_H, c2d.X_AUT, c2d.X_PHA): + cmp.i_NOD = None + c2d.refresh_constants() + c2d = [*c2d] + solubles = c2d[:8] # replace S_ALK with S_IC + others = c2d[9:] + + cmps = Components([*solubles, S_IC, S_K, S_Mg, *others]) + cmps.default_compile() + if set_thermo: settings.set_thermo(cmps) + + return cmps + + +#%% @chemicals_user class ASM2d(CompiledProcesses): ''' @@ -508,4 +413,238 @@ def __new__(cls, components=None, K_ALK_AUT=K_ALK_AUT*12, K_P_AUT=K_P_AUT, k_PRE=k_PRE, k_RED=k_RED, K_ALK_PRE=K_ALK_PRE*12, **kwargs) - return self \ No newline at end of file + return self + +#%% +_mpath = ospath.join(data_path, 'process_data/_masm2d.tsv') + +Monod = lambda S, K: S/(S+K) + +rhos = np.zeros(19) # 19 biological processes, no precipitation/dissociation or gas stripping yet +def rhos_masm2d(state_arr, params, acceptor_dependent_decay=True): + if 'ks' not in params: + k_h, mu_H, mu_PAO, mu_AUT, \ + q_fe, q_PHA, q_PP, \ + b_H, b_PAO, b_PP, b_PHA, b_AUT, \ + eta_NO3, eta_fe, eta_NO3_H, eta_NO3_PAO, \ + eta_NO3_Hl, eta_NO3_PAOl, eta_NO3_PPl, eta_NO3_PHAl, eta_NO3_AUTl, \ + K_O2, K_O2_H, K_O2_PAO, K_O2_AUT, \ + K_NO3, K_NO3_H, K_NO3_PAO, K_NO3_AUT, \ + K_X, K_F, K_fe, K_A_H, K_A_PAO, \ + K_NH4_H, K_NH4_PAO, K_NH4_AUT, \ + K_P_H, K_P_PAO, K_P_AUT, K_P_S, \ + K_PP, K_MAX, K_IPP, K_PHA, \ + = params.values() + + params['ks'] = ks = rhos * 0 + # rate constants + ks[:3] = k_h + ks[3:7] = mu_H + ks[7:19] = (q_fe, b_H, q_PHA, q_PP, q_PP, mu_PAO, mu_PAO, b_PAO, b_PP, b_PHA, mu_AUT, b_AUT) + # rate reduction factors + ks[1] *= eta_NO3 + ks[2] *= eta_fe + ks[5:7] *= eta_NO3_H + ks[[11,13]] *= eta_NO3_PAO + + # half saturation / inhibition factors + params['Ks_o2'] = np.array([K_O2, K_O2_H, K_O2_H, K_O2_PAO, K_O2_PAO, K_O2_AUT]) + params['Ks_no3'] = np.array([K_NO3, K_NO3_H, K_NO3_H, K_NO3_PAO, K_NO3_PAO, K_NO3_AUT]) + params['Ks_nh4'] = np.array([K_NH4_H, K_NH4_PAO, K_NH4_AUT]) + params['Ks_po4'] = np.array([K_P_H, K_P_PAO, K_P_AUT]) + params['eta_decay'] = np.array([eta_NO3_Hl, eta_NO3_PAOl, eta_NO3_PPl, eta_NO3_PHAl, eta_NO3_AUTl]) + + ks = params['ks'] + Ks_o2 = params['Ks_o2'] + Ks_no3 = params['Ks_no3'] + Ks_nh4 = params['Ks_nh4'] + Ks_po4 = params['Ks_po4'] + eta_decay = params['eta_decay'] + + Kx = params['K_X'] + Kf = params['K_F'] + Kfe = params['K_fe'] + Ka_H = params['K_A_H'] + Ka_PAO = params['K_A_PAO'] + Kp_stor = params['K_P_S'] + Kpp = params['K_PP'] + Kmax = params['K_MAX'] + Kipp = params['K_IPP'] + Kpha = params['K_PHA'] + + S_O2, S_NH4, S_NO3, S_PO4, S_F, S_A, \ + X_S, X_H, X_PAO, X_PP, X_PHA, X_AUT \ + = state_arr[[0,2,3,4,5,6,12,13,14,15,16,17]] + + nutrients = Monod(S_NH4, Ks_nh4) * Monod(S_PO4, Ks_po4) + + rhos[:] = ks + rhos[:9] *= X_H * nutrients[0] + rhos[9:15] *= X_PAO + rhos[12:14] *= nutrients[1] + rhos[15] *= X_PP + rhos[16] *= X_PHA + rhos[17:19] *= X_AUT + rhos[17] *= nutrients[2] + + aero = Monod(S_O2, Ks_o2) + anox = Monod(S_NO3, Ks_no3) + rhos[[0,3,4,10,12,17]] *= aero # aerobic + rhos[[1,5,6,11,13]] *= (1-aero[:5]) * anox[:5] # anoxic + rhos[[2,7]] *= (1-aero[:2]) * (1-anox[:2]) # anaerobic/fermentation + + if X_H > 0: rhos[:3] *= Monod(X_S/X_H, Kx) + if S_F > 0: rhos[[3,5]] *= Monod(S_F, Kf) * S_F/(S_F+S_A) + else: rhos[[3,5]] = 0. + if S_A > 0: rhos[[4,6]] *= Monod(S_A, Ka_H) * S_A/(S_F+S_A) + else: rhos[[4,6]] = 0. + + rhos[7] *= Monod(S_F, Kfe) + if X_PAO > 0: + pha = Monod(X_PHA/X_PAO, Kpha) + rhos[9] *= Monod(S_A, Ka_PAO) * Monod(X_PP/X_PAO, Kpp) + rhos[[10,11]] *= pha * Monod(Kmax-X_PP/X_PAO, Kipp) * Monod(S_PO4, Kp_stor) + rhos[[12,13]] *= pha + + if acceptor_dependent_decay: + rhos[8] *= (aero[1] + eta_decay[0]*(1-aero[1])*anox[1]) + rhos[14:17] *= (aero[3] +eta_decay[1:4]*(1-aero[3])*anox[3]) + rhos[18] *= (aero[5] + eta_decay[4]*(1-aero[5])*anox[5]) + + return rhos + +@chemicals_user +class mASM2d(CompiledProcesses): + ''' + Modified ASM2d. [1]_, [2]_ Compatible with `ADM1p` for plant-wide simulations. + + Parameters + ---------- + + Examples + -------- + >>> from qsdsan import processes as pc, set_thermo + >>> cmps = pc.create_asm2d_cmps() + >>> asm2d = pc.ASM2d() + >>> asm2d.show() + ASM2d([aero_hydrolysis, anox_hydrolysis, anae_hydrolysis, hetero_growth_S_F, hetero_growth_S_A, denitri_S_F, denitri_S_A, ferment, hetero_lysis, PAO_storage_PHA, aero_storage_PP, PAO_aero_growth_PHA, PAO_lysis, PP_lysis, PHA_lysis, auto_aero_growth, auto_lysis, precipitation, redissolution, anox_storage_PP, PAO_anox_growth]) + + References + ---------- + .. [1] Henze, M., Gujer, W., Mino, T., & van Loosdrecht, M. (2000). + Activated Sludge Models: ASM1, ASM2, ASM2d and ASM3. In IWA task group + on mathematical modelling for design and operation of biological + wastewater treatment (Ed.), Scientific and Technical Report No. 9. + IWA Publishing. + .. [2] Solon, K., Flores-Alsina, X., Kazadi Mbamba, C., Ikumi, D., Volcke, + E. I. P., Vaneeckhaute, C., Ekama, G., Vanrolleghem, P. A., Batstone, + D. J., Gernaey, K. V., & Jeppsson, U. (2017). Plant-wide modelling + of phosphorus transformations in wastewater treatment systems: + Impacts of control and operational strategies. Water Research, 113, + 97–110. https://doi.org/10.1016/j.watres.2017.02.007 + + ''' + _stoichio_params = ('f_SI', 'Y_H', 'Y_PAO', 'Y_PO4', 'Y_PHA', 'Y_A', + 'f_XI_H', 'f_XI_PAO', 'f_XI_AUT','K_XPP', 'Mg_XPP') + _kinetic_params = ('k_h', 'mu_H', 'mu_PAO', 'mu_AUT', + 'q_fe', 'q_PHA', 'q_PP', + 'b_H', 'b_PAO', 'b_PP', 'b_PHA', 'b_AUT', + # k_PRE, k_RED, + 'eta_NO3', 'eta_fe', 'eta_NO3_H', 'eta_NO3_PAO', + 'eta_NO3_Hl', 'eta_NO3_PAOl', 'eta_NO3_PPl', 'eta_NO3_PHAl', 'eta_NO3_AUTl', + 'K_O2', 'K_O2_H', 'K_O2_PAO', 'K_O2_AUT', + 'K_NO3', 'K_NO3_H', 'K_NO3_PAO', 'K_NO3_AUT', + 'K_X', 'K_F', 'K_fe', 'K_A_H', 'K_A_PAO', + 'K_NH4_H', 'K_NH4_PAO', 'K_NH4_AUT', + 'K_P_H', 'K_P_PAO', 'K_P_AUT', 'K_P_S', + 'K_PP', 'K_MAX', 'K_IPP', 'K_PHA', + # 'K_ALK_PRE' + ) + + decay_dependon_electron_acceptor = True + + def __new__(cls, components=None, path=None, + f_SI=0.0, Y_H=0.625, Y_PAO=0.625, Y_PO4=0.4, Y_PHA=0.2, Y_A=0.24, + f_XI_H=0.1, f_XI_PAO=0.1, f_XI_AUT=0.1, + k_h=3.0, mu_H=6.0, mu_PAO=1.0, mu_AUT=1.0, + q_fe=3.0, q_PHA=3.0, q_PP=1.5, + b_H=0.4, b_PAO=0.2, b_PP=0.2, b_PHA=0.2, b_AUT=0.15, + # k_PRE=1.0, k_RED=0.6, + eta_NO3=0.6, eta_fe=0.4, eta_NO3_H=0.8, eta_NO3_PAO=0.6, + eta_NO3_Hl=0.5, eta_NO3_PAOl=0.33, eta_NO3_PPl=0.33, eta_NO3_PHAl=0.33, eta_NO3_AUTl=0.33, + K_O2=0.2, K_O2_H=0.2, K_O2_PAO=0.2, K_O2_AUT=0.5, + K_NO3=0.5, K_NO3_H=0.5, K_NO3_PAO=0.5, K_NO3_AUT=0.5, + K_X=0.1, K_F=4.0, K_fe=4.0, K_A_H=4.0, K_A_PAO=4.0, + K_NH4_H=0.05, K_NH4_PAO=0.05, K_NH4_AUT=1.0, + K_P_H=0.01, K_P_PAO=0.01, K_P_AUT=0.01, K_P_S=0.2, + K_PP=0.01, K_MAX=0.34, K_IPP=0.02, K_PHA=0.01, + # K_ALK_PRE=0.5, + #!!! kLa and/or solubility values for gas stripping + #!!! precipitation kinetics + **kwargs): + + if not path: path = _mpath + + cmps = _load_components(components) + + self = Processes.load_from_file(path, + components=cmps, + conserved_for=('COD', 'C', 'N', 'P',), + parameters=cls._stoichio_params, + compile=False) + + if path == _path: + _p12 = Process('anox_storage_PP', + 'S_PO4 + [K_XPP]S_K + [Mg_XPP]S_Mg +[Y_PHA]X_PHA + [?]S_NO3 -> X_PP + [?]S_N2 + [?]S_NH4 + [?]S_IC', + components=cmps, + ref_component='X_PP', + conserved_for=('C', 'N', 'P', 'NOD',)) + + _p14 = Process('PAO_anox_growth', + '[1/Y_PAO]X_PHA + [?]S_NO3 + [?]S_PO4 -> X_PAO + [?]S_N2 + [?]S_NH4 + [?]S_IC', + components=cmps, + ref_component='X_PAO', + conserved_for=('C', 'N', 'P', 'NOD', 'COD')) + self.insert(11, _p12) + self.insert(13, _p14) + + #!!! add gas stripping + + self.compile(to_class=cls) + + dct = self.__dict__ + dct.update(kwargs) + stoichio_vals = (f_SI, Y_H, Y_PAO, Y_PO4, Y_PHA, Y_A, + f_XI_H, f_XI_PAO, f_XI_AUT, + cmps.X_PP.i_K, cmps.X_PP.i_Mg) + dct['_parameters'] = dict(zip(cls._stoichio_params, stoichio_vals)) + self.set_rate_function(rhos_masm2d) + kinetic_vals = (k_h, mu_H, mu_PAO, mu_AUT, + q_fe, q_PHA, q_PP, + b_H, b_PAO, b_PP, b_PHA, b_AUT, + # k_PRE, k_RED, + eta_NO3, eta_fe, eta_NO3_H, eta_NO3_PAO, + eta_NO3_Hl, eta_NO3_PAOl, eta_NO3_PPl, eta_NO3_PHAl, eta_NO3_AUTl, + K_O2, K_O2_H, K_O2_PAO, K_O2_AUT, + K_NO3, K_NO3_H, K_NO3_PAO, K_NO3_AUT, + K_X, K_F, K_fe, K_A_H, K_A_PAO, + K_NH4_H, K_NH4_PAO, K_NH4_AUT, + K_P_H, K_P_PAO, K_P_AUT, K_P_S, + K_PP, K_MAX, K_IPP, K_PHA, + # K_ALK_PRE + ) + self.rate_function._params = dict(zip(cls._kinetic_params, kinetic_vals)) + + return self + + def set_parameters(self, **parameters): + stoichio = self._parameters + kinetic = self.rate_function._params + if set(parameters.keys()).intersection(set(kinetic.keys())): + for key in ('ks', 'Ks_o2', 'Ks_no3', 'Ks_nh4', 'Ks_po4', 'eta_decay'): + kinetic.pop(key, None) + for k,v in parameters.items(): + if k in self._kinetic_params: kinetic[k] = v + else: stoichio[k] = v + if self._stoichio_lambdified is not None: + self.__dict__['_stoichio_lambdified'] = None \ No newline at end of file