separations
This module contains functions for modeling separations in unit operations.
- thermosteam.separations.split(feed, 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 = tmo.Stream(Water=35, Ethanol=10) >>> split = 0.8 >>> effluent_a = tmo.Stream('effluent_a') >>> effluent_b = tmo.Stream('effluent_b') >>> tmo.separations.split(feed, 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
- thermosteam.separations.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
- thermosteam.separations.adjust_moisture_content(retentate, permeate, moisture_content)[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
- thermosteam.separations.mix_and_split_with_moisture_content(ins, retentate, permeate, split, moisture_content)[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
- thermosteam.separations.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.629, 1.59 ])
- thermosteam.separations.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.629, 1.59 ])
- thermosteam.separations.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) >>> IDs, K = tmo.separations.lle_partition_coefficients(s['l'], s['L']) >>> IDs ('Water', 'Ethanol', 'Octanol') >>> K array([6.82e+00, 2.38e-01, 3.00e-04])
- thermosteam.separations.partition(feed, top, bottom, IDs, K, phi=None)[source]
Run equilibrium of feed to top and bottom streams given partition coeffiecients and return the phase fraction.
- Parameters
- Returns
phi – Phase fraction in top phase.
- Return type
float
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('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.5002512677600628 >>> 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
- thermosteam.separations.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.show() Stream: top phase: 'l', T: 298.15 K, P: 101325 Pa flow (kmol/hr): Water 3.55 Ethanol 0.861 Octanol 20 >>> bottom.show() Stream: bottom phase: 'l', T: 298.15 K, P: 101325 Pa flow (kmol/hr): Water 16.5 Ethanol 0.139 Octanol 0.00409
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) >>> ms.show() MultiStream: ms phases: ('L', 'l'), T: 298.15 K, P: 101325 Pa flow (kmol/hr): (L) Water 3.55 Ethanol 0.861 Octanol 20 (l) Water 16.5 Ethanol 0.139 Octanol 0.00408
- thermosteam.separations.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.88 K, P: 101325 Pa flow (kmol/hr): Water 7.72 Ethanol 12.3 >>> liquid.show() Stream: bottom phase: 'l', T: 353.88 K, P: 101325 Pa flow (kmol/hr): Water 12.3 Ethanol 7.72
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.88 K, P: 101325 Pa flow (kmol/hr): (g) Water 7.72 Ethanol 12.3 (l) Water 12.3 Ethanol 7.72
- thermosteam.separations.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 array([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.])
- class thermosteam.separations.MultiStageLLE(N_stages, feed, solvent, carrier_chemical=None, thermo=None, partition_data=None)[source]
Create a MultiStageLLE object that models a counter-current system of mixer-settlers for liquid-liquid extraction.
- Parameters
N_stages (int) – Number of stages.
feed (Stream) – Feed with solute.
solvent (Stream) – Solvent to contact feed and recover solute.
carrier_chemical (str) – Name of main chemical in the feed (which is not selectively extracted by the solvent).
partition_data ({'IDs': tuple[str], 'K': 1d array}, optional) – IDs of chemicals in equilibrium and partition coefficients (molar composition ratio of the raffinate over the extract). If given, The mixer-settlers will be modeled with these constants. Otherwise, partition coefficients are computed based on temperature and composition.
Examples
Simulate 2-stage extraction of methanol from water using octanol:
>>> import thermosteam as tmo >>> tmo.settings.set_thermo(['Water', 'Methanol', 'Octanol'], cache=True) >>> N_stages = 2 >>> feed = tmo.Stream('feed', Water=500, Methanol=50) >>> solvent = tmo.Stream('solvent', Octanol=500) >>> stages = tmo.separations.MultiStageLLE(N_stages, feed, solvent) >>> stages.simulate_multi_stage_lle_without_side_draws() >>> stages.raffinate.show() Stream: phase: 'l', T: 298.15 K, P: 101325 Pa flow (kmol/hr): Water 413 Methanol 8.4 Octanol 0.1 >>> stages.extract.show() Stream: phase: 'L', T: 298.15 K, P: 101325 Pa flow (kmol/hr): Water 87. Methanol 41. Octanol 500
Simulate 10-stage extraction with user defined partition coefficients:
>>> import numpy as np >>> tmo.settings.set_thermo(['Water', 'Methanol', 'Octanol']) >>> N_stages = 10 >>> feed = tmo.Stream('feed', Water=5000, Methanol=500) >>> solvent = tmo.Stream('solvent', Octanol=5000) >>> stages = tmo.separations.MultiStageLLE(N_stages, feed, solvent, ... partition_data={ ... 'K': np.array([6.894, 0.7244, 3.381e-04]), ... 'IDs': ('Water', 'Methanol', 'Octanol'), ... 'phi': 0.4100271108219455 # Initial phase fraction guess. This is optional. ... } ... ) >>> stages.simulate_multi_stage_lle_without_side_draws() >>> stages.raffinate.show() Stream: phase: 'l', T: 298.15 K, P: 101325 Pa flow (kmol/hr): Water 4.1e+03 Methanol 1.2 Octanol 1.5 >>> stages.extract.show() Stream: phase: 'L', T: 298.15 K, P: 101325 Pa flow (kmol/hr): Water 871 Methanol 499 Octanol 5e+03
- thermosteam.separations.single_component_flow_rates_for_multi_stage_lle_without_side_draws(N_stages, phase_ratios, partition_coefficients, feed, solvent)[source]
Solve flow rates for a single component across a multi stage liquid-liquid extraction operation without side draws.
- Parameters
N_stages (int) – Number of stages.
phase_ratios (1d array) – Phase ratios by stage. The phase ratio for a given stage is defined as F_l / F_L; where F_l and F_L are the flow rates of phase l (raffinate) and L (extract) leaving the stage respectively.
partition_coefficients (1d array) – Partition coefficients by stage. The partition coefficient for a given stage is defined as x_l / x_L; where x_l and x_L are the fraction of the component in phase l (raffinate) and L (extract) leaving the stage.
feed (float) – Component flow rate in feed entering stage 1.
solvent (float) – Component flow rate in solvent entering stage N.
- Returns
extract_flow_rates – Extract component flow rates by stage.
- Return type
1d array
- thermosteam.separations.flow_rates_for_multi_stage_extration_without_side_draws(N_stages, phase_fractions, partition_coefficients, feed, solvent)[source]
Solve flow rates for a single component across a multi stage liquid-liquid extraction without side draws.
- Parameters
N_stages (int) – Number of stages.
phase_fractions (1d array) – Phase fractions by stage. The phase fraction for a given stage is defined as F_l / (F_l + F_L); where F_l and F_L are the flow rates of phase l (raffinate) and L (extract) leaving the stage respectively.
partition_coefficients (Iterable[1d array]) – Partition coefficients with components by row and stages by column. The partition coefficient for a component in a given stage is defined as x_l / x_L; where x_l and x_L are the fraction of the component in phase l (raffinate) and L (extract) leaving the stage.
feed (Iterable[float]) – Flow rates of all components in feed entering stage 1.
solvent (Iterable[float]) – Flow rates of all components in solvent entering stage N.
- Returns
extract_flow_rates – Extract flow rates with stages by row and components by column.
- Return type
2d array
- thermosteam.separations.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.3861 Ethanol 0.6139 >>> isplits = tmo.separations.chemical_splits(stream['g'], mixed=stream) >>> isplits.show() ChemicalIndexer: Water 0.3861 Ethanol 0.6139