Source code for biorefineries.cellulosic.chemicals

# -*- coding: utf-8 -*-
"""
.. contents:: :local:

Chemicals
---------
.. autofunction:: biorefineries.cellulosic.chemicals.create_cellulosic_ethanol_chemicals
    
Utilities
---------
.. autofunction:: biorefineries.cellulosic.chemicals.get_grouped_chemicals
    
Data
----
.. autodata:: biorefineries.cellulosic.chemicals.chemical_groups
   :annotation:
.. autodata:: biorefineries.cellulosic.chemicals.default_nonsolids
.. autodata:: biorefineries.cellulosic.chemicals.default_insoluble_solids
.. autodata:: biorefineries.cellulosic.chemicals.default_ignored

"""
import thermosteam as tmo
from thermosteam.utils import chemical_cache
from thermosteam import functional as fn
import pandas as pd

__all__ = (
    'create_cellulosic_ethanol_chemicals', 
    'get_grouped_chemicals', 
    'chemical_groups',
    'default_nonsolids',
    'default_insoluble_solids',
    'default_ignored',
)

# %% Constants

# Common structural carbohydrates properties.

# Lignocellulosic heat capacities:
# Assume heat capacity of lignin, cellulose, and hemicellulose
# and all components at 350 K are about the same.
# https://link.springer.com/article/10.1007/s10853-013-7815-6
# https://www.sciencedirect.com/science/article/pii/0032386182901252
Cp_cellulosic = 1.364

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

cal2joule = 4.184

# These defaults are used within system factories for pretreatment and fermentation.

#: Default liquid chemicals for saccharification solids-loading specification
default_nonsolids = ['Water', 'Ethanol', 'AceticAcid', 
                     'Furfural', 'H2SO4', 'NH3', 'HMF']

#: Default insolible chemicals for saccharification solids-loading specification
default_insoluble_solids = ['Glucan', 'Mannan', 'Xylan', 
                            'Arabinan', 'Galactan', 'Lignin']

#: Default ignored chemicals for saccharification solids-loading specification
default_ignored = ['TAG', 'DAG', 'MAG', 'FFA', 'PL']

#: Chemical groups for `get_grouped_chemicals` function
chemical_groups = dict(
        OtherSugars = ('Arabinose',
                       'Mannose',
                       'Galactose',
                       'Cellobiose',
                       'Sucrose'),
        SugarOligomers = ('GlucoseOligomer',
                          'XyloseOligomer',
                          'GalactoseOligomer',
                          'ArabinoseOligomer',
                          'MannoseOligomer'),
        OrganicSolubleSolids = ('AmmoniumAcetate',
                                'SolubleLignin',
                                'Extract', 
                                'LacticAcid', 
                                'Cellulase'),
        InorganicSolubleSolids = ('AmmoniumSulfate',
                                  'DAP',
                                  'NaOH',
                                  'HNO3',
                                  'NaNO3'),
        Furfurals = ('Furfural',
                     'HMF'),
        OtherOrganics = ('Glycerol',
                         'Denaturant',
                         'Oil',
                         'SuccinicAcid',
                         'Xylitol'),
        COxSOxNOxH2S = ('NO',
                        'NO2',
                        'SO2',
                        'CO',
                        'H2S'),
        Protein = ('Protein',
                   'Enzyme',
                   'DenaturedEnzyme'),
        CellMass = ('WWTsludge',
                    'Z_mobilis',
                    'T_reesei'),
        OtherInsolubleSolids = ('Tar',
                                'Ash',
                                'Lime'),
        OtherStructuralCarbohydrates = ('Arabinan', 
                                        'Mannan', 
                                        'Galactan')
)

[docs] def get_grouped_chemicals(stream, units='kmol/hr'): new_stream = tmo.Stream(stream.thermo) new_stream.set_flow(stream.mol, units, stream.chemicals.IDs) data = {group: new_stream.get_flow(units, IDs).sum() for group, IDs in chemical_groups.items()} return pd.Series(data)
# %% Chemicals object and define functions @chemical_cache def create_cellulosic_ethanol_chemicals(): from biorefineries import cane chems = tmo.Chemicals([]) oilcane_chemicals = cane.create_oilcane_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, Cp=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) if Cp is not None: set_Cp(chemical, Cp) 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([oilcane_chemicals.Water, oilcane_chemicals.Ethanol, 'AceticAcid', 'Furfural', oilcane_chemicals.Glycerol, 'H2SO4', 'NH3', 'LacticAcid', 'SuccinicAcid', oilcane_chemicals.P4O10]) ) chems.H2SO4.at_state('l') append_single_phase_chemical('Lime', 'Ca(OH)2') append_single_phase_chemical('HNO3', 'NitricAcid') append_single_phase_chemical('NH4OH') 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', 'Hydroxymethylfurfural', phase='l') chems.HMF.Hf = -99677 * cal2joule chems.AmmoniumAcetate.Hf = -154701 * cal2joule # Will remain in the vapor phase extend_single_phase_chemicals(['N2', '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 chems.extend([ oilcane_chemicals.Glucose, tmo.Chemical('Xylose', phase='l', Hf=cal2joule*-249440), oilcane_chemicals.Sucrose, ]) append_single_phase_chemical('CaSO4') # 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) # Chemicals taken from previous study chems.append(oilcane_chemicals.Ash) chems.append(oilcane_chemicals.NaOH) append_new_single_phase_chemical('Lignin', formula='C8H8O3', phase='s', Hf=-108248*cal2joule) set_rho(chems.Lignin, 1540) set_Cp(chems.Lignin, Cp_cellulosic) append_new_single_phase_chemical('SolubleLignin', formula='C8H8O3', phase='l', Hf=-108248*cal2joule) # Create structural carbohydrates append_chemical_copy('GlucoseOligomer', chems.Glucose) set_Cp(chems.GlucoseOligomer, Cp_cellulosic) chems.GlucoseOligomer.Hf = -233200*cal2joule chems.GlucoseOligomer.formula = "C6H10O5" 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.Hf = -182100*cal2joule chems.XyloseOligomer.formula = "C5H8O4" 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 Cp=Cp_cellulosic, 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', Cp=Cp_cellulosic, Hf=-233200*cal2joule, phase='s') append_new_single_phase_chemical('Xylan', formula="C5H8O4", Cp=Cp_cellulosic, Hf=-182100*cal2joule, phase='s') append_new_single_phase_chemical('Xylitol', formula="C5H12O5", Cp=Cp_cellulosic, Hf=-243145*cal2joule) append_new_single_phase_chemical('Cellobiose', formula="C12H22O11", Cp=Cp_cellulosic, Hf=-480900*cal2joule) append_new_single_phase_chemical('CSL', formula='H2.8925O1.3275C1N0.0725S0.00175', 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) # New feature in Thermosteam allows salt and solutes to be accounted # for in VLE; leading to more accurate results. However, it is not included # here as there is no significant difference in results. # for i in chems['Glucose', 'Xylose']: # i.N_solutes = 1 # for i in chems['Sucrose', 'CaSO4', 'AmmoniumSulfate']: # i.N_solutes = 2 chems.compile() chems.set_synonym('Lime', 'Ca(OH)2') chems.set_synonym('Water', 'H2O') chems.set_synonym('H2SO4', 'SulfuricAcid') chems.set_synonym('NH3', 'Ammonia') chems.set_synonym('AmmoniumSulfate', '(NH4)2SO4') chems.set_synonym('Denaturant', 'Octane') chems.set_synonym('CO2', 'CarbonDioxide') return chems