コード例 #1
0
 def __new__(cls, chemicals, cache=None):
     chemicals = tmo.Chemicals(chemicals)
     chemicals_tuple = tuple(chemicals)
     cache = cls._cache
     if chemicals in cache:
         self = cache[chemicals]
     else:
         chemicals.compile(cache)
         self = cache[chemicals_tuple] = chemicals
     return self
コード例 #2
0
def test_chemical_ID_parsing():
    H2O = tmo.Chemical('H2O,g')
    assert H2O.ID == 'H2O'
    assert H2O.locked_state == 'g'
    Steam = tmo.Chemical('Steam,g', search_ID='H2O')
    assert Steam.ID == 'Steam'
    assert Steam.locked_state == 'g'
    chemicals = tmo.Chemicals(['H2O', 'Ethanol', 'O2,g', 'CO2,g'])
    assert [i.ID for i in chemicals] == ['H2O', 'Ethanol', 'O2', 'CO2']
    assert [i.locked_state for i in chemicals] == [None, None, 'g', 'g']
    with pytest.raises(ValueError):
        tmo.Chemical('CO2,v')
コード例 #3
0
def chemicals_from_data(data, all_data):
    new_chemicals = dict(data)
    chemical_copies = {}
    for ID, kwargs in data.items():
        if kwargs:
            if 'Copy of' in kwargs:
                chemical_copies[ID] = kwargs
            else:
                new_chemicals[ID] = tmo.Chemical(ID, **kwargs)
        else:
            new_chemicals[ID] = tmo.Chemical(ID)
    for ID, kwargs in chemical_copies.items():
        copied_ID = kwargs.pop('Copy of')
        try:
            copied_chemical = new_chemicals[copied_ID]
        except KeyError:
            new_chemicals[copied_ID] = copied_chemical = tmo.Chemical(
                copied_ID, **all_data[copied_ID])
        new_chemicals[ID] = copied_chemical.copy(ID, **kwargs)
    return tmo.Chemicals([new_chemicals[i] for i in data])
コード例 #4
0
def test_reaction_enthalpy_balance():
    # Combustion; ensure heat of gas phase reaction without sensible heats is 
    # the lower heating value
    chemicals = H2O, Methane, CO2, O2, H2 = tmo.Chemicals(['H2O', 'Methane', 'CO2', 'O2', 'H2'])
    H2O.H.g.Hvap_Tb = 44011.496 # Depending on the model, this value may be different.
    tmo.settings.set_thermo(chemicals)
    combustion = tmo.Reaction('Methane + O2 -> H2O + CO2',
                              reactant='Methane', X=1,
                              correct_atomic_balance=True)
    Tref = 298.15
    Tb = H2O.Tb
    feed = tmo.Stream(Methane=1, O2=2, T=Tb, phase='g')
    H0 = feed.Hnet - Methane.Cn.g.T_dependent_property_integral(Tref, Tb) - 2 * O2.Cn.g.T_dependent_property_integral(Tref, Tb) 
    combustion(feed)
    Hf = feed.Hnet - 2 * H2O.Cn.l.T_dependent_property_integral(Tref, Tb) - CO2.Cn.g.T_dependent_property_integral(Tref, Tb)
    assert_allclose(Hf - H0, -Methane.LHV)
    
    # Electrolysis of water; ensure heat of reaction without sensible
    # heats is the higher heating value of hydrogen (with opposite sign)
    tmo.settings.set_thermo(chemicals)
    reaction = tmo.Reaction('2H2O,l -> 2H2,g + O2,g', reactant='H2O', X=1)
    feed = tmo.Stream(None, H2O=1)
    H0 = feed.Hnet
    feed.phases = ('g', 'l') # Gas and liquid phases must be available
    reaction(feed) # Call to run reaction on molar flow
    Hf = feed.Hnet
    assert_allclose(Hf - H0, H2.HHV)
    
    # Electrolysis of water; ensure gas phase heat of reaction without sensible
    # heats is the lower heating value of hydrogen (with opposite sign)
    reaction = tmo.Reaction('2H2O -> 2H2 + O2', reactant='H2O', X=1)
    feed = tmo.Stream(None, H2O=1, T=Tref, phase='g')
    H0 = feed.Hnet - H2O.Cn.l.T_dependent_property_integral(Tref, H2O.Tb) - H2O.Cn.g.T_dependent_property_integral(H2O.Tb, Tref)
    reaction(feed) # Call to run reaction on molar flow
    Hf = feed.Hnet
    assert_allclose(Hf - H0, H2.LHV)
コード例 #5
0
def create_chemicals():
    chems = tmo.Chemicals([])

    def append_single_phase_chemical(ID, search_ID=None, **data):
        chemical = tmo.Chemical(ID, search_ID=search_ID, **data)
        try:
            chemical.at_state(phase=chemical.phase_ref)
        except:
            pass
        chemical.default()
        chems.append(chemical)

    def extend_single_phase_chemicals(IDs, **data):
        for ID in IDs:
            append_single_phase_chemical(ID, **data)

    def append_new_single_phase_chemical(ID, source=None, **data):
        chemical = tmo.Chemical.blank(ID, **data)
        if source:
            default_phase_ref = source.phase_ref
            chemical.copy_models_from(source)
        else:
            default_phase_ref = 'l'
        if not chemical.phase_ref:
            chemical.phase_ref = default_phase_ref
        chemical.at_state(chemical.phase_ref)
        chemical.default()
        chems.append(chemical)

    def append_chemical_copy(ID, chemical):
        new_chemical = chemical.copy(ID)
        chems.append(new_chemical)

    def set_Cp(single_phase_chemical, Cp):
        chem = single_phase_chemical
        chem.Cn.add_model(Cp * chem.MW, top_priority=True)

    def set_rho(single_phase_chemical, rho):
        V = fn.rho_to_V(rho, single_phase_chemical.MW)
        single_phase_chemical.V.add_model(V, top_priority=True)

    ### Define species

    # As is in data bank
    chems.extend(
        tmo.Chemicals([
            'Water', 'Ethanol', 'AceticAcid', 'Furfural', 'Glycerol', 'H2SO4',
            'LacticAcid', 'SuccinicAcid', lc.chemicals.P4O10
        ]))
    chems.H2SO4.at_state('l')
    append_single_phase_chemical('HNO3', 'NitricAcid')
    append_single_phase_chemical('Denaturant', 'Octane')
    append_single_phase_chemical('DAP', 'Diammonium Phosphate')
    append_single_phase_chemical('AmmoniumAcetate')
    append_single_phase_chemical('AmmoniumSulfate')
    append_single_phase_chemical('NaNO3', 'SodiumNitrate')
    append_single_phase_chemical('Oil', 'Oleic acid')
    append_single_phase_chemical('HMF')

    # Will remain in the vapor phase
    extend_single_phase_chemicals(['N2', 'NH3', 'O2', 'CH4', 'H2S', 'SO2'])
    append_single_phase_chemical('CO2')

    # Analagous vapors
    append_new_single_phase_chemical('NO2',
                                     chems.N2,
                                     formula='NO2',
                                     Hf=7925 * cal2joule)
    append_new_single_phase_chemical('NO', chems.N2, formula='NO', Hf=82.05)
    append_single_phase_chemical('CO', 'Carbon monoxide', Hf=-110.522)

    # Will remain as  solid
    extend_single_phase_chemicals(['Glucose', 'Xylose', 'Sucrose'], Hfus=0)
    append_single_phase_chemical('CaSO4')

    subgroup = chems['Glucose', 'Xylose', 'Sucrose', 'CaSO4',
                     'AmmoniumSulfate']
    for chemical in subgroup:
        set_Cp(chemical, Cp_cellulosic)

    # Analagous sugars
    append_chemical_copy('Mannose', chems.Glucose)
    append_chemical_copy('Galactose', chems.Glucose)
    append_chemical_copy('Arabinose', chems.Xylose)

    # Other analogues
    append_chemical_copy('CellulaseNutrients', chems.Glucose)
    append_chemical_copy('Extract', chems.Glucose)
    append_chemical_copy('Acetate', chems.AceticAcid)
    append_chemical_copy('Tar', chems.Xylose)
    chems.Acetate.Hf = -103373

    # Chemicals taken from previous study
    chems.append(lc.chemicals.CaO)
    chems.append(lc.chemicals.Ash)
    chems.append(lc.chemicals.NaOH)
    append_new_single_phase_chemical('Lignin',
                                     formula='C8H8O3',
                                     Hf=-108248 * cal2joule)
    set_rho(chems.Lignin, 1540)
    set_Cp(chems.Lignin, Cp_cellulosic)
    append_chemical_copy('SolubleLignin', chems.Lignin)

    # Create structural carbohydrates
    append_chemical_copy('GlucoseOligomer', chems.Glucose)
    set_Cp(chems.GlucoseOligomer, Cp_cellulosic)
    chems.GlucoseOligomer._formula = None
    chems.GlucoseOligomer.formula = "C6H10O5"
    chems.GlucoseOligomer.Hf = -233200 * cal2joule

    append_chemical_copy('GalactoseOligomer', chems.GlucoseOligomer)
    append_chemical_copy('MannoseOligomer', chems.GlucoseOligomer)
    append_chemical_copy('XyloseOligomer', chems.Xylose)
    set_Cp(chems.XyloseOligomer, Cp_cellulosic)
    chems.XyloseOligomer._formula = None
    chems.XyloseOligomer.formula = "C5H8O4"
    chems.XyloseOligomer.Hf = -182100 * cal2joule

    append_chemical_copy('ArabinoseOligomer', chems.XyloseOligomer)

    # Other
    append_new_single_phase_chemical('Z_mobilis',
                                     formula="CH1.8O0.5N0.2",
                                     Hf=-31169.39 * cal2joule)
    append_new_single_phase_chemical('T_reesei',
                                     formula="CH1.645O0.445N0.205S0.005",
                                     Hf=-23200.01 * cal2joule)
    append_new_single_phase_chemical('Biomass',
                                     formula="CH1.64O0.39N0.23S0.0035",
                                     Hf=-23200.01 * cal2joule)
    append_new_single_phase_chemical(
        'Cellulose',
        formula="C6H10O5",  # Glucose monomer minus water
        Hf=-233200.06 * cal2joule)
    append_new_single_phase_chemical('Protein',
                                     formula="CH1.57O0.31N0.29S0.007",
                                     Hf=-17618 * cal2joule)
    append_new_single_phase_chemical('Enzyme',
                                     formula="CH1.59O0.42N0.24S0.01",
                                     Hf=-17618 * cal2joule)
    append_new_single_phase_chemical('Glucan',
                                     formula='C6H10O5',
                                     Hf=-233200 * cal2joule)
    append_new_single_phase_chemical('Xylan',
                                     formula="C5H8O4",
                                     Hf=-182100 * cal2joule)
    append_new_single_phase_chemical('Xylitol',
                                     formula="C5H12O5",
                                     Hf=-243145 * cal2joule)
    append_new_single_phase_chemical('Cellobiose',
                                     formula="C12H22O11",
                                     Hf=-480900 * cal2joule)
    append_new_single_phase_chemical(
        'CSL',
        MW=(chems.Protein.MW / 4 + chems.Water.MW / 2 +
            chems.LacticAcid.MW / 4),
        Hf=(chems.Protein.Hf / 4 + chems.Water.Hf / 2 +
            chems.LacticAcid.Hf / 4))
    append_chemical_copy('DenaturedEnzyme', chems.Enzyme)
    append_chemical_copy('Arabinan', chems.Xylan)
    append_chemical_copy('Mannan', chems.Glucan)
    append_chemical_copy('Galactan', chems.Glucan)

    # TODO: Maybe remove this
    # For waste water
    append_chemical_copy('WWTsludge', chems.Biomass)
    append_chemical_copy('Cellulase', chems.Enzyme)

    chems.compile()
    chems.set_synonym('CaO', 'Lime')
    chems.set_synonym('Water', 'H2O')
    chems.set_synonym('H2SO4', 'SulfuricAcid')
    chems.set_synonym('NH3', 'Ammonia')
    chems.set_synonym('AmmoniumSulfate', 'NH4SO4')
    chems.set_synonym('Denaturant', 'Octane')
    chems.set_synonym('CO2', 'CarbonDioxide')
    return chems
コード例 #6
0
# %% Facilities

# tmo.Stream.default_ID_number = 500
J7_1 = bst.Junction('J7_1', upstream=S402 - 0, downstream=Stream())
BT = bst.facilities.BoilerTurbogenerator('BT',
                                         ins=(J7_1 - 0),
                                         turbogenerator_efficiency=0.85)
BT.outs[-1].T = 373.15

# tmo.Stream.default_ID_number = 700

CWP = bst.facilities.ChilledWaterPackage('CWP')
CT = bst.facilities.CoolingTower('CT')
CT.outs[1].T = 273.15 + 28
water_thermo = tmo.Thermo(tmo.Chemicals(['Water']))
process_water = tmo.Stream(ID='process_water', thermo=water_thermo)

process_water_streams = (caustic, stripping_water, process_water1,
                         process_water2, steam, BT - 1, CT - 1)


def update_water_loss():
    process_water.imol['Water'] = sum(
        [i.imol['Water'] for i in process_water_streams])


makeup_water = Stream('makeup_water',
                      thermo=water_thermo,
                      price=price['Makeup water'])
コード例 #7
0
# %%  Constants

# Common structural carbohydrates properties

# Assume heat capacity of lignin, cellulose, and hemicellulose
# and all components at 350 K are about the same [2,2].
Cp_cellulosic = 1.364

# Assume density is similar for most solids
rho = 1540  # kg/m3

cal2joule = 4.184

# %% Initialize Chemicals object and define functions

chems = wheatstraw_chemicals = tmo.Chemicals([])

# Chemicals to define
chemical_IDs = [
    'Water', 'Ethanol', 'Glucose', 'Galactose', 'Mannose', 'Xylose',
    'Arabinose', 'Cellobiose', 'Sucrose', 'GlucoseOligomer',
    'GalactoseOligomer', 'MannoseOligomer', 'XyloseOligomer',
    'ArabinoseOligomer', 'Extract', 'SolubleLignin', 'HMF', 'Furfural',
    'AceticAcid', 'LacticAcid', 'Xylitol', 'Glycerol', 'SuccinicAcid', 'NH3',
    'H2SO4', 'NH4SO4', 'AmmoniumAcetate', 'DAP', 'HNO3', 'NaNO3', 'NaOH',
    'CellulaseNutrients', 'Denaturant', 'Oil', 'Cellulose', 'Galactan',
    'Mannan', 'Glucan', 'Xylan', 'Arabinan', 'Lignin', 'Acetate', 'Protein',
    'Ash', 'Enzyme', 'DenaturedEnzyme', 'S_cerevisiae', 'T_reesei', 'Biomass',
    'Tar', 'CaO', 'CaSO4', 'Graphite', 'N2', 'O2', 'CO2', 'CH4', 'H2S', 'SO2',
    'NO', 'CO', 'AmmoniumSulfate', 'NO2', 'CSL', 'WWTsludge', 'Cellulase'
]
コード例 #8
0
    
@author: yalinli_cabbi
"""

# %%

# =============================================================================
# Setup
# =============================================================================

import thermosteam as tmo

__all__ = ('chems', 'chemical_groups', 'soluble_organics', 'combustibles')

# All chemicals used in this biorefinery
chems = tmo.Chemicals([])

# To keep track of which chemicals are available in the database and which
# are created from scratch
database_chemicals_dict = {}
copied_chemicals_dict = {}
defined_chemicals_dict = {}


def chemical_database(ID, phase=None, **kwargs):
    chemical = tmo.Chemical(ID, **kwargs)
    if phase:
        chemical.at_state(phase)
        chemical.phase_ref = phase
    chems.append(chemical)
    database_chemicals_dict[ID] = f'{ID}: {chemical.formula}/{chemical.MW}'
コード例 #9
0
ファイル: chemicals.py プロジェクト: yoelcortes/biosteam_lca
# %%  Constants

# Common structural carbohydrates properties

# Assume heat capacity of lignin, cellulose, and hemicellulose
# and all components at 350 K are about the same [2,2].
Cp_cellulosic = 1.364

# Assume density is similar for most solids
rho = 1540 # kg/m3

cal2joule = 4.184

# %% Initialize Chemicals object and define functions

chems = cornstover_chemicals = tmo.Chemicals([])

# Chemicals to define
chemical_IDs = [
        'Water', 'Ethanol', 'Glucose', 'Galactose',
        'Mannose', 'Xylose', 'Arabinose', 'Cellobiose',
        'Sucrose', 'GlucoseOligomer', 'GalactoseOligomer',
        'MannoseOligomer', 'XyloseOligomer', 'ArabinoseOligomer',
        'Extract','SolubleLignin','HMF', 'Furfural', 'AceticAcid',
        'LacticAcid', 'Xylitol', 'Glycerol', 'SuccinicAcid',
        'NH3', 'H2SO4', 'NH4SO4', 'AmmoniumAcetate', 'DAP',
        'HNO3', 'NaNO3', 'NaOH', 'CellulaseNutrients',
        'Denaturant', 'Oil', 'Cellulose', 'Galactan', 'Mannan', 'Glucan',
        'Xylan', 'Arabinan', 'Lignin', 'Acetate', 'Protein',
        'Ash', 'Enzyme', 'DenaturedEnzyme', 'Z_mobilis', 'T_reesei',
        'Biomass', 'Tar', 'CaO', 'CaSO4', 'Graphite', 'N2', 'O2', 'CO2',
コード例 #10
0
ファイル: chemicals.py プロジェクト: yoelcortes/biosteam_lca
# -*- coding: utf-8 -*-
"""
Created on Tue Feb  4 06:42:02 2020

@author: yoelr
"""
from thermosteam import functional as fn
import thermosteam as tmo

__all__ = ('lipidcane_chemicals', 'pretreatment_chemicals',
           'ethanol_chemicals', 'biodiesel_chemicals')

# %% Define common chemicals
Biodiesel = tmo.Chemical('Biodiesel', search_ID='Methyl oleate')
lipidcane_chemicals = tmo.Chemicals([
    'Water', 'Methanol', 'Ethanol', 'Glycerol', 'Glucose', 'Sucrose', 'H3PO4',
    'P4O10', 'CO2', 'Octane', 'O2', Biodiesel
])

(Water, Methanol, Ethanol, Glycerol, Glucose, Sucrose, H3PO4, P4O10, CO2,
 Octane, O2, Biodiesel) = lipidcane_chemicals

O2.at_state(phase='g')
CO2.at_state(phase='g')
H3PO4.at_state(phase='s')
P4O10.at_state(phase='s')
Glucose.at_state(phase='s')
Sucrose.at_state(phase='s')

# %% Define new chemicals

コード例 #11
0
def test_stream():
    import thermosteam as tmo
    tmo.settings.set_thermo(['Water'], cache=True)
    stream = tmo.Stream(None, Water=1, T=300)
    assert [stream.chemicals.Water] == stream.available_chemicals
    assert_allclose(stream.epsilon, 77.70030000000003)
    assert_allclose(stream.alpha * 1e6, 0.14330776454124503)
    assert_allclose(stream.nu, 8.799123532986536e-07)
    assert_allclose(stream.Pr, 6.14001869413997)
    assert_allclose(stream.Cn, 75.29555729396768)
    assert_allclose(stream.C, 75.29555729396768)
    assert_allclose(stream.Cp, 4.179538552493643)
    assert_allclose(stream.P_vapor, 3533.918074415897)
    assert_allclose(stream.mu, 0.0008766363688287887)
    assert_allclose(stream.kappa, 0.5967303492959747)
    assert_allclose(stream.rho, 996.2769195618362)
    assert_allclose(stream.V, 1.80826029854462e-05)
    assert_allclose(stream.H, 139.31398526921475)
    assert_allclose(stream.S, 70.46581776376684)
    assert_allclose(stream.sigma, 0.07176932405246211)
    assert_allclose(stream.z_mol, [1.0])
    assert_allclose(stream.z_mass, [1.0])
    assert_allclose(stream.z_vol, [1.0])
    assert not stream.source
    assert not stream.sink
    assert stream.main_chemical == 'Water'
    assert not stream.isfeed()
    assert not stream.isproduct()
    assert stream.vapor_fraction == 0.
    with pytest.raises(ValueError):
        stream.get_property('isfeed', 'kg/hr')
    with pytest.raises(ValueError):
        stream.set_property('invalid property', 10, 'kg/hr')
    with pytest.raises(ValueError):
        tmo.Stream(None, Water=1, units='kg')

    stream.mol = 0.
    stream.mass = 0.
    stream.vol = 0.

    with pytest.raises(AttributeError):
        stream.F_mol = 1.
    with pytest.raises(AttributeError):
        stream.F_mass = 1.
    with pytest.raises(AttributeError):
        stream.F_vol = 1.

    # Make sure energy balance is working correctly with mix_from and vle
    chemicals = tmo.Chemicals(['Water', 'Ethanol'])
    thermo = tmo.Thermo(chemicals)
    tmo.settings.set_thermo(thermo)
    s3 = tmo.Stream('s3', T=300, P=1e5, Water=10, units='kg/hr')
    s4 = tmo.Stream('s4', phase='g', T=400, P=1e5, Water=10, units='kg/hr')
    s_eq = tmo.Stream('s34_mixture')
    s_eq.mix_from([s3, s4])
    s_eq.vle(H=s_eq.H, P=1e5)
    H_sum = s3.H + s4.H
    H_eq = s_eq.H
    assert_allclose(H_eq, H_sum, rtol=1e-3)
    s_eq.vle(H=s3.H + s4.H, P=1e5)
    assert_allclose(s_eq.H, H_sum, rtol=1e-3)
コード例 #12
0
ファイル: _system.py プロジェクト: ebrace/Bioindustrial-Park
def create_system(ID='wheatstraw_sys'):
    System.maxiter = 400
    System.converge_method = 'Aitken'
    System.molar_tolerance = 0.01

    ### Streams ###
    chemicals = bst.settings.get_chemicals()
    non_soluble = [
        'Xylan', 'Glucan', 'Arabinan', 'Lignin', 'Extract', 'Ash', 'Mannan',
        'Galactan', 'Acetate'
    ]
    # feed flow
    drycomposition = chemicals.kwarray(
        dict(Glucan=0.3342,
             Xylan=0.2330,
             Arabinan=0.0420,
             Lignin=0.2260,
             Extract=0.1330,
             Ash=0.0180,
             Acetate=0.0130))
    TS = 0.95
    moisture_content = chemicals.kwarray(dict(Water=1 - TS))
    dryflow = 83333.0
    netflow = dryflow / TS
    feedflow = netflow * (drycomposition * TS + moisture_content)
    process_water_over_dryflow = 19.96
    sulfuric_acid_over_dryflow = 0.04

    wheatstraw = Stream('wheatstraw',
                        feedflow,
                        units='kg/hr',
                        price=price['Feedstock'] * TS)

    # %% Pretreatment system

    process_water1 = Stream(
        'process_water1',
        T=25 + 273.15,
        P=1 * 101325,
        Water=process_water_over_dryflow * dryflow,  #only an initialization
        units='kg/hr')

    sulfuric_acid = Stream('sulfuric_acid',
                           P=1 * 101325,
                           T=25 + 273.15,
                           Water=0.05 * sulfuric_acid_over_dryflow * dryflow,
                           SulfuricAcid=0.95 * sulfuric_acid_over_dryflow *
                           dryflow,
                           units='kg/hr',
                           price=price['Sulfuric acid'] * 0.95)
    steam = Stream(
        'steam',
        phase='g',
        T=212 + 273.15,
        P=20 * 101325,
        Water=dryflow * 0.5,  #This is just a guess
        units='kg/hr')

    U101 = units.FeedStockHandling('U101', ins=wheatstraw)
    U101.cost_items['System'].cost = 0
    T201 = units.SulfuricAcidTank('T201', ins=sulfuric_acid)
    M201 = bst.Mixer('M201', ins=(process_water1, T201 - 0, Stream()))
    M202 = units.WashingTank('M202', ins=(M201 - 0, U101 - 0))
    S200 = units.SieveFilter('S200',
                             ins=(M202 - 0),
                             outs=(Stream('feed_20TS'),
                                   Stream('recycled_water1')),
                             moisture_content=1 - 0.20,
                             split=find_split_solids(M202 - 0, non_soluble))
    S201 = units.PressureFilter('S201',
                                ins=(S200 - 0),
                                outs=(Stream('feed_50TS'),
                                      Stream('recycled_water2')),
                                moisture_content=0.5,
                                split=find_split_solids(S200 - 0, non_soluble))
    M200 = bst.Mixer('M200', ins=(S200 - 1, S201 - 1), outs='recycled_water')
    M200 - 0 - 2 - M201
    recycled_water = M200 - 0

    def update_process_water1():
        process_water1.imass[
            'Water'] = process_water_over_dryflow * dryflow - recycled_water.imass[
                'Water']
        sulfuric_acid.imass[
            'SulfuricAcid'] = 0.95 * sulfuric_acid_over_dryflow * dryflow - recycled_water.imass[
                'SulfuricAcid']
        sulfuric_acid.imass[
            'Water'] = 0.05 / 0.95 * sulfuric_acid.imass['SulfuricAcid']

    water_recycle_sys = System('water_recycle_sys',
                               path=(U101, T201, M201, M202, S200, S201, M200,
                                     update_process_water1),
                               recycle=M201 - 0)
    M205 = bst.Mixer('M205', ins=(S201 - 0, None))

    M203 = units.SteamMixer('M203',
                            ins=(M205 - 0, steam),
                            P=steam.chemicals.Water.Psat(190.0 + 273.15))
    R201 = units.PretreatmentReactorSystem(
        'R201',
        ins=M203 - 0,
        outs=(Stream('pretreatment_steam'), Stream('pretreatment_effluent')))
    P201 = units.BlowdownDischargePump('P201', ins=R201 - 1)
    T202 = units.OligomerConversionTank('T202', ins=P201 - 0)
    F201 = units.PretreatmentFlash('F201',
                                   ins=T202 - 0,
                                   outs=(Stream('flash_steam'),
                                         Stream('flash_effluent')),
                                   P=101325,
                                   Q=0)
    M204 = bst.Mixer('M204', ins=(R201 - 0, F201 - 0))
    S202 = units.PressureFilter('S202',
                                ins=(F201 - 1),
                                outs=(Stream('pretreated_stream'),
                                      Stream('pretreated_liquid')),
                                moisture_content=0.5,
                                split=find_split_solids(F201 - 1, non_soluble))
    S203 = bst.Splitter('S203',
                        ins=M204 - 0,
                        outs=(Stream('steam_back'), Stream('residual_steam')),
                        split=0.25)
    H201 = units.WasteVaporCondenser('H201',
                                     ins=S203 - 1,
                                     outs=Stream('condensed_steam'),
                                     T=99 + 273.15,
                                     V=0)
    S203 - 0 - 1 - M205

    steam_out1 = S203 - 1
    steam_inS203 = 0 - S203
    steam_out0 = S203 - 0

    def update_split():
        steam_out1.mol[:] = steam_inS203.mol[:] - steam_out0.mol[:]

    pretreatment_sys = System(
        'pretreatment_sys',
        path=(
            water_recycle_sys, M205, M203, R201, P201, T202, F201, M204, S202,
            S203, update_split,
            H201),  # TODO: H201 moved to the end, no need to resimulate system
        recycle=M204 - 0)

    ### TODO: There is a bug in original code; for now spec is constant
    #    S203.split[:] = 0.5
    T90 = 90 + 273.15

    def f_DSpret(split):
        S203.split[:] = split
        for i in range(3):
            pretreatment_sys.simulate()
        sobj = M205 - 0
        return sobj.T - T90

    pretreatment_sys.specification = BoundedNumericalSpecification(
        f_DSpret, 0.10, 0.70)

    ### Fermentation system ###

    cellulase_conc = 0.05
    cellulase = Stream('cellulase', units='kg/hr', price=price['Enzyme'])

    ammonia = Stream(
        'ammonia',
        Ammonia=1051 / 1000 * dryflow,  #This is just a initialization
        units='kg/hr',
        phase='l',
        price=price['Ammonia'])

    process_water2 = Stream(
        'process_water2',
        T=10 + 273.15,
        P=1 * 101325,
        Water=1664.8 / 1000 * dryflow,  #This is just a guess
        units='kg/hr')
    ammonia1 = Stream(
        'ammonia1',
        Ammonia=26 / 1000 * dryflow,  #This is just a initialization
        units='kg/hr',
        price=price['Ammonia'])
    ammonia2 = Stream(
        'ammonia2',
        Ammonia=116 / 1000 * dryflow,  #This is just a initialization
        units='kg/hr',
        price=price['Ammonia'])

    ammonia_fresh = Stream('ammonia_fresh',
                           units='kg/hr',
                           price=price['Ammonia'])

    ammonia_storage = units.DAPTank('Ammonia_storage',
                                    ins=ammonia_fresh,
                                    outs='Ammonia_fermentation')

    S301 = bst.ReversedSplitter('S301',
                                ins=ammonia_storage - 0,
                                outs=(ammonia, ammonia1, ammonia2))

    air1 = Stream('air_lagoon1', O2=51061, N2=168162, phase='g', units='kg/hr')
    air2 = Stream('air_lagoon2', O2=51061, N2=168162, phase='g', units='kg/hr')

    J1 = bst.Junction('J1', upstream=S202 - 0, downstream=Stream())

    sacch_split = 0.05  #This is just a initialization

    ammonia_zmass = 0.0052

    M301 = bst.Mixer('M301', ins=(ammonia, process_water2))
    M302 = bst.Mixer('M302', ins=(J1 - 0, M301 - 0))
    S303 = units.PressureFilter('S303',
                                ins=(M302 - 0),
                                outs=(Stream('cooled_hydrolysate'),
                                      Stream('residual_water')),
                                moisture_content=0.4,
                                split=find_split_solids(M302 - 0, non_soluble))
    WIS_prehyd = 0.20
    cooled_hydrolyzate_pre = M302.outs[0]
    S303_out0 = S303.outs[0]
    S303_out1 = S303.outs[1]

    def update_moisture_content():
        F_non_sol_S303in = find_WIS(
            cooled_hydrolyzate_pre,
            non_soluble) * cooled_hydrolyzate_pre.F_mass
        F_sol_S303in = cooled_hydrolyzate_pre.F_mass - F_non_sol_S303in
        F_sol_S303out = F_non_sol_S303in / WIS_prehyd - cellulase.F_mass - F_non_sol_S303in
        split_soluble = F_sol_S303out / F_sol_S303in
        new_split = find_split_solids(cooled_hydrolyzate_pre, non_soluble)
        new_split[new_split == 0] = split_soluble
        S303_out0.mass[:] = cooled_hydrolyzate_pre.mass[:] * new_split
        S303_out1.mass[:] = cooled_hydrolyzate_pre.mass[:] * (1 - new_split)

    T203 = units.AmmoniaAdditionTank('T203', ins=S303 - 0)
    M303 = units.EnzymeHydrolysateMixer('M303', ins=(T203 - 0, cellulase))

    cellulase_over_WIS = 0.05 * cellulase_conc
    water_over_WIS = 0.05 * (1 - cellulase_conc)

    def update_cellulase_and_nutrient_loading():
        WIS_premixer = cooled_hydrolyzate_pre.F_mass * find_WIS(
            cooled_hydrolyzate_pre, non_soluble)
        cellulase_mass = cellulase_over_WIS * WIS_premixer
        water_mass = water_over_WIS * WIS_premixer
        cellulase.imass['Cellulase'] = cellulase_mass * 1.1
        cellulase.imass['Water'] = water_mass * 1.1
        # Note: An additional 10% is produced for the media glucose/sophorose mixture
        # Humbird (2011) p[g. 37

    def update_ammonia_loading():
        water_cooled_hydrolyzate = cooled_hydrolyzate_pre.imass['Water']
        ammonia.F_mass = water_cooled_hydrolyzate * ammonia_zmass

    M304 = bst.Mixer('M304', ins=(M303 - 0, None))
    R301 = units.SaccharificationAndCoFermentation(
        'R301',
        ins=(M304 - 0, ammonia1, air1),
        outs=(Stream('CO2_1'), Stream('fermentation_slurry'),
              Stream('saccharified_to_seed')),
        saccharified_slurry_split=sacch_split)
    M305 = bst.Mixer('M305', ins=(R301 - 2, ammonia2, air2))
    R302 = units.SeedTrain('R302',
                           ins=M305 - 0,
                           outs=(Stream('CO2_2'), Stream('effluent')))
    T301 = units.SeedHoldTank('T301', ins=R302 - 1)
    T301 - 0 - 1 - M304

    air2_over_glucose = (R302.reactions.X[1] * 2.17 + R302.reactions.X[3] *
                         1.5 / 2 - R302.reactions.X[2]) * 1.1
    ammonia2_over_glucose = R302.reactions.X[1] * 0.62 * 1.1

    preseed = M305 - 0

    def update_nutrient_loading2():
        glucose_preseed = preseed.imol['Glucose']

        air2.imol['O2'] = air2_over_glucose * glucose_preseed
        air2.imol['N2'] = (air2_over_glucose * glucose_preseed) / 0.21 * 0.79
        ammonia2_mol = ammonia2_over_glucose * glucose_preseed - preseed.imol[
            'Ammonia']
        if ammonia2_mol < 0:
            ammonia2.imol['NH3'] = 0
        else:
            ammonia2.imol['NH3'] = ammonia2_mol

    air1_over_glucose = (R301.cofermentation.X[1] * 2.17 +
                         R301.cofermentation.X[3] * 1.5 / 2 -
                         R301.cofermentation.X[2]) * 1.2
    ammonia1_over_glucose = R301.cofermentation.X[1] * 0.62 * 1.1

    preferm = M304 - 0
    glucose_over_glucan = R301.saccharification.X[
        0] + R301.saccharification.X[1] * 0.5 + R301.saccharification.X[2]

    def update_nutrient_loading1():
        glucose_preferm = preferm.imol['Glucan'] * glucose_over_glucan * (
            1 - R301.saccharified_slurry_split)
        air1.imol['O2'] = air1_over_glucose * glucose_preferm
        air1.imol['N2'] = (air1_over_glucose * glucose_preferm) / 0.21 * 0.79
        ammonia1_mol = ammonia1_over_glucose * glucose_preferm - preferm.imol[
            'Ammonia'] * (1 - R301.saccharified_slurry_split)
        if ammonia1_mol < 0:
            ammonia1.imol['NH3'] = 0
        else:
            ammonia1.imol['NH3'] = ammonia1_mol

    # TODO: Bug in update nutrient loading (not enough O2 to run R301 and R302 seed train)
    # TODO: so just ignore negative flow in the meanwhile
#    def ignore_negative_O2_flow():
#        for i in (R301.outs + R302.outs): i.imol['O2'] = 0

    seed_recycle_sys = System('seed_recycle_sys',
                              path=(M304, update_nutrient_loading1, R301, M305,
                                    update_nutrient_loading2, R302, T301),
                              recycle=M304 - 0)
    conc_yeast = 3.0

    def f_DSferm1(x):
        sacch_split = x
        R301.saccharified_slurry_split = sacch_split
        for i in range(3):
            seed_recycle_sys.simulate()
        s_obj2 = R301 - 1
        light_ind = s_obj2.chemicals._light_indices
        l = [a for a in s_obj2.vol[light_ind] if not a == 0]
        v_0 = s_obj2.F_vol - sum(l)
        conc_yeast_obtained = s_obj2.imass['S_cerevisiae'] / v_0
        return ((conc_yeast_obtained - conc_yeast) / conc_yeast)

    seed_recycle_sys.specification = BoundedNumericalSpecification(
        f_DSferm1, 0.01, 0.35)

    fermentation_sys = System(
        'fermentation_sys',
        path=(J1, M301, M302, S303, update_ammonia_loading, T203,
              update_cellulase_and_nutrient_loading, update_moisture_content,
              M303, seed_recycle_sys))  #update_moisture_content,
    T_solid_cool = 50.0 + 273.15

    def f_DSferm2(x):
        mass_water = x
        process_water2.F_mass = mass_water
        for i in range(3):
            fermentation_sys.simulate()
        s_obj1 = M302 - 0
        return ((s_obj1.T - T_solid_cool) / T_solid_cool)

    fermentation_sys.specification = BoundedNumericalSpecification(
        f_DSferm2, process_water2.F_mass / 2, process_water2.F_mass * 2)

    ### Ethanol purification ###

    stripping_water = Stream(
        'stripping_water',
        Water=26836,  #This is just a initialization
        units='kg/hr')

    M306 = bst.Mixer('M306', ins=(R302 - 0, R301 - 0))
    T302 = units.BeerTank('T302', outs=Stream('cool_feed'))

    # tmo.Stream.default_ID_number = 400

    M401 = bst.Mixer('M401', ins=(R301 - 1, None))
    M401 - 0 - T302

    D401 = bst.VentScrubber('D401',
                            ins=(stripping_water, M306 - 0),
                            outs=(Stream('CO2_purified'),
                                  Stream('bottom_liquid')),
                            gas=('CO2', 'NH3', 'O2', 'N2'))
    D401 - 1 - 1 - M401

    # Heat up before beer column
    # Exchange heat with stillage

    mid_eth_massfrac = 0.50
    high_eth_massfrac = 0.915
    bott_eth_massfrac = 0.00001
    dist_high_pres = 2 * 101325

    high_dist_stream = Stream('high_eth_stream',
                              Ethanol=high_eth_massfrac,
                              Water=1 - high_eth_massfrac,
                              units='kg/hr')

    mid_dist_stream = Stream('mid_eth_stream',
                             Ethanol=mid_eth_massfrac,
                             Water=1 - mid_eth_massfrac,
                             units='kg/hr')

    bottom_stream = Stream(
        'bottom_stream',
        Ethanol=
        bott_eth_massfrac,  #only an initialization. Later it gets updated with the real composition
        Water=1 - bott_eth_massfrac,
        units='kg/hr')

    dist_high_dp = high_dist_stream.dew_point_at_P(dist_high_pres)
    bott_mid_dp = bottom_stream.dew_point_at_T(dist_high_dp.T - 5)
    dist_mid_dp = mid_dist_stream.dew_point_at_P(bott_mid_dp.P)
    bott_low_dp = bottom_stream.dew_point_at_T(dist_mid_dp.T - 5)
    dist_low_dp = mid_dist_stream.dew_point_at_P(bott_low_dp.P)

    S401 = bst.Splitter('S401',
                        ins=(T302 - 0),
                        outs=(Stream('feed_low_pressure', P=bott_low_dp.P),
                              Stream('feed_mid_pressure', P=bott_mid_dp.P)),
                        split=0.5)

    H402 = bst.HXprocess('H402',
                         ins=(S401 - 0, None),
                         outs=(Stream('warmed_feed_lp'),
                               Stream('cooled_bottom_water_lp')),
                         U=1.28)
    H403 = bst.HXprocess('H403',
                         ins=(S401 - 1, None),
                         outs=(Stream('warmed_feed_mp'),
                               Stream('cooled_bottom_water_mp')),
                         U=1.28)

    # Beer column

    Ethanol_MW = chemicals.Ethanol.MW
    Water_MW = chemicals.Water.MW

    def Ethanol_molfrac(e):
        """Return ethanol mol fraction in a ethanol water mixture"""
        return e / Ethanol_MW / (e / Ethanol_MW + (1 - e) / Water_MW)

    xbot = Ethanol_molfrac(bott_eth_massfrac)
    ytop = Ethanol_molfrac(mid_eth_massfrac)

    D402 = units.DistillationColumn('D402',
                                    ins=H402 - 0,
                                    P=bott_low_dp.P,
                                    y_top=ytop,
                                    x_bot=xbot,
                                    k=1.5,
                                    LHK=('Ethanol', 'Water'),
                                    energy_integration=True)
    D402.tray_material = 'Stainless steel 304'
    D402.vessel_material = 'Stainless steel 304'
    D402.BM = 2.4
    D402.boiler.U = 1.85
    # Condense distillate
    H402_dist = bst.HXutility('H402_dist',
                              ins=D402 - 0,
                              V=0,
                              T=dist_low_dp.T - 1)

    P402_2 = bst.Pump('P402_2', ins=H402_dist - 0, P=bott_mid_dp.P)
    P402_2.BM = 3.1

    D402 - 1 - 1 - H402

    LP_dist_sys = System('LP_dist_sys',
                         path=(H402, D402, H402_dist),
                         recycle=H402 - 0)

    D403 = units.DistillationColumn('D403',
                                    ins=H403 - 0,
                                    P=bott_mid_dp.P,
                                    y_top=ytop,
                                    x_bot=xbot,
                                    k=1.5,
                                    LHK=('Ethanol', 'Water'),
                                    energy_integration=True)
    D403.tray_material = 'Stainless steel 304'
    D403.vessel_material = 'Stainless steel 304'
    D403.BM = 2.4
    D403.boiler.U = 1.85
    # Condense distillate
    H403_dist = bst.HXutility('H403_dist',
                              ins=D403 - 0,
                              V=0,
                              T=dist_mid_dp.T - 1)

    D403 - 1 - 1 - H403

    MP_dist_sys = System('MP_dist_sys',
                         path=(H403, D403, H403_dist),
                         recycle=H403 - 0)

    M402 = bst.Mixer('M402',
                     ins=(P402_2 - 0, H403_dist - 0),
                     outs=Stream(P=bott_mid_dp.P))
    P404 = bst.Pump('P404', ins=M402 - 0, P=dist_high_pres)

    M403 = bst.Mixer('M403',
                     ins=(H402 - 1, H403 - 1),
                     outs=Stream('bottom_water'))

    S402 = units.PressureFilter('S402',
                                ins=(M403 - 0),
                                outs=(Stream('Lignin'),
                                      Stream('Thin_spillage')),
                                flux=1220.6 * 0.8,
                                moisture_content=0.35,
                                split=find_split_solids(M403 - 0, non_soluble))

    # Mix ethanol Recycle (Set-up)
    M404 = bst.Mixer('M404',
                     ins=(P404 - 0, None),
                     outs=Stream(P=dist_high_pres))

    ytop = Ethanol_molfrac(high_eth_massfrac)
    D404 = units.DistillationColumn('D404',
                                    ins=M404 - 0,
                                    P=dist_high_pres,
                                    y_top=ytop,
                                    x_bot=xbot,
                                    k=1.5,
                                    LHK=('Ethanol', 'Water'),
                                    energy_integration=True)
    D404.tray_material = 'Stainless steel 304'
    D404.vessel_material = 'Stainless steel 304'

    D404.BM = 2.4
    D404.boiler.U = 1.85

    P405 = bst.Pump('P405', ins=D404 - 1, outs=Stream('bottom_water'))

    # Superheat vapor for mol sieve
    H404 = bst.HXutility('H404', ins=D404 - 0, T=dist_high_dp.T + 37.0, V=1)

    # Molecular sieve
    U401 = bst.MolecularSieve('U401',
                              ins=H404 - 0,
                              split=(2165.14 / 13356.04, 1280.06 / 1383.85),
                              order=('Ethanol', 'Water'))

    U401 - 0 - 1 - M404

    ethanol_recycle_sys = System('ethanol_recycle_sys',
                                 path=(M404, D404, H404, U401),
                                 recycle=M404 - 0)

    # Condense ethanol product
    H405 = bst.HXutility('H405', ins=U401 - 1, V=0, T=dist_high_dp.T - 1)

    T701 = bst.StorageTank('T701',
                           ins=H405 - 0,
                           tau=7 * 24,
                           vessel_type='Floating roof',
                           vessel_material='Carbon steel')

    ethanol = Stream('ethanol', price=price['Ethanol'])
    P701 = bst.Pump('P701', ins=T701 - 0, outs=ethanol)

    P701.BM = 3.1
    T701.BM = 1.7

    vent_stream = M306 - 0
    stripping_water_over_vent = stripping_water.mol / 21202.490455845436

    def update_stripping_water():
        stripping_water.mol[:] = stripping_water_over_vent * vent_stream.F_mass

    purification_sys = System(
        'purification_sys',
        path=(M306, update_stripping_water, D401, M401, T302, S401,
              MP_dist_sys, LP_dist_sys, P402_2, M402, P404, M403, S402,
              ethanol_recycle_sys, P405, H405, T701, P701))

    def f_DSpur(split):
        S401.split[:] = split
        for i in range(3):
            purification_sys.simulate()
        heat_cond = D403.condenser.Q + H403_dist.Q
        heat_boil = D402.boiler.Q
        return heat_boil + heat_cond  #heat_boil and heat_cond have different signs

    purification_sys.specification = BoundedNumericalSpecification(
        f_DSpur, 0.10, 0.70)

    ### Biogas production

    organic_groups = [
        'OtherSugars', 'SugarOligomers', 'OrganicSolubleSolids', 'Furfurals',
        'OtherOrganics', 'Protein', 'CellMass'
    ]
    organics = list(
        sum([chemical_groups[i] for i in organic_groups],
            ('Ethanol', 'AceticAcid', 'Xylose', 'Glucose', 'ExtractVol',
             'ExtractNonVol')))
    organics.remove('WWTsludge')

    P_sludge = 0.05 / 0.91 / chemicals.WWTsludge.MW
    MW = np.array([chemicals.CH4.MW, chemicals.CO2.MW])
    CH4_molcomp = 0.60
    mass = np.array([CH4_molcomp, 1 - CH4_molcomp]) * MW
    mass /= mass.sum()
    mass *= 0.381 / (0.91)
    P_ch4, P_co2 = mass / MW

    def anaerobic_rxn(reactant):
        MW = getattr(chemicals, reactant).MW
        return rxn.Reaction(
            f"{1/MW}{reactant} -> {P_ch4}CH4 + {P_co2}CO2 + {P_sludge}WWTsludge",
            reactant, 0.91)

    anaerobic_digestion = rxn.ParallelReaction(
        [anaerobic_rxn(i) for i in organics] +
        [rxn.Reaction(f"H2SO4 -> H2S + 2O2", 'H2SO4', 1.)])

    well_water1 = Stream('well_water1', Water=1, T=15 + 273.15)

    J5_1 = bst.Junction('J5_1', upstream=S303 - 1, downstream=Stream())
    J5_2 = bst.Junction('J5_2', upstream=S402 - 1, downstream=Stream())
    J5_3 = bst.Junction('J5_3', upstream=S202 - 1, downstream=Stream())
    J5_4 = bst.Junction('J5_4', upstream=H201 - 0, downstream=Stream())
    J5_5 = bst.Junction('J5_5', upstream=P405 - 0, downstream=Stream())
    M501 = bst.Mixer('M501',
                     ins=(J5_1 - 0, J5_2 - 0, J5_3 - 0, J5_4 - 0, J5_5 - 0))

    splits = [('Ethanol', 1, 15), ('Water', 27158, 356069), ('Glucose', 3, 42),
              ('Xylose', 7, 85), ('OtherSugars', 13, 175),
              ('SugarOligomers', 10, 130), ('OrganicSolubleSolids', 182, 2387),
              ('InorganicSolubleSolids', 8, 110), ('Ammonia', 48, 633),
              ('AceticAcid', 0, 5), ('Furfurals', 5, 70),
              ('OtherOrganics', 9, 113), ('Cellulose', 19, 6), ('Xylan', 6, 2),
              ('OtherStructuralCarbohydrates', 1, 0), ('Lignin', 186, 64),
              ('Protein', 51, 18), ('CellMass', 813, 280),
              ('OtherInsolubleSolids', 68, 23)]

    raw_biogas = Stream('raw_biogas', price=price['Pure biogas'] * 0.33)
    Tin_digestor = 37 + 273.15
    R501 = units.AnaerobicDigestion('R501',
                                    ins=(M501 - 0, well_water1),
                                    outs=(raw_biogas, 'waste_effluent',
                                          'sludge_effluent', ''),
                                    reactions=anaerobic_digestion,
                                    sludge_split=find_split(*zip(*splits)),
                                    T=Tin_digestor)

    digestor_sys = System('digestor_sys',
                          path=(J5_1, J5_2, J5_3, J5_4, J5_5, M501, R501))

    ### Waste water treatment
    combustion = chemicals.get_combustion_reactions()

    def growth(reactant):
        f = chemicals.WWTsludge.MW / getattr(chemicals, reactant).MW
        return rxn.Reaction(f"{f}{reactant} -> WWTsludge", reactant, 1.)

    # Note, nitrogenous species included here, but most of it removed in R601 digester
    aerobic_digestion = rxn.ParallelReaction([
        i * 0.74 + 0.22 * growth(i.reactant) for i in combustion
        if (i.reactant in organics)
    ])
    aerobic_digestion.X[:] = 0.96

    # tmo.Stream.default_ID_number = 600

    well_water = Stream('well_water', Water=1, T=15 + 273.15)
    raw_biogas2 = Stream('raw_biogas2', price=price['Pure biogas'] * 0.33)
    WWTC = units.WasteWaterSystemCost('WWTC', ins=R501 - 1)
    R601 = units.AnaerobicDigestionWWT('R601',
                                       ins=(WWTC - 0, well_water),
                                       outs=(raw_biogas2, '', '', ''),
                                       reactions=anaerobic_digestion,
                                       sludge_split=find_split(*zip(*splits)),
                                       T=Tin_digestor - 2)

    air = Stream('air_lagoon', O2=51061, N2=168162, phase='g', units='kg/hr')
    caustic = Stream('WWT_caustic',
                     Water=2252,
                     NaOH=2252,
                     units='kg/hr',
                     price=price['Caustic'] * 0.5)
    # polymer = Stream('WWT polymer') # Empty in humbird report :-/

    M602 = bst.Mixer('M602', ins=(R601 - 1, None))

    caustic_over_waste = caustic.mol / 2544300.6261793654
    air_over_waste = air.mol / 2544300.6261793654
    waste = M602 - 0

    def update_aerobic_input_streams():
        F_mass_waste = waste.F_mass
        caustic.mol[:] = F_mass_waste * caustic_over_waste
        air.mol[:] = F_mass_waste * air_over_waste

    R602 = units.AerobicDigestionWWT('R602',
                                     ins=(waste, air, caustic),
                                     outs=('evaporated_water', ''),
                                     reactions=aerobic_digestion)

    splits = [('Ethanol', 0, 1), ('Water', 381300, 2241169), ('Glucose', 0, 2),
              ('Xylose', 1, 3), ('OtherSugars', 1, 7),
              ('SugarOligomers', 1, 6), ('OrganicSolubleSolids', 79, 466),
              ('InorganicSolubleSolids', 4828, 28378), ('Ammonia', 3, 16),
              ('Furfurals', 0, 3), ('OtherOrganics', 1, 7),
              ('CarbonDioxide', 6, 38), ('O2', 3, 17), ('N2', 5, 32),
              ('Cellulose', 0, 194), ('Xylan', 0, 65),
              ('OtherStructuralCarbohydrates', 0, 15), ('Lignin', 0, 1925),
              ('Protein', 0, 90), ('CellMass', 0, 19778),
              ('OtherInsolubleSolids', 0, 707)]

    S601 = bst.Splitter('S601', ins=R602 - 1, split=find_split(*zip(*splits)))

    S602 = bst.Splitter('S602', ins=S601 - 1, split=0.96)

    M603 = bst.Mixer('M603', ins=(S602 - 0, None))
    M603 - 0 - 1 - M602

    M604 = bst.Mixer('M604', ins=(R601 - 2, S602 - 1))

    centrifuge_species = ('Water', 'Glucose', 'Xylose', 'OtherSugars',
                          'SugarOligomers', 'OrganicSolubleSolids',
                          'InorganicSolubleSolids', 'Ammonia', 'Furfurals',
                          'OtherOrganics', 'CO2', 'COxSOxNOxH2S', 'Cellulose',
                          'Xylan', 'OtherStructuralCarbohydrates', 'Lignin',
                          'Protein', 'CellMass', 'OtherInsolubleSolids')
    S623_flow = np.array(
        [7708, 0, 0, 1, 1, 13, 75, 3, 0, 1, 1, 2, 25, 8, 2, 250, 52, 1523, 92])
    S616_flow = np.array([
        109098, 3, 6, 13, 9, 187, 1068, 46, 5, 8, 14, 31, 1, 0, 0, 13, 3, 80, 5
    ])

    S603 = bst.Splitter('S603',
                        ins=M604 - 0,
                        outs=('', 'sludge'),
                        split=find_split(centrifuge_species, S616_flow,
                                         S623_flow))
    S603 - 0 - 1 - M603

    S604 = bst.Splitter('S604',
                        ins=S601 - 0,
                        outs=('treated_water', 'waste_brine'),
                        split={'Water': 0.987})

    aerobic_recycle_sys = System('aerobic_recycle_sys',
                                 path=(M602, update_aerobic_input_streams,
                                       R602, S601, S602, M604, S603, M603),
                                 recycle=M602 - 0)
    WWT_sys = System('WWT_sys', path=(WWTC, R601, aerobic_recycle_sys, S604))

    ### Facilities

    # %% Facilities

    # TODO: Double check that I did is right.
    # TODO: The BoilerTurbogenerator burns both biogas and lignin
    # Note that lime and boilerchems cost is taking into account in the
    # unit operation now
    #    M605 = bst.Mixer('M605', ins=(R501-0, R601-0))
    BT = bst.facilities.BoilerTurbogenerator(
        'BT',
        ins=(S402 - 0, '', 'boiler_makeup_water', 'natural_gas', 'lime',
             'boilerchems'),
        turbogenerator_efficiency=0.85)

    # tmo.Stream.default_ID_number = 700

    CWP = bst.facilities.ChilledWaterPackage('CWP')
    CT = bst.facilities.CoolingTower('CT')
    CT.outs[1].T = 273.15 + 28
    water_thermo = tmo.Thermo(tmo.Chemicals(['Water']))
    process_water = tmo.Stream(ID='process_water', thermo=water_thermo)

    process_water_streams = (caustic, stripping_water, process_water1,
                             process_water2, steam, BT - 1, CT - 1)

    def update_water_loss():
        process_water.imol['Water'] = sum(
            [i.imol['Water'] for i in process_water_streams])

    makeup_water = Stream('makeup_water',
                          thermo=water_thermo,
                          price=price['Makeup water'])

    PWC = bst.facilities.ProcessWaterCenter(
        'PWC',
        ins=(S604 - 0, makeup_water),
        outs=(process_water, ''),
        makeup_water_streams=(makeup_water, ),
        process_water_streams=process_water_streams)

    Substance = tmo.Chemical.blank('Substance')
    Substance.at_state(phase='l')
    Substance.default()
    substance_thermo = tmo.Thermo(tmo.Chemicals([Substance]))

    CIP = Stream('CIP',
                 thermo=substance_thermo,
                 flow=(126 / 83333 * dryflow, ))
    CIP_package = units.CIPpackage('CIP_package',
                                   ins=CIP,
                                   thermo=substance_thermo)

    plant_air = Stream('plant_air',
                       flow=(83333 / 83333 * dryflow, ),
                       thermo=substance_thermo)

    ADP = bst.facilities.AirDistributionPackage('ADP',
                                                ins=plant_air,
                                                thermo=substance_thermo)

    FT = units.FireWaterTank('FT',
                             ins=Stream('fire_water',
                                        flow=(8343 / 83333 * dryflow, ),
                                        thermo=substance_thermo),
                             thermo=substance_thermo)

    ### Complete system
    wheatstraw_sys = System('wheatstraw_sys',
                            path=(pretreatment_sys, fermentation_sys,
                                  ammonia_storage, S301, purification_sys,
                                  digestor_sys, WWT_sys),
                            facilities=(CWP, BT, CT, update_water_loss, PWC,
                                        ADP, CIP_package, S301,
                                        ammonia_storage, FT))

    return wheatstraw_sys
コード例 #13
0
def create_chemicals():
    ### Define common chemicals ###

    Biodiesel = tmo.Chemical('Biodiesel', search_ID='Methyl oleate')
    lipidcane_chemicals = tmo.Chemicals([
        'Water', 'Methanol', 'Ethanol', 'Glycerol', 'Glucose', 'Sucrose',
        'H3PO4', 'P4O10', 'CO2', 'Octane', 'O2', Biodiesel, 'CH4'
    ])

    (Water, Methanol, Ethanol, Glycerol, Glucose, Sucrose, H3PO4, P4O10, CO2,
     Octane, O2, Biodiesel, CH4) = lipidcane_chemicals

    O2.at_state(phase='g')
    CH4.at_state(phase='g')
    CO2.at_state(phase='g')
    H3PO4.at_state(phase='s')
    P4O10.at_state(phase='s')
    Glucose.at_state(phase='s')
    Sucrose.at_state(phase='s')

    ### Define new chemicals ###

    def create_new_chemical(ID, phase='s', **constants):
        solid = tmo.Chemical.blank(ID, phase=phase, **constants)
        lipidcane_chemicals.append(solid)
        return solid

    Ash = create_new_chemical('Ash', MW=1.)
    Cellulose = create_new_chemical(
        'Cellulose',
        formula="C6H10O5",  # Glucose monomer minus water
        Hf=-975708.8)
    Hemicellulose = create_new_chemical(
        'Hemicellulose',
        formula="C5H8O5",  # Xylose monomer minus water
        Hf=-761906.4)
    Flocculant = create_new_chemical('Flocculant', MW=1.)
    Lignin = create_new_chemical(
        'Lignin',
        formula='C8H8O3',  # Vainillin
        Hf=-452909.632)
    Solids = create_new_chemical('Solids', MW=1.)
    DryYeast = create_new_chemical('DryYeast', MW=1., CAS='Yeast')
    CaO = create_new_chemical('CaO', formula='CaO')
    HCl = create_new_chemical('HCl', formula='HCl')
    NaOH = create_new_chemical('NaOH', formula='NaOH')
    NaOCH3 = create_new_chemical('NaOCH3', formula='NaOCH3')

    Lipid = create_new_chemical('Lipid',
                                phase='l',
                                formula='C57H104O6',
                                Hf=-2193.7e3)
    Lipid.Dortmund.set_group_counts_by_name({
        'CH3': 3,
        'CH2': 41,
        'CH': 1,
        'CH=CH': 3,
        'CH2COO': 3
    })

    ### Fill missing properties ###

    # Assume properties are similar for trioleate and tripalmitin
    Tripalmitin = tmo.Chemical('Tripalmitin').at_state(phase='l', copy=True)
    Lipid.copy_models_from(Tripalmitin, ['V', 'sigma', 'kappa', 'Cn'])

    # Assume a constant volume for lipid
    lipid_molar_volume = fn.rho_to_V(rho=900, MW=Lipid.MW)
    Lipid.V.add_model(lipid_molar_volume)

    # Insolubles occupy a significant volume
    insoluble_solids = (Ash, Cellulose, Hemicellulose, Flocculant, Lignin,
                        Solids, DryYeast, P4O10)

    # Solubles don't occupy much volume
    soluble_solids = (CaO, HCl, NaOH, H3PO4, Glucose, Sucrose)

    for chemical in insoluble_solids:
        V = fn.rho_to_V(rho=1540, MW=chemical.MW)
        chemical.V.add_model(V, top_priority=True)

    for chemical in soluble_solids:
        V = fn.rho_to_V(rho=1e5, MW=chemical.MW)
        chemical.V.add_model(V, top_priority=True)

    # Assume sodium methoxide has some of the same properities as methanol
    LiquidMethanol = Methanol.at_state(phase='l', copy=True)
    NaOCH3.copy_models_from(LiquidMethanol, ['V', 'sigma', 'kappa', 'Cn'])

    # Add constant models for molar heat capacity of solids
    Ash.Cn.add_model(0.09 * 4.184 * Ash.MW)
    CaO.Cn.add_model(1.02388 * CaO.MW)
    Cellulose.Cn.add_model(1.364 * Cellulose.MW)
    Hemicellulose.Cn.add_model(1.364 * Hemicellulose.MW)
    Flocculant.Cn.add_model(4.184 * Flocculant.MW)
    Lignin.Cn.add_model(1.364 * Lignin.MW)
    Solids.Cn.add_model(1.100 * Solids.MW)

    for chemical in lipidcane_chemicals:
        chemical.default()

    lipidcane_chemicals.compile()
    lipidcane_chemicals.set_synonym('Water', 'H2O')
    return lipidcane_chemicals
コード例 #14
0
def create_ethanol_subsystem_example():
    """
    Test BioSTEAM by creating a conventional sugarcane fermentation and ethanol
    purification process.
    
    Examples
    --------
    >>> ethanol_sys = create_ethanol_subsystem_example()
    >>> # The sugarcane_example_subsystem flowsheet may help for accessing units
    >>> from biosteam import main_flowsheet as F
    >>> fs = F.flowsheet['ethanol_subsystem_example']
    >>> fs.unit # Check unit operation registry
    Register:
     <Fermentation: R301>
     <StorageTank: T301>
     <VentScrubber: D301>
     <SolidsCentrifuge: C301>
     <Mixer: M302>
     <Pump: P301>
     <HXprocess: H302>
     <BinaryDistillation: D302>
     <Pump: P302>
     <Mixer: M303>
     <BinaryDistillation: D303>
     <Pump: P303>
     <HXutility: H303>
     <MolecularSieve: U301>
    >>> R301 = fs.unit.R301 # Get unit operation

    """
    original_flowsheet = main_flowsheet.get_flowsheet()
    main_flowsheet.set_flowsheet('ethanol_subsystem_example')
    
    ### Create property package ###
    
    chemicals = tmo.Chemicals(
        ['Water', 'Ethanol', 'Glucose',
         'Sucrose', 'H3PO4', 'P4O10',
         'CO2', 'Octane', 'O2']
    )
    
    Water, Ethanol, Glucose, Sucrose, H3PO4, P4O10, CO2, Octane, O2 = chemicals
    
    CO2.at_state(phase='g')
    H3PO4.at_state(phase='s')
    P4O10.at_state(phase='s')
    Glucose.at_state(phase='s')
    Sucrose.at_state(phase='s')
    
    DryYeast = tmo.Chemical('DryYeast', MW=1., phase='s',
                            search_db=False, default=True, CAS='Yeast')
    chemicals.append(DryYeast)
    
    Ash = tmo.Chemical('Ash', MW=1., search_db=False, phase='s', default=True)
    chemicals.append(Ash)
    
    # Insolubles occupy a significant volume
    insoluble_solids = (Ash, DryYeast)
    
    # Solubles don't occupy much volume
    soluble_solids = (H3PO4, Glucose, Sucrose) 
    
    for chemical in insoluble_solids:
        V = fn.rho_to_V(rho=1540, MW=chemical.MW)
        chemical.V.add_model(V, top_priority=True)
    
    for chemical in soluble_solids:
        V = fn.rho_to_V(rho=1e5, MW=chemical.MW)
        chemical.V.add_model(V, top_priority=True)
    
    # Add constant models for molar heat capacity of solids
    Ash.Cn.add_model(0.09 * 4.184 * Ash.MW) 
    for chemical in chemicals: chemical.default()
    bst.settings.set_thermo(chemicals)
    chemicals.set_synonym('Water', 'H2O')
    
    ### Create fresh streams ###
    
    # Fresh water
    stripping_water = bst.Stream('stripping_water', Water=5000, units='kg/hr')
    fermentation_feed = bst.Stream('fermentation_feed', phase='l',
                                Glucose=21.11,
                                Sucrose=125.9,
                                Water=1370 + 4409,
                                H3PO4=0.7575,
                                DryYeast=1.03e+04)
    
    # Ethanol Production
    R301 = units.Fermentation('R301', outs=('CO2', ''), tau=9, efficiency=0.90, N=4) 
    T301 = units.StorageTank('T301', tau=4, vessel_material='Carbon steel')
    T301.line = 'Beer tank'
    
    D301 = units.VentScrubber('D301', ins=(stripping_water, R301-0), gas=('CO2',))
    
    # Separate 99% of yeast
    C301 = units.SolidsCentrifuge('C301', outs=('recycle_yeast', ''),
                                split=(1, 0.99999, 1, 0.96, 0.01),
                                order=('Ethanol', 'Glucose', 'H3PO4', 
                                       'Water', 'DryYeast'),
                                solids=('DryYeast',))
    C301.split[:] = 1. - C301.split
    # Mix in Water
    M302 = units.Mixer('M302')
    P301 = units.Pump('P301')
    
    # Heat up before beer column
    # Exchange heat with stillage
    H302 = units.HXprocess('H302', outs=('', 'stillage'),
                          phase0='l', phase1='l', U=1.28)
    
    # Beer column
    x_bot = 3.910570816782338e-06
    y_top = 0.34508430224337167
    D302 = units.BinaryDistillation('D302', P=101325,
                                y_top=y_top, x_bot=x_bot, k=1.25,
                                LHK=('Ethanol', 'Water'))
    D302.tray_material = 'Stainless steel 304'
    D302.vessel_material = 'Stainless steel 304'
    D302.boiler.U = 1.85
    P302 = units.Pump('P302')
    
    # Mix ethanol Recycle (Set-up)
    M303 = units.Mixer('M303')
    x_bot = 3.910570816782338e-06
    y_top = 0.7906528373264998
    D303 = units.BinaryDistillation('D303', P=101325,
                                y_top=y_top, x_bot=x_bot, k=1.25,
                                LHK=('Ethanol', 'Water'),
                                tray_material='Stainless steel 304',
                                vessel_material='Stainless steel 304',
                                is_divided=True)
    D303.boiler.U = 1.85
    P303 = units.Pump('P303')
    
    # Superheat vapor for mol sieve
    H303 = units.HXutility('H303', T=115+273.15, V=1)
    
    # Molecular sieve
    U301 = units.MolecularSieve('U301',
                                split=(2165.14/13356.04, 1280.06/1383.85),
                                order=('Ethanol', 'Water'))
    
    fermentation_feed-R301-1-T301-0-C301
    (C301-1, D301-1)-M302-P301
    (P301-0, P302-0)-H302-0-D302-1-P302
    (D302-0, U301-0)-M303-0-D303-0-H303-U301
    D303-1-P303
    
    ethanol_subsystem_example = main_flowsheet.create_system('ethanol_subsystem_example')
    ethanol_subsystem_example.simulate()
    main_flowsheet.set_flowsheet(original_flowsheet) 
    return ethanol_subsystem_example