separations#
This module contains functions for modeling separations in unit operations.
- mix_and_split(ins, top, bottom, split)[source]#
Run splitter mass and energy balance with mixing all input streams.
- Parameters:
Examples
>>> import thermosteam as tmo >>> tmo.settings.set_thermo(['Water', 'Ethanol'], cache=True) >>> feed_a = tmo.Stream(Water=20, Ethanol=5) >>> feed_b = tmo.Stream(Water=15, Ethanol=5) >>> split = 0.8 >>> effluent_a = tmo.Stream('effluent_a') >>> effluent_b = tmo.Stream('effluent_b') >>> tmo.separations.mix_and_split([feed_a, feed_b], effluent_a, effluent_b, split) >>> effluent_a.show() Stream: effluent_a phase: 'l', T: 298.15 K, P: 101325 Pa flow (kmol/hr): Water 28 Ethanol 8 >>> effluent_b.show() Stream: effluent_b phase: 'l', T: 298.15 K, P: 101325 Pa flow (kmol/hr): Water 7 Ethanol 2
- adjust_moisture_content(retentate, permeate, moisture_content, ID=None, strict=None)[source]#
Remove water from permate to adjust retentate moisture content.
- Parameters:
Examples
>>> import thermosteam as tmo >>> Solids = tmo.Chemical('Solids', default=True, search_db=False, phase='s') >>> tmo.settings.set_thermo(['Water', Solids]) >>> retentate = tmo.Stream('retentate', Solids=20, units='kg/hr') >>> permeate = tmo.Stream('permeate', Water=50, Solids=0.1, units='kg/hr') >>> moisture_content = 0.5 >>> tmo.separations.adjust_moisture_content(retentate, permeate, moisture_content) >>> retentate.show(flow='kg/hr') Stream: retentate phase: 'l', T: 298.15 K, P: 101325 Pa flow (kg/hr): Water 20 Solids 20 >>> permeate.show(flow='kg/hr') Stream: permeate phase: 'l', T: 298.15 K, P: 101325 Pa flow (kg/hr): Water 30 Solids 0.1
Note that if not enough water is available, an InfeasibleRegion error is raised:
>>> retentate.imol['Water'] = permeate.imol['Water'] = 0 >>> tmo.separations.adjust_moisture_content(retentate, permeate, moisture_content) Traceback (most recent call last): InfeasibleRegion: not enough water; permeate moisture content is infeasible
- mix_and_split_with_moisture_content(ins, retentate, permeate, split, moisture_content, ID=None, strict=None)[source]#
Run splitter mass and energy balance with mixing all input streams and and ensuring retentate moisture content.
- Parameters:
Examples
>>> import thermosteam as tmo >>> Solids = tmo.Chemical('Solids', default=True, search_db=False, phase='s') >>> tmo.settings.set_thermo(['Water', Solids]) >>> feed = tmo.Stream('feed', Water=100, Solids=10, units='kg/hr') >>> wash_water = tmo.Stream('wash_water', Water=10, units='kg/hr') >>> retentate = tmo.Stream('retentate') >>> permeate = tmo.Stream('permeate') >>> split = [0., 1.] >>> moisture_content = 0.5 >>> tmo.separations.mix_and_split_with_moisture_content( ... [feed, wash_water], retentate, permeate, split, moisture_content ... ) >>> retentate.show(flow='kg/hr') Stream: retentate phase: 'l', T: 298.15 K, P: 101325 Pa flow (kg/hr): Water 10 Solids 10 >>> permeate.show(flow='kg/hr') Stream: permeate phase: 'l', T: 298.15 K, P: 101325 Pa flow (kg/hr): Water 100
- partition_coefficients(IDs, top, bottom)[source]#
Return partition coefficients given streams in equilibrium.
- Parameters:
- Returns:
K – Patition coefficients in mol fraction in top stream over mol fraction in bottom stream.
- Return type:
1d array
Examples
>>> import thermosteam as tmo >>> tmo.settings.set_thermo(['Water', 'Ethanol', tmo.Chemical('O2', phase='g')], cache=True) >>> s = tmo.Stream('s', Water=20, Ethanol=20, O2=0.1) >>> s.vle(V=0.5, P=101325) >>> tmo.separations.partition_coefficients(('Water', 'Ethanol'), s['g'], s['l']) array([0.632, 1.582])
- vle_partition_coefficients(top, bottom)[source]#
Return VLE partition coefficients given vapor and liquid streams in equilibrium.
- Parameters:
- Returns:
IDs (tuple[str]) – IDs for chemicals in vapor-liquid equilibrium.
K (1d array) – Patition coefficients in mol fraction in vapor over mol fraction in liquid.
Examples
>>> import thermosteam as tmo >>> tmo.settings.set_thermo(['Water', 'Ethanol', tmo.Chemical('O2', phase='g')], cache=True) >>> s = tmo.Stream('s', Water=20, Ethanol=20, O2=0.1) >>> s.vle(V=0.5, P=101325) >>> IDs, K = tmo.separations.vle_partition_coefficients(s['g'], s['l']) >>> IDs ('Water', 'Ethanol') >>> K array([0.632, 1.582])
- lle_partition_coefficients(top, bottom)[source]#
Return LLE partition coefficients given two liquid streams in equilibrium.
- Parameters:
- Returns:
IDs (tuple[str]) – IDs for chemicals in liquid-liquid equilibrium.
K (1d array) – Patition coefficients in mol fraction in top liquid over mol fraction in bottom liquid.
Examples
>>> import thermosteam as tmo >>> tmo.settings.set_thermo(['Water', 'Ethanol', 'Octanol'], cache=True) >>> s = tmo.Stream('s', Water=20, Octanol=20, Ethanol=1) >>> s.lle(T=298.15, P=101325, top_chemical='Octanol') # Top phase is L >>> IDs, K = tmo.separations.lle_partition_coefficients(s['L'], s['l']) >>> IDs ('Water', 'Ethanol', 'Octanol') >>> round(K[2], -1) # Octanol 2390.0
- partition(feed, top, bottom, IDs, K, phi=None, top_chemicals=None, bottom_chemicals=None, strict=False, stacklevel=1)[source]#
Run equilibrium of feed to top and bottom streams given partition coeffiecients and return the phase fraction.
- Parameters:
feed (Stream) – Mixed feed.
top (Stream) – Top fluid.
bottom (Stream) – Bottom fluid.
K (1d array) – Partition coefficeints corresponding to IDs.
phi (float, optional) – Guess phase fraction in top phase.
top_chemicals (tuple[str], optional) – Chemicals that remain in the top fluid.
bottom_chemicals (tuple[str], optional) – Chemicals that remain in the bottom fluid.
strict (bool, optional) – Whether to raise an InfeasibleRegion exception when solution results in negative flow rates or to remove negative flows and issue a warning. Defaults to False.
- Returns:
phi – Phase fraction in top phase.
- Return type:
Notes
Chemicals not in equilibrium end up in the top phase.
Examples
>>> import numpy as np >>> import thermosteam as tmo >>> tmo.settings.set_thermo(['Water', 'Ethanol', tmo.Chemical('NaCl', default=True), ... tmo.Chemical('O2', phase='g')], cache=True) >>> IDs = ('Water', 'Ethanol') >>> K = np.array([0.629, 1.59]) >>> feed = tmo.Stream('feed', Water=20, Ethanol=20, O2=0.1) >>> top = tmo.Stream('top') >>> bottom = tmo.Stream('bottom') >>> tmo.separations.partition(feed, top, bottom, IDs, K) 0.500 >>> top.show() Stream: top phase: 'l', T: 298.15 K, P: 101325 Pa flow (kmol/hr): Water 7.73 Ethanol 12.3 O2 0.1 >>> bottom.show() Stream: bottom phase: 'l', T: 298.15 K, P: 101325 Pa flow (kmol/hr): Water 12.3 Ethanol 7.72 >>> feed = tmo.Stream('feed', Water=20, Ethanol=20, NaCl=0.1, O2=0.1) >>> tmo.separations.partition(feed, top, bottom, IDs, K, ... top_chemicals=('O2',), ... bottom_chemicals=('NaCl')) 0.500 >>> top.show() Stream: top phase: 'l', T: 298.15 K, P: 101325 Pa flow (kmol/hr): Water 7.73 Ethanol 12.3 O2 0.1 >>> bottom.show() Stream: bottom phase: 'l', T: 298.15 K, P: 101325 Pa flow (kmol/hr): Water 12.3 Ethanol 7.72 NaCl 0.1
- lle(feed, top, bottom, top_chemical=None, efficiency=1.0, multi_stream=None)[source]#
Run LLE mass and energy balance.
- Parameters:
feed (Stream) – Mixed feed.
top (Stream) – Top fluid.
bottom (Stream) – Bottom fluid.
top_chemical (str, optional) – Identifier of chemical that will be favored in the top fluid.
efficiency=1. (float,) – Fraction of feed in liquid-liquid equilibrium. The rest of the feed is divided equally between phases
multi_stream (MultiStream, optional) – Data from feed is passed to this stream to perform liquid-liquid equilibrium.
Examples
Perform liquid-liquid equilibrium around water and octanol and split the phases:
>>> import thermosteam as tmo >>> tmo.settings.set_thermo(['Water', 'Ethanol', 'Octanol'], cache=True) >>> feed = tmo.Stream('feed', Water=20, Octanol=20, Ethanol=1) >>> top = tmo.Stream('top') >>> bottom = tmo.Stream('bottom') >>> tmo.separations.lle(feed, top, bottom, top_chemical='Octanol') >>> top.show() Stream: top phase: 'l', T: 298.15 K, P: 101325 Pa flow (kmol/hr): Water 2.87 Ethanol 0.828 Octanol 20 >>> bottom.show() Stream: bottom phase: 'l', T: 298.15 K, P: 101325 Pa flow (kmol/hr): Water 17.1 Ethanol 0.172 Octanol 0.00612
Assume that 1% of the feed is not in equilibrium (possibly due to poor mixing):
>>> import thermosteam as tmo >>> tmo.settings.set_thermo(['Water', 'Ethanol', 'Octanol'], cache=True) >>> feed = tmo.Stream('feed', Water=20, Octanol=20, Ethanol=1) >>> top = tmo.Stream('top') >>> bottom = tmo.Stream('bottom') >>> ms = tmo.MultiStream('ms', phases='lL') # Store flow rate data here as well >>> tmo.separations.lle(feed, top, bottom, efficiency=0.99, multi_stream=ms, top_chemical='Octanol') >>> ms.show() MultiStream: ms phases: ('L', 'l'), T: 298.15 K, P: 101325 Pa flow (kmol/hr): (L) Water 2.87 Ethanol 0.828 Octanol 20 (l) Water 17.1 Ethanol 0.172 Octanol 0.00612
- vle(feed, vap, liq, T=None, P=None, V=None, Q=None, x=None, y=None, multi_stream=None)[source]#
Run VLE mass and energy balance.
- Parameters:
feed (Stream) – Mixed feed.
vap (Stream) – Vapor fluid.
liq (Stream) – Liquid fluid.
P=None (float) – Operating pressure [Pa].
Q=None (float) – Duty [kJ/hr].
T=None (float) – Operating temperature [K].
V=None (float) – Molar vapor fraction.
x=None (float) – Molar composition of liquid (for binary mixtures).
y=None (float) – Molar composition of vapor (for binary mixtures).
multi_stream (MultiStream, optional) – Data from feed is passed to this stream to perform vapor-liquid equilibrium.
Examples
Perform vapor-liquid equilibrium on water and ethanol and split phases to vapor and liquid streams:
>>> import thermosteam as tmo >>> tmo.settings.set_thermo(['Water', 'Ethanol'], cache=True) >>> feed = tmo.Stream('feed', Water=20, Ethanol=20) >>> vapor = tmo.Stream('top') >>> liquid = tmo.Stream('bottom') >>> tmo.separations.vle(feed, vapor, liquid, V=0.5, P=101325) >>> vapor.show() Stream: top phase: 'g', T: 353.94 K, P: 101325 Pa flow (kmol/hr): Water 7.75 Ethanol 12.3 >>> liquid.show() Stream: bottom phase: 'l', T: 353.94 K, P: 101325 Pa flow (kmol/hr): Water 12.3 Ethanol 7.75
It is also possible to save flow rate data in a multi-stream as well:
>>> ms = tmo.MultiStream('ms', phases='lg') >>> tmo.separations.vle(feed, vapor, liquid, V=0.5, P=101325, multi_stream=ms) >>> ms.show() MultiStream: ms phases: ('g', 'l'), T: 353.94 K, P: 101325 Pa flow (kmol/hr): (g) Water 7.75 Ethanol 12.3 (l) Water 12.3 Ethanol 7.75
- material_balance(chemical_IDs, variable_inlets, constant_inlets=(), constant_outlets=(), is_exact=True, balance='flow')[source]#
Solve stream mass balance by iteration.
- Parameters:
chemical_IDs (tuple[str]) – Chemicals that will be used to solve mass balance linear equations. The number of chemicals must be same as the number of input streams varied.
variable_inlets (Iterable[Stream]) – Inlet streams that can vary in net flow rate to accomodate for the mass balance.
constant_inlets (Iterable[Stream], optional) – Inlet streams that cannot vary in flow rates.
constant_outlets (Iterable[Stream], optional) – Outlet streams that cannot vary in flow rates.
is_exact=True (bool, optional) – True if exact flow rate solution is required for the specified IDs.
balance='flow' ({'flow', 'composition'}, optional) –
‘flow’: Satisfy output flow rates
’composition’: Satisfy net output molar composition
Examples
Vary inlet flow rates to satisfy outlet flow rates:
>>> import thermosteam as tmo >>> tmo.settings.set_thermo(['Water', 'Ethanol'], cache=True) >>> in_a = tmo.Stream('in_a', Water=1) >>> in_b = tmo.Stream('in_b', Ethanol=1) >>> variable_inlets = [in_a, in_b] >>> in_c = tmo.Stream('in_c', Water=100) >>> constant_inlets = [in_c] >>> out_a = tmo.Stream('out_a', Water=200, Ethanol=2) >>> out_b = tmo.Stream('out_b', Ethanol=100) >>> constant_outlets = [out_a, out_b] >>> chemical_IDs = ('Water', 'Ethanol') >>> tmo.separations.material_balance(chemical_IDs, variable_inlets, constant_inlets, constant_outlets) >>> tmo.Stream.sum([in_a, in_b, in_c]).mol - tmo.Stream.sum([out_a, out_b]).mol # Molar flow rates entering and leaving are equal sparse([0., 0.])
Vary inlet flow rates to satisfy outlet composition:
>>> import thermosteam as tmo >>> tmo.settings.set_thermo(['Water', 'Ethanol'], cache=True) >>> in_a = tmo.Stream('in_a', Water=1) >>> in_b = tmo.Stream('in_b', Ethanol=1) >>> variable_inlets = [in_a, in_b] >>> in_c = tmo.Stream('in_c', Water=100) >>> constant_inlets = [in_c] >>> out_a = tmo.Stream('out_a', Water=200, Ethanol=2) >>> out_b = tmo.Stream('out_b', Ethanol=100) >>> constant_outlets = [out_a, out_b] >>> chemical_IDs = ('Water', 'Ethanol') >>> tmo.separations.material_balance(chemical_IDs, variable_inlets, constant_inlets, constant_outlets, balance='composition') >>> tmo.Stream.sum([in_a, in_b, in_c]).z_mol - tmo.Stream.sum([out_a, out_b]).z_mol # Molar composition entering and leaving are equal array([0., 0.])
- chemical_splits(a, b=None, mixed=None)[source]#
Return a ChemicalIndexer with splits for all chemicals to stream a.
Examples
>>> import thermosteam as tmo >>> tmo.settings.set_thermo(['Water', 'Ethanol'], cache=True) >>> stream = tmo.Stream('stream', Water=10, Ethanol=10) >>> stream.vle(V=0.5, P=101325) >>> isplits = tmo.separations.chemical_splits(stream['g'], stream['l']) >>> isplits.show() ChemicalIndexer: Water 0.387 Ethanol 0.613 >>> isplits = tmo.separations.chemical_splits(stream['g'], mixed=stream) >>> isplits.show() ChemicalIndexer: Water 0.387 Ethanol 0.613
- phase_fraction(feed, IDs, K, phi=None, top_chemicals=None, bottom_chemicals=None, strict=False, stacklevel=1)[source]#
Return the phase fraction given a stream and partition coeffiecients.
- Parameters:
feed (Stream) – Mixed feed.
K (1d array) – Partition coefficeints corresponding to IDs.
phi (float, optional) – Guess phase fraction in top phase.
top_chemicals (tuple[str], optional) – Chemicals that remain in the top fluid.
bottom_chemicals (tuple[str], optional) – Chemicals that remain in the bottom fluid.
strict (bool, optional) – Whether to raise an InfeasibleRegion exception when solution results in negative flow rates or to remove negative flows and issue a warning. Defaults to False.
- Returns:
phi – Phase fraction in top phase.
- Return type:
Notes
Chemicals not in equilibrium end up in the top phase.
Examples
>>> import numpy as np >>> import thermosteam as tmo >>> tmo.settings.set_thermo(['Water', 'Ethanol', tmo.Chemical('NaCl', default=True), ... tmo.Chemical('O2', phase='g')], cache=True) >>> IDs = ('Water', 'Ethanol') >>> K = np.array([0.629, 1.59]) >>> feed = tmo.Stream('feed', Water=20, Ethanol=20, O2=0.1) >>> tmo.separations.phase_fraction(feed, IDs, K) 0.500 >>> feed = tmo.Stream('feed', Water=20, Ethanol=20, NaCl=0.1, O2=0.1) >>> tmo.separations.phase_fraction(feed, IDs, K, ... top_chemicals=('O2',), ... bottom_chemicals=('NaCl')) 0.500