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`[:py:class:`~biosteam.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`[:py:class:`~biosteam.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

variable_priority: list[str] = ['equilibrium', 'material', 'energy', 'material']#

Variable solution priority for phenomena oriented simulation.

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, optional) – Main feedstock of the process.

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

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

  • ends (Stream], optional) – 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 (Unit], optional) – Unit operations to be included.

  • ends (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.

property responses#

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

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

Define parameter.

Parameters:
  • setter (function) – Should set parameter in the element.

  • element (Unit or Stream) – Element in the system being altered.

  • kind ({'coupled', 'isolated', 'design', 'cost'}, optional) –

    • ‘coupled’: parameter is coupled to the system.

    • ’isolated’: parameter does not affect the system but does affect the element (if any).

    • ’design’: parameter only affects design and/or cost of the element.

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

  • distribution (chaospy.Dist) – 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.

  • scale (float, optional) – The sample is multiplied by the scale before setting.

Notes

If kind is ‘coupled’, account for downstream operations. Otherwise, only account for given element. If kind is ‘design’ or ‘cost’, element must be a Unit object.

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, **graph_attrs)[source]#

Display a Graphviz diagram of the system.

Parameters:
  • kind (int | str, optional) –

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

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

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

    • 3 or ‘minimal’: Display a single box representing all units.

  • 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`[:py:class:`~biosteam._system.RecycleData], optional) – 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`[:py:class:`str] | 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`[:py:class:`str] | 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', **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_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].