System#

System objects manage recycle loops. It takes care of bringing a chemical process to steady state.

class System(ID='', path=(), recycle=None, facilities=(), facility_recycle=None, N_runs=None, operating_hours=None, lang_factor=None, responses=None, algorithm=None, method=None, maxiter=None, molar_tolerance=None, relative_molar_tolerance=None, temperature_tolerance=None, relative_temperature_tolerance=None)[source]#

Create a System object that can iteratively run each element in a path of BioSTREAM objects until the recycle stream is converged. A path can have Unit and/or System objects. When the path contains an inner System object, it converges/solves it in each loop/iteration.

Parameters:
  • ID (str, optional) – Unique identification. If ID is None, instance will not be registered in flowsheet.

  • path (Iterable[Unit | System], optional) – Path that is run element by element until the recycle converges.

  • recycle (Stream, optional) – Tear stream for the recycle loop.

  • facilities (Iterable[Facility]) – Offsite facilities that are simulated only after completing the path simulation.

  • facility_recycle (Stream, optional) – Recycle stream between facilities and system path.

  • N_runs (int, optional) – Number of iterations to converge the system.

  • operating_hours (float, optional) – Number of operating hours in a year. This parameter is used to compute annualized properties such as utility cost and material cost on a per year basis.

  • lang_factor (float, optional) – Lang factor for getting fixed capital investment from total purchase cost. If no lang factor, installed equipment costs are estimated using bare module factors.

default_maxiter: int = 200#

Default maximum number of iterations

default_molar_tolerance: float = 1.0#

Default molar tolerance for each component [kmol/hr]

default_relative_molar_tolerance: float = 0.01#

Default relative molar tolerance for each component

default_temperature_tolerance: float = 0.1#

Default temperature tolerance [K]

default_relative_temperature_tolerance: float = 0.001#

Default relative temperature tolerance

default_phenomena_maxiter: int = 15#

Default maximum number of phenomena-oriented simulations before running each unit operation sequentially

default_algorithm: str = 'Sequential modular'#

Default convergence algorithm.

default_methods: dict[str] = {'Phenomena oriented': 'fixed-point', 'Sequential modular': 'Aitken'}#

Default method for convergence algorithm.

strict_convergence: bool = True#

Whether to raise a RuntimeError when system doesn’t converge

available_methods: Methods[str, tuple[Callable, bool, dict]] = {'aitken': (<function conditional_aitken>, True, {}), 'anderson': (<function root>, False, {'method': 'anderson', 'options': {'fatol': 1e-24, 'ftol': 1e-24, 'maxiter': 1000000, 'xatol': 1e-24, 'xtol': 1e-24}}), 'broyden1': (<function root>, False, {'method': 'broyden1', 'options': {'fatol': 1e-24, 'ftol': 1e-24, 'maxiter': 1000000, 'xatol': 1e-24, 'xtol': 1e-24}}), 'broyden2': (<function root>, False, {'method': 'broyden2', 'options': {'fatol': 1e-24, 'ftol': 1e-24, 'maxiter': 1000000, 'xatol': 1e-24, 'xtol': 1e-24}}), 'diagbroyden': (<function root>, False, {'method': 'diagbroyden', 'options': {'fatol': 1e-24, 'ftol': 1e-24, 'maxiter': 1000000, 'xatol': 1e-24, 'xtol': 1e-24}}), 'excitingmixing': (<function root>, False, {'method': 'excitingmixing', 'options': {'fatol': 1e-24, 'ftol': 1e-24, 'maxiter': 1000000, 'xatol': 1e-24, 'xtol': 1e-24}}), 'fixedpoint': (<function conditional_fixed_point>, True, {}), 'linearmixing': (<function root>, False, {'method': 'linearmixing', 'options': {'fatol': 1e-24, 'ftol': 1e-24, 'maxiter': 1000000, 'xatol': 1e-24, 'xtol': 1e-24}}), 'wegstein': (<function conditional_wegstein>, True, {})}#

Method definitions for convergence

classmethod register_method(name, solver, conditional=False, **kwargs)[source]#

Register new convergence method (root solver). Two solver signatures are supported:

  • If conditional is False, the signature must be solver(f, x, **kwargs) where f(x) = 0 is the solution. This is common for scipy solvers.

  • If conditional is True, the signature must be solver(f, x, **kwargs) where f(x) = (x, converged) is the solution and the solver stops when converged is True. This method is prefered in BioSTEAM.

classmethod from_feedstock(ID='', feedstock=None, feeds=None, facilities=(), ends=None, facility_recycle=None, operating_hours=None, **kwargs)[source]#

Create a System object from a feedstock.

Parameters:
  • ID (str, optional) – Name of system.

  • feedstock (Stream) – Main feedstock of the process.

  • feeds (Iterable[Stream], optional) – Additional feeds to the process.

  • facilities (Iterable[Facility]) – Offsite facilities that are simulated only after completing the path simulation.

  • ends (Iterable[Stream]) – Streams that not products, but are ultimately specified through process requirements and not by its unit source.

  • facility_recycle (Stream, optional) – Recycle stream between facilities and system path.

  • operating_hours (float, optional) – Number of operating hours in a year. This parameter is used to compute annualized properties such as utility cost and material cost on a per year basis.

classmethod from_units(ID='', units=None, ends=None, facility_recycle=None, operating_hours=None, **kwargs)[source]#

Create a System object from all units given.

Parameters:
  • ID (str, optional) – Name of system.

  • units (Iterable[Unit], optional) – Unit operations to be included.

  • ends (Iterable[Stream], optional) – End streams of the system which are not products. Specify this argument if only a section of the complete system is wanted, or if recycle streams should be ignored.

  • facility_recycle (Stream, optional) – Recycle stream between facilities and system path. This argument defaults to the outlet of a BlowdownMixer facility (if any).

  • operating_hours (float, optional) – Number of operating hours in a year. This parameter is used to compute annualized properties such as utility cost and material cost on a per year basis.

classmethod from_segment(ID='', start=None, end=None, operating_hours=None, inclusive=False, **kwargs)[source]#

Create a System object from all units in between start and end.

Parameters:
  • ID (str, optional) – Name of system.

  • start (Unit, optional) – Only downstream units from start are included in the system.

  • end (Unit, optional) – Only upstream units from end are included in the system.

  • operating_hours (float, optional) – Number of operating hours in a year. This parameter is used to compute annualized properties such as utility cost and material cost on a per year basis.

  • inclusive – Whether to include start and end units.

maxiter: int#

Maximum number of iterations.

phenomena_maxiter#

Default maximum number of phenomena-oriented simulations before attempting sequential modular

molar_tolerance: float#

Molar tolerance [kmol/hr].

relative_molar_tolerance: float#

Relative molar tolerance.

temperature_tolerance: float#

Temperature tolerance [K].

relative_temperature_tolerance: float#

Relative temperature tolerance.

operating_hours: float | None#

Number of operating hours per year

lang_factor: float | None#

Lang factor for computing fixed capital cost from purchase costs

simulate_after_specifications#

Whether to simulate system after running all specifications.

adaptive_phenomena_oriented_simulation#

Whether to run sequential modular simulation when phenomena oriented simulation is not converging.

property responses#

Unit design decisions that need to converge to satisfy process specifications.

parameter(setter=None, element=None, coupled=None, name=None, distribution=None, units=None, baseline=None, bounds=None, hook=None, description=None, optimized=False, kind=None)[source]#

Define and register parameter.

Parameters:
  • setter (Callable, optional) – Should set parameter in the element.

  • element (Unit, optional) – Element in the system being altered.

  • coupled (bool, optional) – Whether parameter is coupled to the system’s mass and energy balances. This allows a ConvergenceModel to predict it’s impact on recycle loops. Defaults to False.

  • name (str, optional) – Name of parameter. If None, default to argument name of setter.

  • distribution (str, optional) – Parameter distribution.

  • units (str, optional) – Parameter units of measure

  • baseline (float, optional) – Baseline value of parameter.

  • bounds (tuple[float, float], optional) – Lower and upper bounds of parameter.

  • hook (Callable, optional) – Should return the new parameter value given the sample.

copy(ID=None)[source]#

Copy system.

copy_like(other)[source]#

Copy path, facilities and recycle from other system.

set_tolerance(mol=None, rmol=None, T=None, rT=None, subsystems=False, maxiter=None, subfactor=None, method=None, algorithm=None)[source]#

Set the convergence tolerance and convergence method of the system.

Parameters:
  • mol (float, optional) – Molar tolerance.

  • rmol (float, optional) – Relative molar tolerance.

  • T (float, optional) – Temperature tolerance.

  • rT (float, optional) – Relative temperature tolerance.

  • subsystems (bool) – Whether to set tolerance and method of subsystems as well.

  • maxiter (int, optional) – Maximum number if iterations.

  • subfactor (float, optional) – Factor to rescale tolerance in subsystems.

  • method (str, optional) – Numerical method.

  • algorithm (str, optional) – Convergence algorithm

property ins: piping.StreamPorts[piping.InletPort]#

All inlets to the system.

property outs: piping.StreamPorts[piping.InletPort]#

All outlets to the system.

load_inlet_ports(inlets, names=None)#

Load inlet ports to system.

load_outlet_ports(outlets, names=None)#

Load outlet ports to system.

property TEA: TEA#

TEA object linked to the system.

property LCA#

QSDsan.LCA object linked to the system.

property specifications: list[ProcessSpecification]#

Process specifications as a list of process specification objects.

add_bounded_numerical_specification(f=None, *args, **kwargs)#

Add a bounded numerical specification that solves x where f(x) = 0 using an inverse quadratic interpolation solver.

Parameters:
  • f (Callable) – Objective function in the form of f(x, *args).

  • x (float, optional) – Root guess.

  • x0 (float) – Root bracket. Solution must lie within x0 and x1.

  • x1 (float) – Root bracket. Solution must lie within x0 and x1.

  • xtol (float, optional) – Solver stops when the root lies within xtol. Defaults to 0.

  • ytol (float, optional) – Solver stops when the f(x) lies within ytol of the root. Defaults to 5e-8.

  • args (tuple, optional) – Arguments to pass to f.

  • maxiter – Maximum number of iterations. Defaults to 50.

  • checkiter (bool, optional) – Whether to raise a Runtime error when tolerance could not be satisfied before the maximum number of iterations. Defaults to True.

  • checkroot (bool, optional) – Whether satisfying both tolerances, xtol and ytol, are required for termination. Defaults to False.

  • checkbounds (bool, optional) – Whether to raise a ValueError when in a bounded solver when the root is not certain to lie within bounds (i.e. f(x0) * f(x1) > 0.). Defaults to True.

Examples

Process specifications

Notes

This method also works as a decorator.

add_specification(specification=None, args=(), simulate=None)[source]#

Add a specification.

Parameters:
  • specification (Callable, optional) – Function runned for mass and energy balance.

  • args (tuple, optional) – Arguments to pass to the specification function.

  • simulate (bool, optional) – Whether to simulate after specification.

Examples

Process specifications

Notes

This method also works as a decorator.

prioritize_unit(unit)[source]#

Prioritize unit operation to run first within it’s recycle system, if there is one.

Parameters:

unit (Unit) – Unit operation to prioritize.

Raises:
  • ValueError – When unit is not in the system.

  • RuntimeError – When prioritization algorithm fails. This should never happen.

Examples

Create a simple recycle loop and prioritize a different unit operation:

>>> from biosteam import main_flowsheet as f, Stream, settings, Mixer, Splitter
>>> f.set_flowsheet('simple_recycle_loop')
>>> settings.set_thermo(['Water'], cache=True)
>>> feedstock = Stream('feedstock', Water=1000)
>>> water = Stream('water', Water=10)
>>> recycle = Stream('recycle')
>>> product = Stream('product')
>>> M1 = Mixer('M1', [feedstock, water, recycle])
>>> S1 = Splitter('S1', M1-0, [product, recycle], split=0.5)
>>> recycle_loop_sys = f.create_system('recycle_loop_sys')
>>> recycle_loop_sys.print()
System('recycle_loop_sys',
    [M1,
     S1],
    recycle=S1-1)
>>> recycle_loop_sys.prioritize_unit(S1)
>>> recycle_loop_sys.print()
System('recycle_loop_sys',
    [S1,
     M1],
    recycle=S1-1)
find_system(unit)[source]#

Return system containing given unit within it’s path.

split(stream, ID_upstream=None, ID_downstream=None)[source]#

Split system in two; upstream and downstream.

Parameters:
  • stream (Stream) – Stream where unit group will be split.

  • ID_upstream (str, optional) – ID of upstream system.

  • ID_downstream (str, optional) – ID of downstream system.

Examples

>>> from biorefineries import cellulosic
>>> from biosteam import default
>>> cs = cellulosic.Biorefinery() # Create corn stover biorefinery
>>> upstream_sys, downstream_sys = cs.cornstover_sys.split(cs.M201-0)
>>> upstream_group = upstream_sys.to_unit_group()
>>> upstream_group.show()
UnitGroup: Unnamed
 units: U101, H2SO4_storage, T201, M201
>>> downstream_group = downstream_sys.to_unit_group()
>>> for i in upstream_group: assert i not in downstream_group.units
>>> assert set(upstream_group.units + downstream_group.units) == set(cs.cornstover_sys.units)
>>> default() # Reset to biosteam defaults
flatten()[source]#

Flatten system by removing subsystems.

to_unit_group(name=None)[source]#

Return a UnitGroup object of all units within the system.

property subsystems: list[System]#

All subsystems in the system.

property units: list[Unit]#

All unit operations as ordered in the path without repetitions.

property unit_set: set[Unit]#

Set of all unit operations.

property unit_path: list[Unit]#

Unit operations as ordered in the path (some units may be repeated).

property cost_units: set[Unit]#

All unit operations with costs.

property streams: list[Stream]#

All streams within the system.

property feeds: list[Stream]#

All feeds to the system.

property products: list[Stream]#

All products of the system.

property facilities: tuple[Facility, ...]#

All system facilities.

property recycle: Stream | None#

A tear stream for the recycle loop.

property N_runs: int | None#

Number of times to converge the path.

property path: list[Unit | System]#

A path that is run element by element until the recycle(s) converges (if any).

property method: str#

Iterative convergence accelerator method (‘wegstein’, ‘aitken’, or ‘fixedpoint’).

property converge_method: str#

Iterative convergence accelerator method (‘wegstein’, ‘aitken’, or ‘fixedpoint’).

property algorithm: str#

Iterative convergence algorithm (‘Sequatial modular’, or ‘Phenomena oriented’).

Notes

Timulation algorithms are available:

Sequential modular - squentially runs each unit and subsystem until the recycle (i.e. tear) stream convergences.

Phenomena oriented - partitions and linearizes the underlying phenomenological equations for rapid and robust convergence.

property isdynamic: bool#

Whether the system contains any dynamic Unit.

diagram(kind=None, file=None, format=None, display=True, number=None, profile=None, label=None, title=None, auxiliaries=None, facilities=True, **graph_attrs)[source]#

Display a Graphviz diagram of the system.

Parameters:
  • kind (int, optional) –

    • 0 or ‘cluster’: Display all units clustered by system.

    • 1 or ‘thorough’: Display every unit within the system.

    • 2 or ‘surface’: Display only elements listed in the path.

    • 3 or ‘minimal’: Display a single box representing the system.

    • 4 or ‘stage’: Display every stage within the system.

  • file (str, optional) – File name to save diagram.

  • format (str, optional) – File format (e.g. “png”, “svg”). Defaults to ‘png’

  • display (bool, optional) – Whether to display diagram in console or to return the graphviz object.

  • number (bool, optional) – Whether to number unit operations according to their order in the system path.

  • profile (bool, optional) – Whether to clock the simulation time of unit operations.

  • label (bool, optional) – Whether to label the ID of streams with sources and sinks.

  • auxiliaries (bool, optional) – Whether to include auxiliary units.

run_sequential_modular()[source]#

Run mass and energy balances for each element in the path without costing unit operations.

run_phenomena()[source]#

Decouple and linearize material, equilibrium, summation, enthalpy, and reaction phenomena and iteratively solve them.

get_recycle_data()[source]#

Return recycle data defining material flows and conditions of recycle streams.

converge(recycle_data=None, update_recycle_data=False)[source]#

Converge mass and energy balances. If material data was given, return converged material flows at steady state. Shape will be M by N, where M is the number of recycle streams and N is the number of chemicals.

Parameters:

recycle_data (list[RecycleData]) – Material data to set recycle streams.

See also

System~.get_recycle_data()

Warning

No design, costing, nor facility algorithms are run. To run full simulation algorithm, see simulate().

empty_outlet_streams()[source]#

Reset all outlet streams to zero flow.

empty_recycles()[source]#

Reset all recycle streams to zero flow.

rescale(feedstock, ratio)[source]#

Rescale feedstock flow rate and update recycle stream flow rate guesses.

reset_cache()[source]#

Reset cache of all unit operations.

set_dynamic_tracker(*subjects, **kwargs)[source]#

Set up an SystemScope object to track the dynamic data.

Parameters:

*subjects – Any subjects of the system to track, which must have an .scope attribute of type Scope.

property scope: SystemScope#

A tracker of dynamic data of the system, set up with System.`set_dynamic_tracker()`

property DAE#

System-wide differential algebraic equations.

clear_state()[source]#

Clear all states and dstates (system, units, and streams).

simulate(update_configuration=None, units=None, design_and_cost=None, **kwargs)[source]#

If system is dynamic, run the system dynamically. Otherwise, converge the path of unit operations to steady state. After running/converging the system, size and cost all unit operations.

Parameters:
  • **kwargs – Additional parameters for dynamic_run() (if dynamic) or converge() (if steady state).

  • update_configuration (bool, optional) – Whether to update system configuration if unit connections have changed.

  • units – Unit operations of the system. If given, original unit operations of the system will be replaced.

dynamic_run(**dynsim_kwargs)[source]#

Run system dynamically without accounting for the cost or environmental impacts of unit operations.

Parameters:

**dynsim_kwargs

Dynamic simulation keyword arguments, could include:

t_spantuple[float, float]

Interval of integration (t0, tf). The solver starts with t=t0 and integrates until it reaches t=tf.

t_evaliterable(float)

The time points where status will be saved.

state_reset_hook: str|Callable

Hook function to reset the cache state between simulations for dynamic systems). Can be “reset_cache” or “clear_state” to call System.reset_cache or System.clear_state, or None to avoiding resetting.

export_state_to: str

If provided with a path, will save the simulated states over time to the given path, supported extensions are “.xlsx”, “.xls”, “csv”, and “tsv”.

sample_idstr

ID of the samples to run (for results exporting).

print_msgbool

Whether to print returned message from scipy.

print_tbool

Whether to print integration time in the console, usually used for debugging.

solve_ivp_kwargs

All remaining keyword arguments will be passed to solve_ivp.

define_process_impact(key, name, basis, inventory, CF)[source]#

Define a process impact.

Parameters:
  • key (str) – Impact indicator key.

  • name (str) – Name of process impact.

  • basis (str) – Functional unit for the characterization factor.

  • inventory (Callable) – Should return the annualized (not hourly) inventory flow rate given no parameters. Units should be in basis / yr

  • CF (float) – Characterization factor in impact / basis.

property heat_utilities: tuple[HeatUtility, ...]#

The sum of all heat utilities in the system by agent.

property power_utility: PowerUtility#

Sum of all power utilities in the system.

get_inlet_cost_flows()[source]#

Return a dictionary with flow rates for inlet streams with fees/credits/utilities.

get_outlet_revenue_flows()[source]#

Return a dictionary with flow rates for outlet streams with fees/credits/utilities.

get_inlet_flow(units, key=None)[source]#

Return total flow across all inlets per year.

Parameters:
  • units (str) – Material units of measure (e.g., ‘kg’, ‘gal’, ‘kmol’).

  • key (Sequence[str], optional) – Chemical identifiers. If none given, the sum of all chemicals returned

Examples

>>> from biosteam import Stream, Mixer, Splitter, settings, main_flowsheet
>>> settings.set_thermo(['Water', 'Ethanol'])
>>> main_flowsheet.clear()
>>> S1 = Splitter('S1', Stream(Ethanol=10, units='ton/hr'), split=0.1)
>>> M1 = Mixer('M1', ins=[Stream(Water=10, units='ton/hr'), S1-0])
>>> sys = main_flowsheet.create_system(operating_hours=330*24)
>>> sys.get_inlet_flow('Mton') # Sum of all chemicals
0.1584
>>> sys.get_inlet_flow('Mton', 'Water') # Just water
0.0792
get_outlet_flow(units, key=None)[source]#

Return total flow across all outlets per year.

Parameters:
  • units (str) – Material units of measure (e.g., ‘kg’, ‘gal’, ‘kmol’).

  • key (Sequence[str], optional) – Chemical identifiers. If none given, the sum of all chemicals returned

Examples

>>> from biosteam import Stream, Mixer, Splitter, settings, main_flowsheet
>>> settings.set_thermo(['Water', 'Ethanol'])
>>> main_flowsheet.clear()
>>> S1 = Splitter('S1', Stream(Ethanol=10, units='ton/hr'), split=0.1)
>>> M1 = Mixer('M1', ins=[Stream(Water=10, units='ton/hr'), S1-0])
>>> sys = main_flowsheet.create_system(operating_hours=330*24)
>>> sys.simulate()
>>> sys.get_outlet_flow('Mton') # Sum of all chemicals
0.1584
>>> sys.get_outlet_flow('Mton', 'Water') # Just water
0.0792
get_mass_flow(stream)[source]#

Return the mass flow rate of a stream [kg/yr].

get_market_value(stream)[source]#

Return the market value of a stream [USD/yr].

has_market_value(stream)[source]#

Return whether stream has a market value.

get_property(stream, name, units=None)[source]#

Return the annualized property of a stream.

get_total_feeds_impact(key)[source]#

Return the total annual impact of all feeds given the impact indicator key.

get_total_products_impact(key)[source]#

Return the total annual impact of all products given the impact indicator key.

get_material_impact(stream, key)[source]#

Return the annual material impact given the stream and the impact indicator key.

get_total_input_impact(key)[source]#

Return total annual impact of inputs given the impact indicator key.

get_process_impact(key)[source]#

Return the annual process impact given the impact indicator key.

get_net_impact(key)[source]#

Return net annual impact, including displaced impacts, given the impact indicator key.

property sales: float#

Annual sales revenue [USD/yr].

property material_cost: float#

Annual material cost [USD/yr].

property utility_cost: float#

Total utility cost [USD/yr].

property purchase_cost: float#

Total purchase cost [USD].

property installed_equipment_cost: float#

Total installed cost [USD].

property installed_cost: float#

Total installed cost [USD].

get_electricity_consumption()[source]#

Return the total electricity consumption [kWhr/yr].

get_electricity_production()[source]#

Return the total electricity production [kWhr/yr].

get_utility_duty(agent)[source]#

Return the total utility duty for given agent [kJ/yr].

get_utility_flow(agent)[source]#

Return the total utility flow for given agent [kmol/yr].

get_cooling_duty()[source]#

Return the total cooling duty [kJ/yr].

get_heating_duty()[source]#

Return the total heating duty [kJ/yr].

results(with_units=True)[source]#

Return a DataFrame of key results from simulation.

save_report(file='report.xlsx', dpi='900', sheets=None, stage=False, **stream_properties)[source]#

Save a system report as an xlsx file.

Parameters:
  • file (str, optional) – File name to save report

  • dpi (str, optional) – Resolution of the flowsheet. Defaults to ‘300’

  • **stream_properties (str) – Additional stream properties and units as key-value pairs (e.g. T=’degC’, flow=’gpm’, H=’kW’, etc..)

debug()[source]#

Simulate in debug mode. If an exception is raised, it will automatically enter in a breakpoint.

profile()[source]#

Simulate system in profile mode and return a DataFrame object of unit operation simulation times.

print(spaces='')[source]#

Print in a format that you can use recreate the system.

show(layout=None, T=None, P=None, flow=None, composition=None, N=None, IDs=None, sort=None, data=True)[source]#

Prints information on system.

property ID#

Unique identification (str). If set as ‘’, it will choose a default ID.

get_ash_disposal_cost()#

Return the ash disposal cost [USD/yr].

get_ash_disposal_flow()#

Return the ash disposal flow rate [kg/yr].

get_fuel_cost()#

Return the fuel cost [USD/yr].

get_fuel_flow()#

Return the fuel flow rate [kg/yr].

get_natural_gas_cost()#

Return the natural gas cost [USD/yr].

get_natural_gas_flow()#

Return the natural gas flow rate [kg/yr].

get_process_water_cost()#

Return the process water cost [USD/yr].

get_process_water_flow()#

Return the process water flow rate [kg/yr].

get_reverse_osmosis_water_cost()#

Return the reverse osmosis water cost [USD/yr].

get_reverse_osmosis_water_flow()#

Return the reverse osmosis water flow rate [kg/yr].