Ejemplo n.º 1
0
 def diagram(self, radius=0, upstream=True, downstream=True, 
             file=None, format='png', **graph_attrs):
     """
     Display a `Graphviz <https://pypi.org/project/graphviz/>`__ diagram
     of the unit and all neighboring units within given radius.
     
     Parameters
     ----------
     radius : int
              Maxium number streams between neighbors.
     downstream=True : bool, optional
         Whether to show downstream operations
     upstream=True : bool, optional
         Whether to show upstream operations
     file : Must be one of the following:
         * [str] File name to save diagram.
         * [None] Display diagram in console.
     format : str
              Format of file.
     
     """
     if radius > 0:
         neighborhood = self._neighborhood(radius, upstream, downstream)
         neighborhood.add(self)
         sys = bst.System('', neighborhood)
         return sys.diagram('thorough', file, format, **graph_attrs)
     f = self.get_digraph(format, **graph_attrs)
     finalize_digraph(f, file, format)
def system():
    bst.main_flowsheet.clear()
    MockChemical = bst.Chemical('MockChemical', phase='l', search_db=False, default=True)
    bst.settings.set_thermo([MockChemical])
    with bst.System('MockSystem') as system:
        feed = bst.Stream('feed', MockChemical=1e6, units='kg/hr', price=0.150)
        product = bst.Stream('product', price=0.151)
        M1 = bst.MixTank('M1', feed, 's1')
        H1 = bst.HXutility('H1', M1-0, product, T=325, V=0.)
    system.simulate()
    return system
Ejemplo n.º 3
0
 def build_network(self):
     units = self.path + [self.sink]
     network = []
     for segment in units:
         if isinstance(segment, list):
             source = segment[0]
             for recycle in segment[-1].outs:
                 if recycle.sink is source: break
             system = bst.System(segment, recycle=recycle)
             network.append(system)
         else:
             network.append(segment)
     return network
Ejemplo n.º 4
0
def test_kolmogorov_smirnov_d(model):
    # Test made by Yalin.
    import numpy as np
    import biosteam as bst
    from chaospy import distributions as shape

    bst.settings.set_thermo(['H2O', 'Ethanol'], cache=True)

    s1 = bst.Stream('s1', H2O=100)
    M1 = bst.MixTank(ins=s1)
    M2 = bst.MixTank(ins=M1 - 0)
    sys = bst.System('sys', path=(M1, M2))

    model = bst.Model(sys)

    baseline = 1
    distribution = shape.Uniform(lower=0.5, upper=1.5)

    @model.parameter(name='M1 tau',
                     element=M1,
                     kind='coupled',
                     distribution=distribution,
                     units='hr',
                     baseline=baseline)
    def set_M1_tau(i):
        M1.tau = i

    baseline = 1.75
    distribution = shape.Uniform(lower=1, upper=2)

    @model.parameter(name='M2 tau',
                     element=M2,
                     kind='coupled',
                     distribution=distribution,
                     units='hr',
                     baseline=baseline)
    def set_M2_tau(i):
        M2.tau = i

    model.metrics = [
        bst.Metric(name='tau1', getter=lambda: M1.tau, units='hr', element=M1),
        bst.Metric(name='tau2', getter=lambda: M2.tau, units='hr', element=M2),
    ]

    np.random.seed(3221)
    samples = model.sample(100, rule='L')
    model.load_samples(samples)
    model.evaluate()

    D, p = model.kolmogorov_smirnov_d(
        thresholds=[1, 1.5])  # Just make sure it works for now
Ejemplo n.º 5
0
def test_parameter_hook():
    import biosteam as bst
    from chaospy.distributions import Uniform
    sys = bst.System(None, ())
    model = bst.Model(sys)

    @model.parameter(distribution=Uniform(0., 1.), hook=round)
    def set_param(x):
        pass

    np.random.seed(0)
    samples = model.sample(10, 'L')
    model.load_samples(samples)
    actual_values = [[1.], [0.], [0.], [0.], [0.], [0.], [1.], [1.], [1.],
                     [1.]]
    assert_allclose(model.table.values, actual_values)
Ejemplo n.º 6
0
def create_tea(sys, OSBL_units, ignored_units=()):
    BT = tmo.utils.get_instance(OSBL_units,
                                bst.facilities.BoilerTurbogenerator)
    OSBL_units = list(OSBL_units)
    OSBL_units.remove(BT)
    ethanol_tea = CellulosicEthanolTEA(
        system=sys,
        IRR=0.10,
        duration=(2007, 2037),
        depreciation='MACRS7',
        income_tax=0.35,
        operating_days=350.4,
        lang_factor=None,
        construction_schedule=(0.08, 0.60, 0.32),
        startup_months=3,
        startup_FOCfrac=1,
        startup_salesfrac=0.5,
        startup_VOCfrac=0.75,
        WC_over_FCI=0.05,
        finance_interest=0.08,
        finance_years=10,
        finance_fraction=0.4,
        OSBL_units=OSBL_units,  # BT not included
        warehouse=0.04,
        site_development=0.09,
        additional_piping=0.045,
        proratable_costs=0.10,
        field_expenses=0.10,
        construction=0.20,
        contingency=0.10,
        other_indirect_costs=0.10,
        labor_cost=2.5e6,
        labor_burden=0.90,
        property_insurance=0.007,
        maintenance=0.03)
    for i in ignored_units:
        ethanol_tea.units.remove(i)
    ethanol_tea.units.remove(BT)
    Area700 = bst.TEA.like(bst.System('Area700', (BT, )), ethanol_tea)
    Area700.labor_cost = 0
    Area700.depreciation = 'MACRS20'
    Area700.OSBL_units = (BT, )
    tea = bst.CombinedTEA([ethanol_tea, Area700], IRR=0.10)
    sys._TEA = tea
    return tea
Ejemplo n.º 7
0
def test_sanunit():
    import biosteam as bst
    from qsdsan import Components, WasteStream, sanunits
    components = Components.load_default()
    bst.settings.set_thermo(components)
    ws1 = WasteStream(S_Ac=5, H2O=1000, units='kg/hr')
    ws2 = WasteStream(X_NOO=10, H2O=1000, units='kg/hr')
    M1 = sanunits.Mixer('M1', ins=(ws1, ws2, ''), outs='mixture')
    M1.show()
    assert type(M1.ins[0]).__name__ == 'WasteStream'
    
    S1 = sanunits.Splitter('S1', ins=M1-0, outs=('', ''), split=0.2)
    ins3 = WasteStream(S_CH3OH=7, H2O=1000, units='kg/hr')
    P1 = sanunits.Pump('P1', ins=ins3)    
    M2 = sanunits.MixTank('M2', ins=(S1-0, P1-0), tau=2)
    M2-0-2-M1
    System = bst.System('System', path=(M1, S1, P1, M2), recycle=M2-0)
    System.simulate()
    assert_allclose(M2.installed_cost, 65519.00446342958, rtol=1e-3)
Ejemplo n.º 8
0
def create_evaluation_model():
    import biosteam as bst
    from chaospy.distributions import Uniform
    sys = bst.System(None, ())
    model = bst.Model(sys)

    parameter_box = [100.]

    @model.parameter(bounds=[90, 110],
                     distribution=Uniform(90, 110),
                     units='kg/hr')
    def set_parameter(parameter_1):
        parameter_box[0] = parameter_1

    @model.parameter(bounds=[0., 1.], distribution=Uniform(0., 1.))
    def set_parameter(parameter_2):
        ...

    @model.metric
    def good_metric():
        p = parameter_box[0]
        return 2. * p * p / (p + 100.)

    switch_box = [False]

    @model.metric
    def bad_metric():
        give_nan = switch_box[0]
        switch_box[0] = not give_nan
        p = parameter_box[0]
        return float('Nan') if give_nan else 2. * p * p / (p + 100.)

    @model.metric
    def non_correlated_metric():
        return float(switch_box[0])

    sample = model.sample(1000, 'L')
    model.load_samples(sample)
    model.evaluate()
    return model
Ejemplo n.º 9
0
 def __call__(self, ID=None, ins=None, outs=None, mockup=False, area=None, udct=None, 
              operating_hours=None, **kwargs):
     ins = create_streams(self.ins, ins, 'inlets', self.fixed_ins_size)
     outs = create_streams(self.outs, outs, 'outlets', self.fixed_outs_size)
     rename = area is not None
     with (bst.MockSystem() if mockup else bst.System(ID or self.ID, operating_hours=operating_hours)) as system:
         if rename: 
             unit_registry = system.flowsheet.unit
             irrelevant_units = system._irrelevant_units
             unit_registry.untrack(irrelevant_units)
         self.f(ins, outs, **kwargs)
     system.load_inlet_ports(ins, optional=[ins[i] for i in self.optional_ins_index])
     system.load_outlet_ports(outs, optional=[outs[i] for i in self.optional_outs_index])
     if rename: 
         units = system.units
         if udct: unit_dct = {i.ID: i for i in units}
         unit_registry.track(irrelevant_units)
         utils.rename_units(units, area)
         if udct: return system, unit_dct
     elif udct:
         unit_dct = {i.ID: i for i in system.units}
         return system, unit_dct
     return system
Ejemplo n.º 10
0
def create_fattyalcohol_production_sys(
        ID='fattyalcohol_production_sys',
        fa_stoichiometry='Glucose -> 1.5 Hexanol + 1.5 Octanol + 4.5 Decanol + H2O + CO2',
        yg_stoichiometry='Glucose ->  3.72 Cells + 2 CO2'):

    chemicals = tmo.settings.get_chemicals()

    ### Reactions ###

    fatty_alcohol_production = Rxn(fa_stoichiometry,
                                   'Glucose',
                                   0.5,
                                   basis='wt')
    fatty_alcohol_production.basis = 'mol'
    fatty_alcohol_production.correct_atomic_balance(constants=[
        'Hexanol', 'Octanol', 'Decanol', 'Dodecanol', 'Tetradecanol'
    ])
    yeast_growth = Rxn(yg_stoichiometry,
                       'Glucose',
                       .999,
                       correct_mass_balance=True)

    ### Streams ###
    filepath = os.path.dirname(__file__)
    stream_data_path = os.path.join(filepath, 'streams.yaml')
    stream_data = tmo.ThermoData.from_yaml(stream_data_path)
    glucose, process_water, tridecane, CSL, DAP, salt, \
    cell_recycle, mixed_bioreactor_feed = stream_data.create_streams(
        ['glucose', 'process_water', 'tridecane', 'CSL', 'DAP',
         'salt', 'cell_recycle', 'mixed_bioreactor_feed']
    )
    process_water.T = 310.15  # Assume heat integration so that this stream comes in heated

    ### Unit operations ###

    M101 = units.Mixer('M101', ins=(tridecane, 'solvent_recycle'))
    M101.ins[
        1].T = 310.15  # Assume heat integration so that this stream comes in heated

    one_week = 7 * 24
    T101 = units.StorageTank('T101', glucose, tau=one_week)
    T102 = units.StorageTank('T102', M101 - 0, tau=0.25)
    P102 = units.Pump('P102', T102 - 0)
    T103 = fa_units.CSLTank('T103', CSL)
    T104 = units.StorageTank('T104', salt, tau=one_week)
    T106 = fa_units.DAPTank('T106', DAP)

    def balance_feeds_to_bioreactor():
        feed_imol = mixed_bioreactor_feed.imol
        glucose.imol['Glucose'] = feed_imol['Glucose']
        process_water.imol[
            'Water'] = feed_imol['Water'] - M101.ins[1].imol['Water']
        tridecane.imol['Tridecane'] = feed_imol['Tridecane'] - M101.ins[
            1].imol['Tridecane']
        salt.imol['NaCl'] = feed_imol['NaCl']
        cell_recycle.imol['Cells'] = feed_imol['Cells']
        CSL.imol['CSL'] = feed_imol['CSL']
        DAP.imol['DAP'] = feed_imol['DAP']
        M101._run()

    M101.specification = balance_feeds_to_bioreactor
    M102 = units.Mixer('M102',
                       ins=(T101 - 0, P102 - 0, T103 - 0, T104 - 0, T106 - 0,
                            process_water, cell_recycle))
    H101 = units.HXutility('H101',
                           ins=M102 - 0,
                           outs=mixed_bioreactor_feed,
                           material='Stainless steel/stainless steel',
                           T=310.15,
                           V=0)

    def make_sure_enough_CSL_and_DAP_are_fed():
        # tmo.reaction.CHECK_FEASIBILITY = False
        feed = R101.ins[0]
        CSL.imass['CSL'] = feed.imass['CSL'] = 0.0025 * feed.F_mass
        DAP.imass['DAP'] = feed.imass['DAP'] = 0.33 * feed.F_vol
        R101._run()
        # effluent = R101.outs[1]
        # if effluent.imol['CSL'] < 0. or effluent.imol['DAP'] < 0.:
        #     CSL.imol['CSL'] = feed.imol['CSL'] = CSL_flow - effluent.imol['CSL']
        #     DAP.imol['DAP'] = feed.imol['DAP'] = DAP_flow - effluent.imol['DAP']
        #     effluent.imol['CSL'] = effluent.imol['DAP'] = 0.
        # tmo.reaction.CHECK_FEASIBILITY = True

    R101 = fa_units.FattyAlcoholBioreactor(
        'R101',
        outs=('CO2', ''),
        ins=H101 - 0,
        fermentation_reaction=fatty_alcohol_production,
        postfermentation_reaction=yeast_growth,
        T=310.15,
        tau=32,
        V=3785,
        Nmin=2,
        Nmax=32)
    R101.specification = make_sure_enough_CSL_and_DAP_are_fed
    T105 = units.StorageTank('T105', ins=R101 - 1, tau=2)
    solids_split = chemicals.kwarray({'Cells': 0.999})
    solids_split[solids_split == 0] = 0.001
    solids_split[chemicals.index('Water')] = 0
    P104 = units.Pump('P104', ins=T105 - 0)
    C101 = fa_units.SolidLiquidsSplitCentrifuge(
        'C101',
        ins=P104 - 0,
        outs=('', 'aqueous_fraction', 'cell_mass'),
        solids_split=solids_split,
        liquids_split=dict(Water=0.0004,
                           Tridecane=0.9966,
                           Hexanol=0.6781,
                           Octanol=0.9608,
                           Decanol=0.9966,
                           Dodecanol=0.9999,
                           Tetradecanol=1.0),
        moisture_content=0.45)
    P107 = units.Pump('P107', C101 - 0, 'oil_fraction', P=5 * 101325)

    ### System ###

    return bst.System(ID, (M101, T102, P102, T101, T104, T103, T106, M102,
                           H101, R101, T105, P104, C101, P107))
Ejemplo n.º 11
0
    def diagram(self, radius=0, file=None, format='png'):
        """Display a `Graphviz <https://pypi.org/project/graphviz/>`__ diagram of the unit and all neighboring units within given radius.
        
        **Parameters**
        
            **radius:** [int] Maxium number streams between neighbors.
        
            **file:** Must be one of the following:
                * [str] File name to save diagram.
                * [None] Display diagram in console.
        
            **format:** Format of file.
        
        """
        if radius > 0:
            neighborhood = self._neighborhood(radius)
            neighborhood.add(self)
            sys = bst.System('', neighborhood)
            return sys.diagram('thorough', file, format)

        graphics = self._graphics

        # Make a Digraph handle
        f = Digraph(name='unit', filename='unit', format='svg')
        f.attr('graph',
               ratio='0.5',
               splines='normal',
               outputorder='edgesfirst',
               nodesep='1.1',
               ranksep='0.8',
               maxiter='1000')  # Specifications
        f.attr(rankdir='LR')  # Left to right

        # If many streams, keep streams close
        if (len(self.ins) >= 3) or (len(self.outs) >= 3):
            f.attr('graph', nodesep='0.4')

        # Initialize node arguments based on unit and make node
        type_ = graphics.node_function(self) or self.line
        name = self.ID + '\n' + type_
        f.attr('node', **self._graphics.node)
        f.node(name)

        # Set stream node attributes
        f.attr('node',
               shape='rarrow',
               fillcolor='#79dae8',
               style='filled',
               orientation='0',
               width='0.6',
               height='0.6',
               color='black',
               peripheries='1')

        # Make nodes and edges for input streams
        di = 0  # Destination position of stream
        for stream in self.ins:
            if not stream: continue
            f.node(stream.ID)
            edge_in = self._graphics.edge_in
            if di >= len(edge_in): di = 0
            f.attr('edge',
                   arrowtail='none',
                   arrowhead='none',
                   tailport='e',
                   **edge_in[di])
            f.edge(stream.ID, name)
            di += 1

        # Make nodes and edges for output streams
        oi = 0  # Origin position of stream
        for stream in self.outs:
            if not stream: continue
            f.node(stream.ID)
            edge_out = self._graphics.edge_out
            if oi >= len(edge_out): oi = 0
            f.attr('edge',
                   arrowtail='none',
                   arrowhead='none',
                   headport='w',
                   **edge_out[oi])
            f.edge(name, stream.ID)
            oi += 1
        save_digraph(f, file, format)
def create_ethanol_production_system(ID='ethanol_production_sys',
                                     sugar_solution=None):
    ### Streams ###
    
    # Fresh water
    stripping_water = bst.Stream('stripping_water', Water=5000, units='kg/hr')
    
    # Gasoline
    denaturant = bst.Stream('denaturant', Octane=230.69,
                            units='kg/hr', price=price['Gasoline'])
    
    if not sugar_solution: # Feedstock
        sugar_solution = bst.Stream('sugar_solution',
            Glucose = 3802,
            Sucrose = 4.309e+04,
            Water   = 2.59e+05,
            H3PO4   = 83.33,
            units = 'kg/hr',
            T = 372,
        )
    
    # Yeast
    yeast = bst.Stream('yeast', Water=24700, DryYeast=10300, units='kg/hr')
    
    # Ethanol product
    ethanol = bst.Stream('ethanol', price=price['Ethanol'])
    
    ### Units ###
    
    # Split sugar solution
    S301 = units.Splitter('S301',
                        split=0.265)
    
    # Concentrate sugars
    F301 = units.MultiEffectEvaporator('F301',
                                       P=(101325, 73581, 50892, 32777),
                                       V=0.95) # fraction evaporated
    F301.components['condenser'].U = 1.85
    # Note: value of steam ~ 6.86 for the following 
    # (101325, 73580.467, 50891.17, 32777.406, 19999.925, 11331.5),
    
    # Mix sugar solutions
    M301 = units.Mixer('M301')
    
    # Cool for fermentation
    H301 = units.HXutility('H301', T=295.15)
    
    # 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), 
                              outs=('vent', ''),
                              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',))
    
    # Mix in Water
    M302 = units.Mixer('M302')
    P301 = units.Pump('P301')
    
    # Heat up before beer column
    # Exchange heat with stillage
    H302 = units.HXprocess('H302', phase0='l', phase1='l', U=1.28)
    
    # Beer column
    xbot = mass2molar_ethanol_fraction(0.00001)
    ytop = mass2molar_ethanol_fraction(0.574)
    D302 = units.BinaryDistillation('D302', P=101325,
                                y_top=ytop, x_bot=xbot, 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')
    
    ytop = mass2molar_ethanol_fraction(0.9061726)
    D303 = units.BinaryDistillation('D303', P=101325,
                                y_top=ytop, x_bot=xbot, 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'))
    
    # Condense ethanol product
    H304 = units.HXutility('H304', 'S149', V=0, T=340.)
    T302 = units.StorageTank('T302', tau=7*24,
                             vessel_type='Floating roof',
                             vessel_material='Carbon steel')
    P304 = units.Pump('P304')
    
    # Storage for gasoline
    T303 = units.StorageTank('T303', tau=7*24,
                             vessel_type='Floating roof',
                             vessel_material='Carbon steel')
    P305 = units.Pump('P305')
    
    # Denatured ethanol product
    T304 = units.MixTank('T304', outs=ethanol)
    T304.tau = 0.10
    
    # Waste water
    M305 = units.Mixer('M305', outs='wastewater')
    
    # Yeast mixing
    T305 = units.MixTank('T305')
    T305.tau = 0.1
    yeast-T305
    
    # Multi-effect evaporator pumps
    P306 = units.Pump('P306')
    
    
    ### Ethanol system set-up ###
    
    sugar_solution-S301-1-F301-0-P306
    (S301-0, P306-0)-M301-H301
    (H301-0, yeast-T305-0)-R301-1-T301-0-C301
    (C301-0, 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
    
    def adjust_denaturant():
        P304._run()
        pure_ethanol = P304.outs[0]
        denaturant.imol['Octane'] = 0.021*pure_ethanol.F_mass/114.232
        
    P304.specification = adjust_denaturant
    U301-1-H304-0-T302-0-P304
    denaturant-T303-P305
    (P305-0, P304-0)-T304
    (P303-0, F301-1, H302-1)-M305
    
    ### System ###
    
    return bst.System(ID, 
                [S301, 
                 F301, 
                 P306, 
                 M301, 
                 H301, 
                 T305,
                 R301,
                 T301, 
                 C301, 
                 M302, 
                 P301,
                 bst.System('beer_column_heat_integration',
                     [H302,
                      D302,
                      P302],
                     recycle=P302-0),
                 bst.System('ethanol_recycle_from_molecular_sieves',
                     [M303,
                      D303,
                      H303,
                      U301],
                     recycle=U301-0),
                 H304,
                 T302, 
                 P304,
                 T303, 
                 P305, 
                 T304, 
                 D301,
                 P303, 
                 M305])
Ejemplo n.º 13
0
def create_system(ID='sugarcane_sys'):
    ### Streams ###
    chemicals = bst.settings.get_chemicals()

    z_mass_sugarcane = chemicals.kwarray(
        dict(Glucose=0.0120811,
             Lignin=0.0327653,
             Solids=0.015,
             Sucrose=0.136919,
             Ash=0.006,
             Cellulose=0.0611531,
             Hemicellulose=0.036082,
             Water=0.7))

    sugarcane = bst.Stream('sugarcane',
                           flow=333334 * z_mass_sugarcane,
                           units='kg/hr',
                           price=price['Sugar cane'])

    enzyme = bst.Stream('enzyme',
                        Cellulose=100,
                        Water=900,
                        units='kg/hr',
                        price=price['Protease'])

    imbibition_water = bst.Stream('imbibition_water',
                                  Water=87023.35,
                                  units='kg/hr',
                                  T=338.15)

    H3PO4 = bst.Stream('H3PO4',
                       H3PO4=74.23,
                       Water=13.10,
                       units='kg/hr',
                       price=price['H3PO4'])  # to T203

    lime = bst.Stream('lime',
                      CaO=333.00,
                      Water=2200.00,
                      units='kg/hr',
                      price=price['Lime'])  # to P5

    polymer = bst.Stream('polymer',
                         Flocculant=0.83,
                         units='kg/hr',
                         price=price['Polymer'])  # to T205

    rvf_wash_water = bst.Stream('rvf_wash_water',
                                Water=16770,
                                units='kg/hr',
                                T=363.15)  # to C202

    ### Unit operations ###

    # Feed the shredder
    U101 = units.ConveyingBelt('U101', ins=sugarcane)

    # Separate metals
    U102 = units.MagneticSeparator('U102', ins=U101 - 0)

    # Shredded cane
    U103 = units.Shredder('U103', ins=U102 - 0)

    # Hydrolyze starch
    T201 = units.EnzymeTreatment('T201', T=323.15)  # T=50

    # Finely crush lipid cane
    U201 = units.CrushingMill('U201',
                              split=dict(Ash=0.92,
                                         Cellulose=0.92,
                                         Glucose=0.04,
                                         Hemicellulose=0.92,
                                         Lignin=0.92,
                                         Sucrose=0.04,
                                         Solids=1),
                              moisture_content=0.5)

    # Convey out bagasse
    U202 = units.ConveyingBelt('U202', ins=U201.outs[0], outs='Bagasse')

    # Mix in water
    M201 = units.Mixer('M201')
    # crushing_mill_recycle_sys = bst.System('crushing_mill_recycle_sys',
    #                                path=(U201, S201, M201),
    #                                recycle=M201-0)

    # Screen out fibers
    S201 = units.VibratingScreen('S201',
                                 split=dict(Ash=0.35,
                                            Cellulose=0.35,
                                            Glucose=0.88,
                                            Hemicellulose=0.35,
                                            Lignin=0.35,
                                            Solids=0,
                                            Sucrose=0.88,
                                            Water=0.88))

    # Store juice before treatment
    T202 = units.StorageTank('T202', tau=4, vessel_material='Carbon steel')

    # Heat up before adding acid
    H201 = units.HXutility('H201', T=343.15)

    # Mix in acid
    T203 = units.MixTank('T203')

    # Pump acid solution
    P201 = units.Pump('P201')

    # Mix lime solution
    T204 = units.MixTank('T204', tau=0.10)
    P202 = units.Pump('P202')

    # Blend acid lipid solution with lime
    T205 = units.MixTank('T205', tau=0.10)

    # Mix recycle
    M202 = units.Mixer('M202')

    # Heat before adding flocculant
    H202 = units.HXutility('H202', T=372.15)

    # Mix in flocculant
    T206 = units.MixTank('T206')
    T206.tau = 0.10

    # Separate residual solids
    C201 = units.Clarifier('C201',
                           split=dict(Ash=0,
                                      CaO=0,
                                      Cellulose=0,
                                      Flocculant=0.522,
                                      Glucose=0.522,
                                      Hemicellulose=0,
                                      Lignin=0,
                                      H3PO4=0.522,
                                      Sucrose=0.522,
                                      Water=0.522))

    # Remove solids as filter cake
    C202 = units.RVF('C202',
                     outs=('filter_cake', ''),
                     moisture_content=0.80,
                     split=dict(Ash=0.85,
                                CaO=0.85,
                                Cellulose=0.85,
                                Glucose=0.01,
                                Hemicellulose=0.85,
                                Lignin=0.85,
                                Sucrose=0.01))
    P203 = units.Pump('P203')

    # Screen out small fibers from sugar stream
    S202 = units.VibratingScreen('S202',
                                 outs=('', 'fiber_fines'),
                                 split=dict(Ash=1.0,
                                            CaO=1.0,
                                            Cellulose=1.0,
                                            Flocculant=0.0,
                                            Glucose=0.998,
                                            Hemicellulose=1.0,
                                            Lignin=1.0,
                                            H3PO4=1.0,
                                            Sucrose=0.998,
                                            Water=0.998))
    S202.mesh_opening = 2

    ### Process specifications ###

    # Specifications dependent on lipid cane flow rate
    def correct_flows():
        U103._run()
        F_mass = sugarcane.F_mass
        # correct enzyme, lime, phosphoric acid, and imbibition water
        enzyme.imass['Cellulose',
                     'Water'] = 0.003 * F_mass * np.array([0.1, 0.9])
        lime.imass['CaO', 'Water'] = 0.001 * F_mass * np.array([0.046, 0.954])
        H3PO4.imass['H3PO4', 'Water'] = 0.00025 * F_mass
        imbibition_water.imass['Water'] = 0.25 * F_mass

    U103.specification = correct_flows

    # Specifications within a system
    def correct_wash_water():
        P202._run()
        solids = P202.outs[0].imol['Ash', 'CaO', 'Cellulose', 'Hemicellulose',
                                   'Lignin'].sum()
        rvf_wash_water.imol['Water'] = 0.0574 * solids

    P202.specification = correct_wash_water

    ### System set-up ###

    (U103 - 0, enzyme) - T201
    (T201 - 0, M201 - 0) - U201 - 1 - S201 - 0 - T202
    (S201 - 1, imbibition_water) - M201

    T202 - 0 - H201
    (H201 - 0, H3PO4) - T203 - P201
    (P201 - 0, lime - T204 - 0) - T205 - P202
    (P202 - 0, P203 - 0) - M202 - H202
    (H202 - 0, polymer) - T206 - C201
    (C201 - 1, rvf_wash_water) - C202 - 1 - P203
    C201 - 0 - S202

    ### Ethanol section ###

    ethanol_production_sys = create_ethanol_production_system(
        sugar_solution=S202 - 0)

    ### Facilities ###

    s = F.stream
    BT = units.BoilerTurbogenerator(
        'BT', (U202 - 0, '', 'boiler_makeup_water', 'natural_gas', '', ''),
        boiler_efficiency=0.80,
        turbogenerator_efficiency=0.85)

    CT = units.CoolingTower('CT')
    makeup_water_streams = (s.cooling_tower_makeup_water,
                            s.boiler_makeup_water)
    process_water_streams = (s.imbibition_water, rvf_wash_water,
                             s.stripping_water, *makeup_water_streams)
    makeup_water = bst.Stream('makeup_water', price=0.000254)

    CWP = units.ChilledWaterPackage('CWP')
    PWC = units.ProcessWaterCenter('PWC', (bst.Stream(), makeup_water), (),
                                   None, makeup_water_streams,
                                   process_water_streams)

    ### System ###

    return bst.System(
        ID,
        [
            U101, U102, U103, T201,
            bst.System("juice_extraction_sys", [U201, S201, M201],
                       recycle=M201 - 0), T202, H201, T203, P201, T204, T205,
            P202,
            bst.System('juice_separation_sys',
                       [M202, H202, T206, C201, C202, P203],
                       recycle=P203 - 0), S202, ethanol_production_sys, U202
        ],
        facilities=(CWP, BT, CT, PWC),
    )
Ejemplo n.º 14
0
P306 = units.Pump('P306')

### Ethanol system set-up ###

sugar_solution - S301 - 1 - F301 - 0 - P306
(S301 - 0, P306 - 0) - M301 - H301
(H301 - 0, yeast - T305 - 0) - R301 - 1 - T301 - 0 - C301
(C301 - 0, D301 - 1) - M302 - P301
(P301 - 0, P302 - 0) - H302 - 0 - D302 - 1 - P302
EtOH_start_path = (S301, F301, P306, M301, H301, T305, R301, T301, C301, D301,
                   M302, P301, H302, D302, P302, H302)

(D302 - 0, U301 - 0) - M303 - 0 - D303 - 0 - H303 - U301
D303 - 1 - P303
ethanol_recycle_sys = bst.System('ethanol_recycle_sys',
                                 path=(M303, D303, H303, U301),
                                 recycle=M303 - 0)

pure_ethanol = P304.outs[0]


def adjust_denaturant():
    denaturant.imol['Octane'] = 0.021 * pure_ethanol.F_mass / 114.232


PS4 = bst.ProcessSpecification('PS4', specification=adjust_denaturant)

U301 - 1 - H304 - 0 - T302 - 0 - P304 - 0 - PS4
denaturant - T303 - P305
(P305 - 0, PS4 - 0) - M304 - T304
(P303 - 0, F301 - 1) - M305
Ejemplo n.º 15
0
def test_equipment_lifetimes():
    from biorefineries.sugarcane import create_tea
    bst.settings.set_thermo(['Water'], cache=True)
    
    class A(bst.Unit):
        _BM = {
            'Equipment A': 2,
            'Equipment B': 3,
        }
        _equipment_lifetime = {
            'Equipment A': 10,
            'Equipment B': 5,
        }
        def _cost(self):
            purchase_costs = self.purchase_costs
            purchase_costs['Equipment A'] = 1e6
            purchase_costs['Equipment B'] = 1e5
            
    class B(bst.Unit):
        _BM = {
            'Equipment A': 2,
        }
        _equipment_lifetime = 15
        def _cost(self):
            self.purchase_costs['Equipment A'] = 1e6

    class C(bst.Unit):
        _BM = {
            'Equipment A': 4,
        }
        def _cost(self):
            self.purchase_costs['Equipment A'] = 1e6
            
    @bst.decorators.cost('Flow rate', units='kmol/hr', S=1, BM=3,
                         cost=1e6, n=0.6, CE=bst.CE, lifetime=8)
    class D(bst.Unit): pass
    
    @bst.decorators.cost('Flow rate', units='kmol/hr', S=1, BM=4,
                         cost=1e6, n=0.6, CE=bst.CE, lifetime=20)
    class E(bst.Unit): pass
    
    D_feed = bst.Stream('D_feed', Water=1)
    E_feed = D_feed.copy('E_feed')
    units = [A(None, 'A_feed'), B(None, 'B_feed'), C(None, 'C_feed'), D(None, D_feed), E(None, E_feed)]
    test_sys = bst.System('test_sys', units)
    test_sys.simulate()
    tea = create_tea(test_sys)
    table = tea.get_cashflow_table()
    C_FCI = table['Fixed capital investment [MM$]']
    # Test with lang factor = 3 (default for sugarcane biorefinery)
    cashflows_FCI = [6.12, 9.18, 0.0, 0.0, 0.0, 0.0, 0.0, 0.3, 0.0, 0.0, 3.0, 
                     0.0, 3.3, 0.0, 0.0, 0.0, 0.0, 0.3, 0.0, 0.0, 0.0, 0.0]
    assert_allclose(C_FCI, cashflows_FCI)
    # Cashflows include maintainance and others, so all entries are not zero
    cashflows = [-6120000.0, -9945000.0, -4321300.0, -4321300.0, -4321300.0, 
                 -4321300.0, -4321300.0, -4621300.0, -4321300.0, -4321300.0, 
                 -7321300.0, -4321300.0, -7621300.0, -4321300.0, -4321300.0, 
                 -4321300.0, -4321300.0, -4621300.0, -4321300.0, -4321300.0, 
                 -4321300.0, -3556300.0]
    assert_allclose(tea.cashflow_array, cashflows)
    
    # Test with bare module costs
    tea.lang_factor = None
    table = tea.get_cashflow_table()
    C_FCI = table['Fixed capital investment [MM$]']
    cashflows_FCI = [6.12, 9.18, 0.0, 0.0, 0.0, 0.0, 0.0, 0.3, 0.0, 0.0, 3.0, 
                     0.0, 2.3, 0.0, 0.0, 0.0, 0.0, 0.3, 0.0, 0.0, 0.0, 0.0]
    assert_allclose(C_FCI, cashflows_FCI)
    cashflows = [-6120000.0, -9945000.0, -4321300.0, -4321300.0, -4321300.0, 
                 -4321300.0, -4321300.0, -4621300.0, -4321300.0, -4321300.0, 
                 -7321300.0, -4321300.0, -6621300.0, -4321300.0, -4321300.0, 
                 -4321300.0, -4321300.0, -4621300.0, -4321300.0, -4321300.0, 
                 -4321300.0, -3556300.0]
    assert_allclose(tea.cashflow_array, cashflows)
Ejemplo n.º 16
0
def create_system(ID='LAOs_sys', stainless_steel=True):
    checks = {'check_atomic_balance': True}
    # LAOs production
    LAOs_production =  ParallelRxn([
        Rxn('Hexanol -> Hexene + H2O', 'Hexanol', 1, **checks),
        Rxn('Octanol -> Octene + H2O', 'Octanol', 1, **checks),
        Rxn('Decanol -> Decene + H2O', 'Decanol', 1, **checks),
        Rxn('Dodecanol -> Dodecene + H2O', 'Dodecanol', 1, **checks),
        Rxn('Tetradecanol -> Tetradecene + H2O', 'Tetradecanol', 1, **checks),
        Rxn('Hexadecanol -> Hexadecene + H2O', 'Hexadecanol', 1, **checks),
    ])
    
    stream_data_path = os.path.join(os.path.dirname(__file__), 'streams.yaml')
    stream_data = tmo.ThermoData.from_yaml(stream_data_path)
    hexene, octene, decene = stream_data.create_streams(['hexene', 'octene', 'decene'])
    
    fattyalcohol_production_sys = create_fattyalcohol_production_sys()
    F.unit.C101.liquids_isplit['Hexene', 'Octene', 'Decene', 'Dodecene', 'Tetradecene'] = 1.0
    H102 = units.HXprocess('H102', ins=F.unit.P107-0, dT=10, phase0='g', phase1='l')
    M103 = units.Mixer('M103', ins=(H102-0, None))
    H103 = units.HXutility('H103', ins=M103-0, V=1, T=623.15)
    R102 = LAOs_units.AdiabaticFixedbedGasReactor('R102',
        ins=H103-0,
        WHSV=1.,
        vessel_type='Vertical',
        P=5 * 101325, 
        reaction=LAOs_production,
        length_to_diameter=2,
        catalyst_price=9.69,
        catalyst_density=2650
    )
    R102-0-1-H102
    R102.dehydration_reactor_mass_fraction = 0.10 # A proces specification
    H105 = units.HXutility('H105', ins=H102-1, T=320)
    T107 = LAOs_units.SurgeTank('T107', H105-0, ('recycle_nitrogen', 'LAOs_to_separations'),
                                  tau=0.1)
    P105 = units.Pump('P105', T107-1)
    C102 = units.LiquidsSplitCentrifuge('C102', P105-0,
                               split=dict(Water=0.1,
                                          Tridecane=1.0,
                                          Hexene=1.0,
                                          Octene=1.0,
                                          Decene=1.0,
                                          Dodecene=1.0,
                                          Tetradecene=1.0))
    P106 = units.Pump('P106', C102-0)
    H104 = units.HXprocess('H104', ins=(P106-0, None), phase0='l', phase1='l')
    
    # Lab mass fraction is 0.0242 g / g
    # Baseline mass fraction is 0.1 g /g
    def adjust_nitrogen_flow():
        T107._run()
        recycle_nitrogen = T107.outs[0]
        feed = H102.outs[0]
        F_mass = feed.F_mass
        F_mass_alcohols = feed.imass[LAOs.fermentation_products].sum()
        x_alcohol = R102.dehydration_reactor_mass_fraction
        # Math to get amount of nitrogen flow:
        # x_alcohol = F_mass_alcohols / (F_mass + F_mass_N2)
        # F_mass_N2 * x_alcohol + x_alcohol * F_mass = F_mass_alcohols
        # F_mass_N2 * x_alcohol = F_mass_alcohols - x_alcohol * F_mass 
        F_mass_N2 = F_mass_alcohols / x_alcohol - F_mass 
        if F_mass_N2 < 0: F_mass_N2 = 0
        recycle_nitrogen.imass['Nitrogen'] = F_mass_N2
        recycle_nitrogen.phase = 'g'
    
    T107.specification = adjust_nitrogen_flow
    T107 - 0 - 1 - M103
    D101 = units.ShortcutColumn('D101', H104-0, LHK=('Decene', 'Tridecane'), 
                                k=1.05, Lr=0.999, Hr=0.90, is_divided=True)
    
    def distillate_recoveries_hook(IDs, recoveries):
        light_keys = ('Water', 'Hexene', 'Octene')
        index = [n for n, i in enumerate(IDs) if i in light_keys]
        recoveries[index] = 1.0
    D102 = units.ShortcutColumn('D102', D101-0, LHK=('Decene', 'Tridecane'), 
                                k=1.05, y_top=0.98, x_bot=1e-9, is_divided=True)
    D102._distillate_recoveries_hook = distillate_recoveries_hook
    M105 = units.Mixer('M105', (D101-1, D102-1))
    P108 = units.Pump('P108', M105-0)
    P108-0-1-H104
    settler_data = {'split': dict(Water=0.000227,
                                  Tridecane=0.999999,
                                  Hexanol=0.342,
                                  Octanol=0.859,
                                  Decanol=0.932,
                                  Dodecanol=0.999,
                                  Hexene=1.0,
                                  Octene=1.0,
                                  Decene=1.0,
                                  Dodecene=1.0,
                                  Tetradecene=1.0,
                                  Tetradecanol=1.0)
    }
    M104 = units.MixerSettler('M104', (H104-1, F.unit.C101-1, C102-1, ''), ('', 'wastewater'),
                              settler_data=settler_data, model='split')
    
    def adjust_price_per_organics():
        M104._run()
        wastewater = M104.outs[1]
        wastewater.price = -0.33 * (1 - wastewater.imass['Water', 'NaCl'].sum() / wastewater.F_mass)
    
    M104.specification = adjust_price_per_organics
    M104.outs[1].price = -0.33 # USD / kg organics
    P109 = units.Pump('P109', M104-0, 1**F.unit.M101)
    H109 = units.HXutility('H109', D102-0, T=320, V=0)
    C103 = units.LiquidsSplitCentrifuge('C103', H109-0, outs=('', 3**M104),
                               split=dict(Water=0.01,
                                          Hexene=0.995,
                                          Octene=0.999,
                                          Decene=1.0,
                                          Dodecene=1.0,
                                          Tetradecene=1.0))
    
    D103 = units.ShortcutColumn('D103', LHK=('Hexene', 'Octene'),
                                k=1.05, y_top=0.98, x_bot=1e-6)
    H106 = units.HXutility('H106', D103-0, T=320, V=0)
    D104 = units.BinaryDistillation('D104', D103-1, LHK=('Octene', 'Decene'),
                                k=1.05, y_top=0.98, x_bot=1e-6)
    H107 = units.HXutility('H107', D104-0, T=320, V=0)
    H108 = units.HXprocess('H108', (C103-0, D104-1), dT=5, phase1='l')
    H108-0-D103
    
    T108 = units.StorageTank('T108', H106-0, hexene,
                              vessel_type='Floating roof',
                              tau=7*24)
    T109 = units.StorageTank('T109', H107-0, octene,
                              vessel_type='Floating roof',
                              tau=7*24)
    T110 = units.StorageTank('T110', H108-1, decene,
                              vessel_type='Floating roof',
                              tau=7*24)
    
    ### Facilities ###
    
    *other_agents, high_pressure_steam = bst.HeatUtility.heating_agents
    BT = bst.BoilerTurbogenerator('BT', 
                                  ins=(None, None, 'boiler_makeup_water', 
                                       'natural_gas', 'lime', 'boiler_chemicals'),
                                  boiler_efficiency = 0.80,
                                  turbogenerator_efficiency=0.85,
                                  agent=high_pressure_steam,
                                  other_agents=other_agents)
    CT = bst.CoolingTower('CT')
    CWP = bst.ChilledWaterPackage('CWP')
    CCI = bst.ChemicalCapitalInvestment('CCI', 'Tridecane', 644.05)
    
    ### System ###
    
    sys = bst.System('LAOs_sys',
        [bst.System('tridecane_recycle',
            [fattyalcohol_production_sys,
             bst.System('reaction_heat_integration_sys',
                [H102,
                 H105,
                 T107,
                 M103,
                 H103,
                 R102],
                recycle=R102-0),
             P105,
             C102,
             P106,
             bst.System('distillation_heat_integration_sys',
                [H104,
                 D101,
                 D102,
                 C103,
                 H109,
                 M104,
                 M105,
                 P108],
                recycle=P108-0),
             P109],
            recycle=1**F.unit.M101),
         H108,
         D103,
         D104,
         H106,
         H107,
         H108,
         T108,
         T109,
         T110],
        facilities=[CWP, BT, CT, BT, CCI])

    if stainless_steel:
        isa = isinstance
        for i in sys.units:
            if isa(i, bst.HX):
                i.material = 'Stainless steel/stainless steel'
            elif isa(i, bst.BinaryDistillation):
                i.boiler.material = i.condenser.material = 'Stainless steel/stainless steel'
                i.vessel_material = 'Stainless steel 304'
                i.tray_material = 'Stainless steel 304'
            elif isa(i, bst.Pump):
                i.material = 'Stainless steel'
    return sys
Ejemplo n.º 17
0
def create_wastewater_treatment_system(
        wastewater_streams=(),
        wastewater_treatment_area=600,
        NaOH_price=0.15,
):
    """
    Create a system for wastewater treatment.

    Parameters
    ----------
    wastewater_streams : Iterable[:class:`~thermosteam.Stream`], optional
        Wastewater streams (without solids).
    wastewater_treatment_area : int, optional
        Area number to label unit operations. The default is 600.
    NaOH_price : float, optional
        Price of NaOH in USD/kg. The default is 0.15.
    
    Returns
    -------
    wastewater_treatment : :class:`~biosteam.System`
        Wastewater treatment system. The system includes anaerobic and aerobic 
        digestion, a membrane bioreactor, a sludge centrifuge, and reverse osmosis.
        

    """
    n = wastewater_treatment_area
    well_water = bst.Stream('well_water', Water=1, T=15 + 273.15)
    air = bst.Stream('air_lagoon',
                     O2=51061,
                     N2=168162,
                     phase='g',
                     units='kg/hr')
    caustic = bst.Stream('caustic',
                         Water=2252,
                         NaOH=2252,
                         units='kg/hr',
                         price=NaOH_price * 0.5)

    wastewater_mixer = bst.Mixer(f'M{n+1}', wastewater_streams)
    WWTC = WastewaterSystemCost('WWTC', wastewater_mixer - 0)
    anaerobic_digestion = AnaerobicDigestion(f'R{n+1}', (WWTC - 0, well_water))
    recycled_sludge_mixer = bst.Mixer(f'M{n+2}',
                                      (anaerobic_digestion - 1, None))

    caustic_over_waste = caustic.mol / 2544300.6261793654
    air_over_waste = air.mol / 2544300.6261793654
    waste = recycled_sludge_mixer - 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

    aerobic_digestion = AerobicDigestion(f'R{n+2}', (waste, air, caustic),
                                         outs=('evaporated_water', ''))
    membrane_bioreactor = MembraneBioreactor(f'S{n+1}', aerobic_digestion - 1)
    sludge_splitter = bst.Splitter(f'S{n+2}',
                                   membrane_bioreactor - 1,
                                   split=0.96)
    fresh_sludge_mixer = bst.Mixer(
        f'M{n+3}', (anaerobic_digestion - 2, sludge_splitter - 1))
    sludge_centrifuge = SludgeCentrifuge(f'S{n+3}',
                                         fresh_sludge_mixer - 0,
                                         outs=('', 'sludge'))
    sludge_centrifuge - 0 - 1 - recycled_sludge_mixer
    reverse_osmosis = ReverseOsmosis(f'S{n+4}',
                                     membrane_bioreactor - 0,
                                     outs=('treated_water', 'waste_brine'))

    aerobic_digestion_sys = bst.System(
        'aerobic_digestion_sys',
        path=(recycled_sludge_mixer, update_aerobic_input_streams,
              aerobic_digestion, membrane_bioreactor, sludge_splitter,
              fresh_sludge_mixer, sludge_centrifuge),
        recycle=recycled_sludge_mixer - 0)

    wastewater_treatment = bst.System('wastewater_treatment',
                                      path=[
                                          wastewater_mixer, WWTC,
                                          anaerobic_digestion,
                                          aerobic_digestion_sys,
                                          reverse_osmosis
                                      ])
    return wastewater_treatment
Ejemplo n.º 18
0
def create_system(ID='lipidcane_sys'):
    chemicals = bst.settings.get_chemicals()
    s = bst.main_flowsheet.stream
    u = bst.main_flowsheet.unit

    ### Streams ###

    lipidcane = lipidcane = bst.Stream('lipidcane',
                                       Ash=2000.042,
                                       Cellulose=26986.69,
                                       Glucose=2007.067,
                                       Hemicellulose=15922.734,
                                       Lignin=14459.241,
                                       Lipid=10035.334,
                                       Solids=5017.667,
                                       Sucrose=22746.761,
                                       Water=234157.798,
                                       units='kg/hr',
                                       price=price['Lipid cane'])

    enzyme = bst.Stream('enzyme',
                        Cellulose=100,
                        Water=900,
                        units='kg/hr',
                        price=price['Protease'])

    imbibition_water = bst.Stream('imbibition_water',
                                  Water=87023.35,
                                  units='kg/hr',
                                  T=338.15)

    H3PO4 = bst.Stream('H3PO4',
                       H3PO4=74.23,
                       Water=13.10,
                       units='kg/hr',
                       price=price['H3PO4'])  # to T203

    lime = bst.Stream('lime',
                      CaO=333.00,
                      Water=2200.00,
                      units='kg/hr',
                      price=price['Lime'])  # to P5

    polymer = bst.Stream('polymer',
                         Flocculant=0.83,
                         units='kg/hr',
                         price=price['Polymer'])  # to T205

    rvf_wash_water = bst.Stream('rvf_wash_water',
                                Water=16770,
                                units='kg/hr',
                                T=363.15)  # to C202

    oil_wash_water = bst.Stream('oil_wash_water',
                                Water=1350,
                                units='kg/hr',
                                T=358.15)  # to T207

    ### Unit operations ###

    bst.Stream.ticket_name = 'd'
    bst.Stream.ticket_number = 100

    # Feed the shredder
    U101 = units.ConveyingBelt('U101', ins=lipidcane)
    U101.cost_items['Conveying belt'].ub = 5000

    # Separate metals
    U102 = units.MagneticSeparator('U102', ins=U101 - 0)

    # Shredded cane
    U103 = units.Shredder('U103', ins=U102 - 0)

    bst.Stream.ticket_number = 200

    # Hydrolyze starch
    T201 = units.EnzymeTreatment('T201', T=323.15)  # T=50

    # Finely crush lipid cane
    U201 = units.CrushingMill('U201',
                              split=dict(Ash=0.92,
                                         Cellulose=0.92,
                                         Glucose=0.04,
                                         Hemicellulose=0.92,
                                         Lignin=0.92,
                                         Sucrose=0.04,
                                         Lipid=0.1,
                                         Solids=1),
                              moisture_content=0.5)

    # Convey out bagasse
    U202 = units.ConveyingBelt('U202', ins=U201.outs[0], outs='Bagasse')

    # Mix in water
    M201 = units.Mixer('M201')

    # Screen out fibers
    S201 = units.VibratingScreen('S201',
                                 split=dict(Ash=0.35,
                                            Cellulose=0.35,
                                            Glucose=0.88,
                                            Hemicellulose=0.35,
                                            Lignin=0.35,
                                            Lipid=0.88,
                                            Solids=0,
                                            Sucrose=0.88,
                                            Water=0.88))

    # Store juice before treatment
    T202 = units.StorageTank('T202', tau=4, vessel_material='Carbon steel')

    # Heat up before adding acid
    H201 = units.HXutility('H201', T=343.15, V=0)

    # Mix in acid
    T203 = units.MixTank('T203')
    T203.tau = 0.10

    # Pump acid solution
    P201 = units.Pump('P201')

    # Mix lime solution
    T204 = units.MixTank('T204')
    T204.tau = 0.10
    P202 = units.Pump('P202')

    # Blend acid lipid solution with lime
    T205 = units.MixTank('T205')

    # Mix recycle
    M202 = units.Mixer('M202')

    # Heat before adding flocculant
    H202 = units.HXutility('H202', T=372.15, V=0)

    # Mix in flocculant
    T206 = units.MixTank('T206')
    T206.tau = 0.10

    # Separate residual solids
    C201 = units.Clarifier('C201',
                           split=dict(Ash=0,
                                      CaO=0,
                                      Cellulose=0,
                                      Flocculant=0.522,
                                      Glucose=0.522,
                                      Hemicellulose=0,
                                      Lignin=0,
                                      Lipid=0.98,
                                      H3PO4=0.522,
                                      Sucrose=0.522,
                                      Water=0.522))

    # Remove solids as filter cake
    C202 = units.RVF('C202',
                     outs=('filter_cake', ''),
                     moisture_content=0.80,
                     split=dict(Ash=0.85,
                                CaO=0.85,
                                Cellulose=0.85,
                                Glucose=0.01,
                                Hemicellulose=0.85,
                                Lignin=0.85,
                                Sucrose=0.01))
    P203 = units.Pump('P203')

    # Separate oil and sugar
    T207 = units.MixTank('T207')
    T207_2 = units.Splitter('T207_2', split=dict(Lipid=1, Water=1e-4))

    # Cool the oil
    H203 = units.HXutility('H203', T=343.15, V=0)

    # Screen out small fibers from sugar stream
    S202 = units.VibratingScreen('S202',
                                 outs=('', 'fiber_fines'),
                                 split=dict(Ash=1.0,
                                            CaO=1.0,
                                            Cellulose=1.0,
                                            Flocculant=0.0,
                                            Glucose=0.998,
                                            Hemicellulose=1.0,
                                            Lignin=1.0,
                                            Lipid=1.0,
                                            H3PO4=1.0,
                                            Sucrose=0.998,
                                            Water=0.998))
    sugar = S202 - 0
    S202.mesh_opening = 2

    # Add distilled water to wash lipid
    T208 = units.MixTank('T208')
    T208.tau = 0.10

    # Centrifuge out water
    C203 = units.LiquidsSplitCentrifuge('C203',
                                        split=dict(Lipid=0.99, Water=0.01))

    # Vacume out water
    F201 = units.SplitFlash('F201',
                            T=357.15,
                            P=2026.5,
                            outs=('water_vapor', ''),
                            split=dict(Lipid=0.0001, Water=0.999))

    ### Process specifications ###
    def correct_flows():
        F_mass = lipidcane.F_mass
        # correct enzyme, lime, phosphoric acid, and imbibition water
        enzyme.imass['Cellulose',
                     'Water'] = 0.003 * F_mass * np.array([0.1, 0.9])
        lime.imass['CaO', 'Water'] = 0.001 * F_mass * np.array([0.046, 0.954])
        H3PO4.imass['H3PO4', 'Water'] = 0.00025 * F_mass
        imbibition_water.imass['Water'] = 0.25 * F_mass
        T201._run()

    T201.specification = correct_flows

    # Specifications within a system
    def correct_lipid_wash_water():
        oil_wash_water.imol['Water'] = 100 / 11 * H202.outs[0].imol['Lipid']
        T208._run()

    T208.specification = correct_lipid_wash_water

    def correct_wash_water():
        P202._run()
        solids = P202.outs[0].imol['Ash', 'CaO', 'Cellulose', 'Hemicellulose',
                                   'Lignin'].sum()
        rvf_wash_water.imol['Water'] = 0.0574 * solids

    P202.specification = correct_wash_water

    ### System set-up ###

    (U103 - 0, enzyme) - T201
    (T201 - 0, M201 - 0) - U201 - 1 - S201 - 0 - T202
    (S201 - 1, imbibition_water) - M201

    T202 - 0 - H201
    (H201 - 0, H3PO4) - T203 - P201
    (P201 - 0, lime - T204 - 0) - T205 - P202
    (P202 - 0, P203 - 0) - M202 - H202
    (H202 - 0, polymer) - T206 - C201
    (C201 - 1, rvf_wash_water) - C202 - 1 - P203

    C201 - 0 - T207 - T207_2 - 0 - H203
    (H203 - 0, oil_wash_water) - T208 - C203 - 0 - F201
    T207 - T207_2 - 1 - S202

    lipid = F201 - 1

    ### Ethanol section ###

    ### Utilities ###

    MW_etoh = chemicals.Ethanol.MW
    MW_water = chemicals.Water.MW

    def mass2molar_ethanol_fraction(ethanol_mass_fraction):
        """Return ethanol mol fraction in a ethanol water mixture"""
        x = ethanol_mass_fraction
        return x / MW_etoh / (x / MW_etoh + (1 - x) / MW_water)

    ### Input streams ###

    ethanol_production_sys = create_ethanol_production_system(
        sugar_solution=S202 - 0)
    u.M305.ins.append(C203 - 1)

    ### Biodiesel section ###

    ### Streams ###

    # Fresh degummed oil
    oil = lipid

    # Fresh methanol
    methanol = bst.Stream('methanol', Methanol=1, price=price['Methanol'])

    # Catalyst
    catalyst = bst.Stream('catalyst',
                          NaOCH3=0.25,
                          Methanol=0.75,
                          units='kg/hr',
                          price=price['NaOCH3'])
    # price=0.25*price['NaOCH3'] + 0.75*Methanol.price)

    # Water to remove glycerol
    biodiesel_wash_water = bst.Stream('biodiesel_wash_water',
                                      Water=13.6,
                                      T=273.15 + 60,
                                      price=price['Water'])

    # Acid to neutralize catalyst after second centrifuge
    HCl1 = bst.Stream('HCl1', HCl=0.21, Water=0.79, price=price['HCl'])
    # price=0.21*price['HCl'] + 0.79*Water.price) # 35% HCl by mass

    # Acid to remove soaps after first centrifuge
    HCl2 = bst.Stream('HCl2', HCl=0.21, Water=0.79, price=HCl1.price)

    # Base to neutralize acid before distillation
    NaOH = bst.Stream('NaOH', NaOH=1, price=price['NaOH'])

    # Products
    crude_glycerol = bst.Stream('crude_glycerol',
                                price=price['Crude glycerol'])
    biodiesel = bst.Stream('biodiesel', price=price['Biodiesel'])

    # Waste
    waste = bst.Stream('waste', price=price['Waste'])

    ### Units ###

    ### Biodiesel Transesterification Section ###

    # Aparently reactors are adiabatic, meoh coming in at 40C, lipid at 60C

    # From USDA Biodiesel model
    x_cat = 1.05e-05  # Catalyst molar fraction in methanol feed

    # Mix Recycle Methanol and Fresh Methanol
    T401 = units.StorageTank('T401')
    P401 = units.Pump('P401')

    # Storage Tank for Catalyst
    T402 = units.StorageTank('T402')
    P402 = units.Pump('P402')

    # Tank for oil
    T403 = units.StorageTank('T403')
    T403.tau = 4
    P403 = units.Pump('P403')

    # Mix Methanol and Catalyst stream
    T404 = units.MixTank('T404')
    P404 = units.Pump('P404')

    # Split Methanol/Catalyst to reactors (this is done through a process specification, so use a fake splitter)
    S401 = bst.FakeSplitter('S401')

    # First Reactor
    R401 = units.Transesterification('R401',
                                     efficiency=0.90,
                                     methanol2lipid=6,
                                     T=333.15,
                                     catalyst_molfrac=x_cat)

    # Centrifuge to remove glycerol
    C401 = units.LiquidsSplitCentrifuge('C401',
                                        split=dict(Lipid=0.99,
                                                   Methanol=0.40,
                                                   Glycerol=0.06,
                                                   Biodiesel=0.999,
                                                   Water=0.40,
                                                   NaOH=0,
                                                   HCl=0,
                                                   NaOCH3=0.40))

    P405 = units.Pump('P405')

    # Second Reactor
    R402 = units.Transesterification('R402',
                                     efficiency=0.90,
                                     methanol2lipid=6,
                                     T=333.15,
                                     catalyst_molfrac=x_cat)

    def adjust_feed_to_reactors():
        R402._run()
        S401.ins[0].sum(S401.outs)

    R402.specification = adjust_feed_to_reactors

    # Centrifuge to remove glycerol
    C402 = units.LiquidsSplitCentrifuge('C402',
                                        split=dict(Lipid=0.90,
                                                   Methanol=0.10,
                                                   Glycerol=0.05,
                                                   Biodiesel=0.999,
                                                   Water=0.10,
                                                   NaOH=0,
                                                   HCl=0,
                                                   NaOCH3=0.10))

    # Acids and bases per catalyst by mol
    k1 = 0.323 / 1.5
    k2 = 1.060 / 1.5
    k3 = 0.04505 / 1.5

    def adjust_acid_and_base():
        T404._run()
        # Adjust according to USDA biodiesel model
        catalyst_mol = T404.outs[0].imol['NaOCH3']
        NaOH.imol['NaOH'] = k1 * catalyst_mol
        HCl1.imol['HCl'] = k2 * catalyst_mol
        HCl2.imol['HCl'] = k3 * catalyst_mol

    T404.specification = adjust_acid_and_base

    ### Biodiesel Purification Section ###

    # Water wash
    T405 = units.MixTank('T405')
    P406 = units.Pump('P406')

    # Centrifuge out water
    C403 = units.LiquidsRatioCentrifuge('C403',
                                        K_chemicals=('Methanol', 'Glycerol'),
                                        Ks=np.array([0.382, 0.183]),
                                        top_solvents=('Biodiesel', ),
                                        top_split=(0.999, ),
                                        bot_solvents=('Water', 'Lipid', 'NaOH',
                                                      'HCl'),
                                        bot_split=(0.999, 1, 1, 1))

    # Vacuum dry biodiesel
    # Consider doing this by split, and keeping this unit constant
    # 290 Pa, 324 K according to USDA Biodiesel Model
    F401 = units.SplitFlash('F401',
                            order=('Water', 'Methanol', 'Biodiesel'),
                            split=(0.9999, 0.9999, 0.00001),
                            P=2026.5,
                            T=331.5,
                            Q=0)
    F401.line = 'Vacuum dryer'
    F401.material = 'Stainless steel 304'
    P407 = units.Pump('P407')

    ### Glycerol Purification Section ###

    # Condense vacuumed methanol to recycle
    H401 = units.HXutility('H401', V=0, T=295)
    P408 = units.Pump('P408')

    # Mix recycled streams and HCl
    T406 = units.MixTank('T406')
    P409 = units.Pump('P409')

    # Centrifuge out waste fat
    # assume all the lipid, free_lipid and biodiesel is washed out
    C404 = units.LiquidsSplitCentrifuge('C404',
                                        outs=('', waste),
                                        order=('Methanol', 'Glycerol',
                                               'Water'),
                                        split=(0.999, 0.999, 0.999))

    # Add and mix NaOH
    T407 = units.MixTank('T407')
    P410 = units.Pump('P410')

    # Methanol/Water distillation column
    D401 = units.BinaryDistillation('D401',
                                    LHK=('Methanol', 'Water'),
                                    P=101325,
                                    y_top=0.99999,
                                    x_bot=0.0001,
                                    k=2.5,
                                    is_divided=True,
                                    vessel_material='Stainless steel 304',
                                    tray_material='Stainless steel 304')

    # Condense water to recycle
    H402 = units.HXutility('H402', T=353, V=0)

    # Glycerol/Water flash (not a distillation column)
    w = 0.20 / chemicals.Water.MW
    g = 0.80 / chemicals.Glycerol.MW
    x_water = w / (w + g)

    D402 = units.BinaryDistillation('D402',
                                    LHK=('Water', 'Glycerol'),
                                    k=1.25,
                                    P=101325,
                                    y_top=0.999,
                                    x_bot=x_water,
                                    tray_material='Stainless steel 304',
                                    vessel_material='Stainless steel 304')

    def startup_water():
        imol = D402.ins[0].imol
        water, glycerol = imol['Water', 'Glycerol']
        minimum_water = 5 * (w / (w + g)) * glycerol
        if water < minimum_water:
            imol['Water'] = minimum_water
        D402._run()
        # Remove accumulation
        D402.outs[0].imol['Water'] = 1100 * C402.outs[0].imol['Glycerol']

    D402.specification = startup_water

    # Condense recycle methanol
    H403 = units.HXutility('H403', V=0, T=315)
    P411 = units.Pump('P411')

    # Condense recycle water
    H404 = units.HXutility('H404', V=0, T=315)
    P412 = units.Pump('P412')

    # Storage tank for glycerol
    T408 = units.StorageTank('T408', outs=crude_glycerol)

    # Storage tank for biodiesel
    T409 = units.StorageTank('T409', outs=biodiesel)
    F401 - 1 - P407 - 0 - T409

    ### Biodiesel system set-up ###

    # Biodiesel Transesterification Section
    oil - T403 - P403
    (P403 - 0, S401 - 0) - R401 - 0 - C401
    (C401 - 0, S401 - 1) - R402 - 0 - C402 - 1

    # Specs for product https://www.afdc.energy.gov/fuels/biodiesel_specifications.html
    # minimum spec requirements:
    #  0.050 wt % water (lower to 0.045)
    #  0.2 wt % meoh (lower to 0.15)
    #  0.02 wt % glycerol (lower to 0.015)
    #  0.4 wt % free lipids (lower to 0.35)

    # Find Water Flow
    def adjust_biodiesel_wash_water():
        total_glycerol = (C401.outs[1].imol['Glycerol'] +
                          R402.outs[0].imol['Glycerol'])
        wash_water = (x_water / (1 - x_water) * total_glycerol -
                      HCl1.imol['Water'] - NaOH.imol['Water'] -
                      oil.imol['Water'] - HCl2.imol['Water'])
        biodiesel_wash_water.imol[
            'Water'] = wash_water if wash_water > 0 else 0.
        T405._run()

    T405.specification = adjust_biodiesel_wash_water
    D402 - 0 - H404 - 0 - P412

    # Biodiesel wash
    (C402 - 0, P412 - 0, biodiesel_wash_water, HCl1) - T405 - P406 - C403

    # Glycerol recycle and purification section
    C403 - 0 - F401
    F401 - 0 - H401 - P408
    C401 - 1 - P405
    (P405 - 0, C402 - 1, C403 - 1, P408 - 0, HCl2) - T406 - P409 - C404
    (C404 - 0, NaOH) - T407 - P410
    H402 - 0 - D401 - 1 - D402 - 1 - T408
    P410 - 0 - H402

    # Mass Balance for Methanol, Recycle Methanol, and Catalyst stream
    B401 = bst.MassBalance(
        'B401',
        description='Adjust catalyst and methanol feed to reactors',
        variable_inlets=[catalyst, methanol],
        constant_inlets=[D401 - 0],
        constant_outlets=[1**R401, 1**R402],
        chemical_IDs=('Methanol', 'NaOCH3'))

    # Find Fresh Methanol Flow
    D401 - 0 - B401 - H403 - P411  # Recycle methanol
    methanol - T401 - P401  # Mix fresh and recycled methanol
    catalyst - T402 - P402  # Fresh catalyst
    (P411 - 0, P401 - 0,
     P402 - 0) - T404 - P404 - S401  # Mix Catalyst with Methanol

    # Initial guess
    D402.outs[0].imol['Methanol', 'Glycerol',
                      'Water'] = [0.00127, 3.59e-05, 0.0244]

    ### Facilities ###

    # Burn bagasse from conveyor belt
    BT = units.BoilerTurbogenerator(
        'BT', (U202 - 0, '', 'boiler_makeup_water', 'natural_gas', '', ''),
        boiler_efficiency=0.80,
        turbogenerator_efficiency=0.85)

    CT = units.CoolingTower('CT')
    makeup_water_streams = (s.cooling_tower_makeup_water,
                            s.boiler_makeup_water)

    process_water_streams = (s.imbibition_water, s.biodiesel_wash_water,
                             oil_wash_water, rvf_wash_water, s.stripping_water,
                             *makeup_water_streams)

    makeup_water = bst.Stream('makeup_water', price=0.000254)

    CWP = units.ChilledWaterPackage('CWP')
    PWC = units.ProcessWaterCenter('PWC', (bst.Stream(), makeup_water), (),
                                   None, makeup_water_streams,
                                   process_water_streams)

    return bst.System(
        ID,
        [
            U101, U102, U103, T201,
            bst.System('juice_extraction_sys', [U201, S201, M201],
                       recycle=M201 - 0), T202, H201, T203, P201, T204, T205,
            P202,
            bst.System(
                'juice_separation_sys', [M202, H202, T206, C201, C202, P203],
                recycle=P203 - 0), T207, T207_2, H203, T208, C203, F201, T403,
            P403, R401, C401, R402, C402,
            bst.System('methanol_recycle_sys', [
                T406, P409, C404, T407, P410, H402, D401, D402, H404, P412,
                T405, P406, C403
            ],
                       recycle=C403 - 1), F401, P407, T409, H401, P408, P405,
            B401, H403, P411, T401, P401, T402, P402, T404, P404, S401, S202,
            ethanol_production_sys, T408, U202
        ],
        facilities=(CWP, BT, CT, PWC),
    )