Beispiel #1
0
def test_StorageTank():
    bst_s, qs_ws = create_streams(1)
    bst.settings.set_thermo(chems)
    bst_unit = bst.units.StorageTank(ins=bst_s)

    qs.set_thermo(cmps)
    qs_unit = qs.sanunits.StorageTank(ins=qs_ws)

    check_results(bst_unit, qs_unit)
Beispiel #2
0
def test_Splitter():
    bst_s, qs_ws = create_streams(1)
    bst.settings.set_thermo(chems)
    bst_unit = bst.units.Splitter(ins=bst_s, split=0.1)

    qs.set_thermo(cmps)
    qs_unit = qs.sanunits.Splitter(ins=qs_ws, split=0.1)

    check_results(bst_unit, qs_unit)
Beispiel #3
0
def test_HXutility():
    bst_s, qs_ws = create_streams(1)
    bst.settings.set_thermo(chems)
    bst_unit = bst.units.HXutility(ins=bst_s, T=400,
                                   rigorous=False)  #!!! Try True

    qs.set_thermo(cmps)
    qs_unit = qs.sanunits.HXutility(ins=qs_ws, T=400,
                                    rigorous=False)  #!!! Try True

    check_results(bst_unit, qs_unit)
Beispiel #4
0
def test_HXprocess():
    bst_s, qs_ws = create_streams(2)
    bst_s[0].T = qs_ws[0].T = 400

    bst.settings.set_thermo(chems)
    bst_unit = bst.units.HXprocess(ins=bst_s, phase0='l', phase1='l')

    qs.set_thermo(cmps)
    qs_unit = qs.sanunits.HXprocess(ins=qs_ws, phase0='l', phase1='l')

    check_results(bst_unit, qs_unit)
Beispiel #5
0
def test_bsm1():
    from numpy.testing import assert_allclose as ac
    from numpy import arange
    from qsdsan import set_thermo
    from exposan import bsm1 as b1

    sys = b1.bsm1
    set_thermo(b1.cmps)
    sys.reset_cache()
    sys.simulate(t_span=(0, 50), method='BDF', t_eval=arange(0, 51, 1))
    assert sys.outs[0].isempty() == False
    ac(float(sys.outs[0].iconc['S_S']), 0.895, rtol=1e-2)
    ac(float(sys.outs[1].iconc['X_BH']), 4994.3, rtol=1e-2)
    ac(sys.outs[0].COD, 47.5, rtol=1e-2)
    ac(sys.outs[1].get_TSS(), 6377.9, rtol=1e-2)
Beispiel #6
0
def create_streams(num):
    bst.settings.set_thermo(chems)
    bst_s = []
    for n in range(num):
        s = bst.Stream(Methanol=100 * (n + 1),
                       Ethanol=100 * (n + 1),
                       units='kg/hr')
        bst_s.append(s)

    qs.set_thermo(cmps)
    qs_ws = []
    for n in range(num):
        ws = qs.WasteStream(Methanol=100 * (n + 1),
                            Ethanol=100 * (n + 1),
                            units='kg/hr')
        qs_ws.append(ws)

    return bst_s, qs_ws
Beispiel #7
0
def test_waste_stream():
    import pytest, numpy as np
    from numpy.testing import assert_allclose
    from math import isclose
    from qsdsan import set_thermo, Components, WasteStream

    components = Components.load_default()
    set_thermo(components)

    ws1 = WasteStream.codstates_inf_model('ws1', 1e5)
    ws2 = WasteStream.codstates_inf_model('ws2', 1e5*24/1e3, units=('m3/d', 'g/m3'))
    assert isclose(ws1.COD, 430, rel_tol=1e-2)
    assert isclose(ws1.TKN, 40, rel_tol=1e-2)
    assert isclose(ws1.TP, 10, rel_tol=1e-2)
    assert isclose(ws1.F_vol, ws2.F_vol)

    ws3 = WasteStream(S_Ac=5, H2O=1000, units='kg/hr')
    ws4 = WasteStream(X_NOO=10, H2O=1000, units='kg/hr')
    ws5 = WasteStream()
    ws5.mix_from((ws3, ws4))
    assert_allclose(ws5.F_mass, 2015.0)
    # TODO: After updating the default component properties,
    # add in tests here to make sure COD, etc. are calculated correctly
    assert_allclose(ws5.COD, 7414.267796, rtol=1e-2)

    # Make sure below attributes are calculated based on flow info, cannot be set
    with pytest.raises(AttributeError):
        ws5.COD = 5

    # Concentration calclation
    ws6 = WasteStream(X_CaCO3=1, H2O=1000, units='kg/hr')
    assert_allclose(np.abs(ws6.conc.value-ws6.mass/ws6.F_vol*1e3).sum(), 0, atol=1e-6)
    ws6.imass['X_B_Subst', 'X_GAO_PHA'] = (100, 1)
    ws7 = WasteStream(X_CaCO3=1, X_B_Subst=100, X_GAO_PHA=1, H2O=1000, units='kg/hr')
    assert_allclose(np.abs(ws6.conc.value-ws7.mass/ws7.F_vol*1e3).sum(), 0, atol=1e-6)
    ws6.mass[:] = 1e-3
    ws6.imass['H2O'] = 1e3
    diff = ws6.conc.value - np.ones_like(ws6.conc.value)
    diff[components.index('H2O')] = 0
    assert_allclose(np.max(np.abs(diff)), 0, atol=1e-2)
Beispiel #8
0
def _load_components():
    global components, _components_loaded
    components = create_components()
    qs.set_thermo(components)
    _components_loaded = True
Beispiel #9
0
def test_component():
    import pytest
    from qsdsan import Chemical, Component, Components, set_thermo, \
        _waste_stream as ws_module
    from chemicals.elements import molecular_weight
    from math import isclose

    S_NH4 = Component('S_NH4',
                      formula='NH4+',
                      measured_as='N',
                      f_BOD5_COD=0,
                      f_uBOD_COD=0,
                      f_Vmass_Totmass=0,
                      description="Ammonium",
                      particle_size="Soluble",
                      degradability="Undegradable",
                      organic=False)
    assert S_NH4.i_N == 1
    assert S_NH4.i_NOD == molecular_weight({'O': 4}) / molecular_weight(
        {'N': 1})
    S_NH4.measured_as = None
    assert S_NH4.i_mass == 1

    S_Ac = Component('S_Ac',
                     formula='CH3COO-',
                     measured_as='COD',
                     f_BOD5_COD=0.717,
                     f_uBOD_COD=0.863,
                     f_Vmass_Totmass=1,
                     description="Acetate",
                     particle_size="Soluble",
                     degradability="Readily",
                     organic=True)
    assert S_Ac.i_COD == 1
    S_Ac.measured_as = None
    assert S_Ac.i_mass == 1
    assert S_Ac.i_COD == molecular_weight({'O': 4}) / molecular_weight({
        'C': 2,
        'H': 3,
        'O': 2
    })

    S_HS = Component.from_chemical('S_HS',
                                   Chemical('Hydrosulfide'),
                                   particle_size="Soluble",
                                   degradability="Undegradable",
                                   organic=False)
    assert S_HS.i_charge < 0
    S_HS.measured_as = 'S'
    assert S_HS.i_mass > 1

    # Check default components
    cmps1 = Components.load_default(default_compile=False)
    H2O_chemical = Chemical('H2O')
    H2O = Component.from_chemical('H2O', H2O_chemical)
    with pytest.raises(ValueError):  # H2O already in default components
        cmps1.append(H2O)
    with pytest.raises(
            RuntimeError):  # key chemical-related properties missing
        cmps1.compile()
    # Can compile with default-filling those missing properties
    cmps1.default_compile(lock_state_at='', particulate_ref='NaCl')

    cmps2 = Components((cmp for cmp in cmps1 if cmp.ID != 'H2O'))
    H2O = Component.from_chemical('H2O',
                                  Chemical('H2O'),
                                  particle_size='Soluble',
                                  degradability='Undegradable',
                                  organic=False)
    cmps2.append(H2O)
    cmps2.default_compile(lock_state_at='', particulate_ref='NaCl')

    cmps3 = Components.load_default()
    assert cmps3.S_H2.measured_as == 'COD'
    assert cmps3.S_H2.i_COD == 1
    assert isclose(cmps3.S_N2.i_COD,
                   -molecular_weight({'O': 1.5}) / molecular_weight({'N': 1}),
                   rel_tol=1e-3)
    assert isclose(cmps3.S_NO3.i_COD,
                   -molecular_weight({'O': 4}) / molecular_weight({'N': 1}),
                   rel_tol=1e-3)
    set_thermo(cmps3)

    # Check if the default groups are up-to-date
    cached_cmp_IDs = ws_module._default_cmp_IDs
    cached_cmp_groups = ws_module._specific_groups
    assert set(cmps3.IDs) == cached_cmp_IDs
    get_IDs = lambda attr: {cmp.ID for cmp in getattr(cmps3, attr)}
    for attr, IDs in cached_cmp_groups.items():
        assert IDs == get_IDs(attr)
Beispiel #10
0
    c1s = {k: v for k, v in dct['C1_s'].items() if v > 0}
    c1x = {k: v for k, v in dct['C1_x'].items() if v > 0}
    tss = [v for v in dct['C1_tss'].values() if v > 0]
    C1.set_init_solubles(**c1s)
    C1.set_init_sludge_solids(**c1x)
    C1.set_init_TSS(tss)


#%%
# =============================================================================
# Benchmark Simulation Model No. 1
# =============================================================================

############# load components and set thermo #############
cmps = components = pc.load_asm1_cmps()
set_thermo(cmps)

############# create WasteStream objects #################
Q = 18446  # influent flowrate [m3/d]
Temp = 273.15 + 20  # temperature [K]

PE = WasteStream('Wastewater', T=Temp)
inf_kwargs = {
    'concentrations': {
        'S_S': 69.5,
        'X_BH': 28.17,
        'X_S': 202.32,
        'X_I': 51.2,
        'S_NH': 31.56,
        'S_I': 30,
        'S_ND': 6.95,
Beispiel #11
0
def test_process():
    import pytest
    import os
    from sympy import symbols, Eq
    from sympy.parsing.sympy_parser import parse_expr
    from math import isclose
    from qsdsan import set_thermo, Components, Process, Processes, CompiledProcesses, _pk
    import qsdsan.processes as pc

    cmps = Components.load_default()

    S_A = cmps.S_Ac.copy('S_A')
    S_ALK = cmps.S_CO3.copy('S_ALK')  # measured as g C
    S_F = cmps.S_F.copy('S_F')
    S_I = cmps.S_U_E.copy('S_I')
    S_N2 = cmps.S_N2.copy('S_N2')
    S_NH4 = cmps.S_NH4.copy('S_NH4')
    S_NO3 = cmps.S_NO3.copy('S_NO3')
    S_O2 = cmps.S_O2.copy('S_O2')
    S_PO4 = cmps.S_PO4.copy('S_PO4')
    X_AUT = cmps.X_AOO.copy('X_AUT')
    X_H = cmps.X_OHO.copy('X_H')
    X_I = cmps.X_U_OHO_E.copy('X_I')
    X_MeOH = cmps.X_FeOH.copy('X_MeOH')
    X_MeP = cmps.X_FePO4.copy('X_MeP')
    X_PAO = cmps.X_PAO.copy('X_PAO')
    X_PHA = cmps.X_PAO_PHA.copy('X_PHA')
    X_PP = cmps.X_PAO_PP_Lo.copy('X_PP')
    X_S = cmps.X_B_Subst.copy('X_S')

    S_I.i_N = 0.01
    S_F.i_N = 0.03
    X_I.i_N = 0.02
    X_S.i_N = 0.04
    X_H.i_N = X_PAO.i_N = X_AUT.i_N = 0.07

    S_I.i_P = 0.00
    S_F.i_P = 0.01
    X_I.i_P = 0.01
    X_S.i_P = 0.01
    X_H.i_P = X_PAO.i_P = X_AUT.i_P = 0.02

    cmps_asm2d = Components([
        S_O2, S_F, S_A, S_NH4, S_NO3, S_PO4, S_I, S_ALK, S_N2, X_I, X_S, X_H,
        X_PAO, X_PP, X_PHA, X_AUT, X_MeOH, X_MeP
    ])

    cmps_asm2d.compile()
    set_thermo(cmps_asm2d)

    p1 = Process(
        'aero_hydrolysis',
        'X_S -> [1-f_SI]S_F + [f_SI]S_I + [?]S_NH4 + [?]S_PO4 + [?]S_ALK',
        ref_component='X_S',
        rate_equation='K_h * S_O2/(K_O2+S_O2) * X_S/(K_X*X_H+X_S) * X_H',
        parameters=('f_SI', 'K_h', 'K_O2', 'K_X'))

    f_SI = symbols('f_SI')
    assert abs(sum(p1._stoichiometry * p1._components.i_N).subs({'f_SI': 1
                                                                 })) < 1e-8
    assert abs(sum(p1._stoichiometry * p1._components.i_N).subs({'f_SI': 0
                                                                 })) < 1e-8
    assert abs(sum(p1._stoichiometry * p1._components.i_P).subs({'f_SI': 1
                                                                 })) < 1e-8
    assert abs(
        sum(p1._stoichiometry * p1._components.i_charge).subs({'f_SI': 1
                                                               })) < 1e-8

    p1.set_parameters(f_SI=0.0)
    assert p1.parameters['f_SI'] == 0.0
    assert Eq(p1._stoichiometry[p1._components._index['S_I']],
              parse_expr('1*f_SI'))

    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+S_O2) * S_PO4/(K_PS+S_PO4) * S_ALK/(K_ALK+S_ALK) * (X_PHA/X_PAO)/(K_PHA+X_PHA/X_PAO) * (K_MAX-X_PP/X_PAO)/(K_PP+K_MAX-X_PP/X_PAO) * X_PAO * eta_NO3 * K_O2/S_O2 * S_NO3/(K_NO3+S_NO3)',
        parameters=('Y_PHA', 'q_PP', 'K_O2', 'K_PS', 'K_ALK', 'K_PHA',
                    'eta_NO3', 'K_PP', 'K_NO3'),
        conserved_for=('COD', 'N', 'P', 'NOD', 'charge'))

    p14 = Process(
        'PAO_anox_growth',
        '[1/Y_H]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 + S_O2) * S_NH4/(K_NH4 + S_NH4) * S_PO4/(K_P + S_PO4) * S_CO3/(K_ALK + S_ALK) * (X_PHA/X_PAO)/(K_PHA + X_PHA/X_PAO) * X_PAO * eta_NO3 * K_O2/S_O2 * S_NO3/(K_NO3 + S_NO3)',
        parameters=('Y_H', 'mu_PAO', 'K_O2', 'K_NH4', 'K_P', 'K_ALK', 'K_PHA',
                    'eta_NO3', 'K_NO3'),
        conserved_for=('COD', 'N', 'P', 'NOD', 'charge'))

    PAO_anox_processes = Processes([p12, p14])
    assert PAO_anox_processes.PAO_anox_growth.ref_component == X_PAO
    with pytest.raises(AttributeError):
        print(PAO_anox_processes.production_rates)

    params = ('f_SI', 'Y_H', 'f_XI', 'Y_PO4', 'Y_PHA', 'Y_A', 'K_h', 'eta_NO3',
              'eta_fe', 'K_O2', 'K_NO3', 'K_X', 'mu_H', 'q_fe', 'eta_NO3_deni',
              'b_H', 'K_F', 'K_fe', 'K_A', 'K_NH4', 'K_P', 'K_ALK', 'q_PHA',
              'q_PP', 'mu_PAO', 'b_PAO', 'b_PP', 'b_PHA', 'K_PS', 'K_PP',
              'K_MAX', 'K_IPP', 'K_PHA', 'mu_AUT', 'b_AUT', 'K_O2_AUT',
              'K_NH4_AUT', 'K_ALK_2', 'k_PRE', 'k_RED')

    path = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                        'ASM2d_original.tsv')
    asm2d = Processes.load_from_file(path,
                                     conserved_for=('COD', 'N', 'P', 'charge'),
                                     parameters=params,
                                     compile=False)
    asm2d.extend(PAO_anox_processes)
    asm2d.compile()
    assert isinstance(asm2d, CompiledProcesses)
    assert p12 in asm2d
    assert set(asm2d.parameters.keys()) == set(params)

    # Try re-pickling if the tests are run locally and
    # the environment supports Pickle Protocol 5
    pickle = True if _pk else False
    try:
        pc.load_asm1_cmps()
    except:
        pc._asm1._create_asm1_cmps(pickle=pickle)

    try:
        pc.load_asm2d_cmps()
    except:
        pc._asm2d._create_asm2d_cmps(pickle=pickle)
        pc.load_asm2d_cmps()
Beispiel #12
0
def create_asm_validation_system(process_model='ASM1', aerated=False):
    suffix = 'aer' if aerated else 'an'
    flowsheet = qs.Flowsheet(f'{process_model}_{suffix}')
    qs.main_flowsheet.set_flowsheet(flowsheet)

    # Load process model (including associated components)
    pc_lower = process_model.lower()
    if pc_lower == 'asm1':
        # Thermodynamic conditions
        cmps = pc.load_asm1_cmps()
        set_thermo(cmps)
        # Influent
        inf_kwargs = {
            'concentrations': {
                'S_S': 69.5,
                'X_BH': 28.17,
                'X_S': 202.32,
                'X_I': 51.2,
                'S_NH': 31.56,
                'S_I': 30,
                'S_ND': 6.95,
                'X_ND': 10.59,
                'S_ALK': 7*12,
                },
            'units': ('m3/d', 'mg/L'),
            }
        # Process model
        asm = pc.ASM1(
            Y_A=0.24, Y_H=0.67, f_P=0.08, i_XB=0.08, i_XP=0.06,
            mu_H=4.0, K_S=10.0, K_O_H=0.2, K_NO=0.5, b_H=0.3,
            eta_g=0.8, eta_h=0.8, k_h=3.0, K_X=0.1, mu_A=0.5,
            K_NH=1.0, b_A=0.05, K_O_A=0.4, k_a=0.05, fr_SS_COD=1/1.48,
            path=os.path.join(asm_path, 'data/_asm1.tsv'),
            )
        # Initial conditions in the CSTR
        init_conds = {
                'S_I': 30,
                'S_S': 5,
                'X_I': 1000,
                'X_S': 100,
                'X_BH': 500,
                'X_BA': 100,
                'X_P': 100,
                'S_O': 2,
                'S_NO': 20,
                'S_NH': 2,
                'S_ND': 1,
                'X_ND': 1,
                'S_ALK': 7*12,
            }
        DO_ID = 'S_O'
    elif pc_lower == 'asm2d':
        cmps = pc.load_asm2d_cmps()
        set_thermo(cmps)

        inf_kwargs = {
            'concentrations': { # Henze et al., Activated Sludge Models ASM1, ASM2, ASM2d and ASM3, P91
                'S_I': 30,
                'S_F': 30,
                'S_A': 0,
                'S_NH4': 16,
                'S_PO4': 3.6,
                'S_ALK': 5*12, # mmol/L to mg C/L
                'X_I': 25,
                'X_S': 125,
                'X_H': 30,
                },
            'units': ('m3/d', 'mg/L'),
            }
        asm = pc.ASM2d(
                iN_SI=0.01, iN_SF=0.03, iN_XI=0.02, iN_XS=0.04, iN_BM=0.07,
                iP_SI=0.0, iP_SF=0.01, iP_XI=0.01, iP_XS=0.01, iP_BM=0.02,
                iTSS_XI=0.75, iTSS_XS=0.75, iTSS_BM=0.9,
                f_SI=0.0, Y_H=0.67, f_XI_H=0.1,
                Y_PAO=0.625, Y_PO4=0.4, Y_PHA=0.2, f_XI_PAO=0.1,
                Y_A=0.24, f_XI_AUT=0.1,
                K_h=3.0, eta_NO3=0.6, eta_fe=0.4, K_O2=0.2, K_NO3=0.5, K_X=0.1,
                mu_H=4.0, q_fe=3.0, eta_NO3_H=0.8, b_H=0.3, K_O2_H=0.2, K_F=4.0,
                K_fe=4.0, K_A_H=4.0, K_NO3_H=0.5, K_NH4_H=0.05, K_P_H=0.01, K_ALK_H=0.1,
                q_PHA=3.0, q_PP=1.5, mu_PAO=1.0, eta_NO3_PAO=0.6, b_PAO=0.2, b_PP=0.2,
                b_PHA=0.2, K_O2_PAO=0.2, K_NO3_PAO=0.5, K_A_PAO=4.0, K_NH4_PAO=0.05,
                K_PS=0.2, K_P_PAO=0.01, K_ALK_PAO=0.1,
                K_PP=0.01, K_MAX=0.34, K_IPP=0.02, K_PHA=0.01,
                mu_AUT=1.0, b_AUT=0.15, K_O2_AUT=0.5, K_NH4_AUT=1.0, K_ALK_AUT=0.5,
                K_P_AUT=0.01, k_PRE=1.0, k_RED=0.6, K_ALK_PRE=0.5,
                )
        init_conds = {
                'S_I': 30,
                'S_F': 5,
                'S_A': 5,
                'X_I': 1000,
                'X_S': 100,
                'X_H': 500,
                'X_AUT': 100,
                'S_O2': 2,
                'S_NH4': 2,
                'S_N2': 0,
                'S_NO3': 20,
                'S_PO4': 5,
                'X_PAO': 200,
                'X_PP': 100,
                'X_PHA': 100,
                'S_ALK': 7*12,
            }
        DO_ID = 'S_O2'
    else:
        raise ValueError(f'`process_model` can only be "ASM1" or "ASM2d", not {process_model}.')

    # Aeration
    if aerated:
        V = V_aer
        # aer = pc.DiffusedAeration('aer', DO_ID, KLa=240, DOsat=8.0, V=V)
        aer = 2 # fixed DO at 2 mg/L
    else:
        V = V_an
        aer = None

    # Set up system
    inf = WasteStream('influent', T=Temp)
    inf.set_flow_by_concentration(Q, **inf_kwargs)
    eff = WasteStream('effluent', T=Temp)
    CSTR = su.CSTR('CSTR', ins=inf, outs=eff, V_max=V, DO_ID=DO_ID, aeration=aer, suspended_growth_model=asm)
    CSTR.set_init_conc(**init_conds)
    sys = System('sys', path=(CSTR,))
    sys.set_dynamic_tracker(CSTR, inf, eff)
    return sys
Beispiel #13
0
def test_cas():
    from qsdsan import set_thermo
    from exposan import cas

    set_thermo(cas.cmps)
    cas.sys.simulate()