tespy.networks package¶
tespy.networks.network module¶
Module for tespy network class.
The network is the container for every TESPy simulation. The network class automatically creates the system of equations describing topology and parametrization of a specific model and solves it.
This file is part of project TESPy (github.com/oemof/tespy). It’s copyrighted by the contributors recorded in the version control history of the file, available from its original location tespy/networks/networks.py
SPDX-License-Identifier: MIT
- class tespy.networks.network.Network(iterinfo=True, units=None, m_range=None, p_range=None, h_range=None, **kwargs)[source]¶
Bases:
objectThe container for TESPy simulations.
The network collects components, connections and user defined equations, builds the system of equations describing the plant topology and parametrization and solves it.
- Parameters:
iterinfo (boolean) – Print convergence progress to console.
h_range (list) – List with minimum and maximum values for enthalpy value range.
m_range (list) – List with minimum and maximum values for mass flow value range.
p_range (list) – List with minimum and maximum values for pressure value range.
Note
Units are specified via the
Network.units.set_defaultsinterface. The specification is optional and will use SI units by default.Range specification is optional, too. The value range is used to stabilize the newton algorithm. For more information see the “getting started” section in the online-documentation.
Example
Basic example for a setting up a
tespy.networks.network.Networkobject.Standard value for iterinfo is
True. This will print out convergence progress to the console. You can stop the printouts by setting this property toFalse.>>> from tespy.networks import Network >>> mynetwork = Network() >>> mynetwork.units.set_defaults(**{ ... "pressure": "bar", "pressure_difference": "bar", ... "temperature": "degC" ... }) >>> mynetwork.p_range = [1, 10] >>> type(mynetwork) <class 'tespy.networks.network.Network'> >>> mynetwork.iterinfo = False >>> mynetwork.iterinfo False >>> mynetwork.iterinfo = True >>> mynetwork.iterinfo True
A simple network consisting of a source, a pipe and a sink. This example shows how the printout parameter can be used. We specify
printout=Falsefor both connections, the pipe as well as the power connection. Therefore the.print_results()method should not print any results.>>> from tespy.networks import Network >>> from tespy.components import Source, Sink, Pipe, HeatSink >>> from tespy.connections import Connection, HeatConnection >>> nw = Network() >>> nw.units.set_defaults(**{ ... "pressure": "bar", "pressure_difference": "bar", ... "temperature": "degC" ... }) >>> so = Source('source') >>> si = Sink('sink') >>> p = Pipe('pipe', Q=0, pr=0.95, printout=False) >>> h = HeatSink('heat to ambient') >>> a = Connection(so, 'out1', p, 'in1') >>> b = Connection(p, 'out1', si, 'in1') >>> nw.add_conns(a, b) >>> a.set_attr(fluid={'CH4': 1}, T=30, p=10, m=10, printout=False) >>> b.set_attr(printout=False) >>> e = HeatConnection(p, 'heat', h, 'heat', printout=False) >>> nw.add_conns(e) >>> nw.iterinfo = False >>> nw.solve('design') >>> nw.print_results()
- add_conns(*args)[source]¶
Add one or more connections to the network.
- Parameters:
c (tespy.connections.connection.Connection) – The connection to be added to the network, connections objects ci
add_conns(c1, c2, c3, ...).
- add_subsystems(*args)[source]¶
Add one or more subsystems to the network.
- Parameters:
c (tespy.components.subsystem.Subsystem) – The subsystem to be added to the network, subsystem objects si
network.add_subsystems(s1, s2, s3, ...).
- add_ude(*args)[source]¶
Add a user defined function to the network.
- Parameters:
c (tespy.tools.helpers.UserDefinedEquation) – The objects to be added to the network, UserDefinedEquation objects ci
add_ude(c1, c2, c3, ...).
- add_udv(*args)[source]¶
Add a user defined variable to the network.
- Parameters:
c (tespy.tools.helpers.UserDefinedVariable) – The objects to be added to the network, UserDefinedVariable objects ci
add_udv(c1, c2, c3, ...).
- property converged¶
- del_conns(*args)[source]¶
Remove one or more connections from the network.
- Parameters:
c (tespy.connections.connection.Connection) – The connection to be removed from the network, connections objects ci
del_conns(c1, c2, c3, ...).
- del_subsystems(*args)[source]¶
Delete one or more subsystems from the network.
- Parameters:
c (tespy.components.subsystem.Subsystem) – The subsystem to be deleted from the network, subsystem objects si
network.del_subsystems(s1, s2, s3, ...).
- del_ude(*args)[source]¶
Remove a user defined function from the network.
- Parameters:
c (tespy.tools.helpers.UserDefinedEquation) – The objects to be deleted from the network, UserDefinedEquation objects ci
del_ude(c1, c2, c3, ...).
- del_udv(*args)[source]¶
Remove a user defined variable from the network.
- Parameters:
c (tespy.tools.helpers.UserDefinedVariable) – The objects to be deleted from the network, UserDefinedVariable objects ci
del_udv(c1, c2, c3, ...).
- export(json_file_path=None)[source]¶
Export the parametrization and structure of the Network instance
- Parameters:
json_file_path (str, optional) – Path for exporting to filesystem. If path is None, the data are only returned and not written to the filesystem, by default None.
- Returns:
dict – Parametrization and structure of the Network instance.
- classmethod from_json(json_file_path)[source]¶
Load a network from a base path.
- Parameters:
path (str) – The path to the network data.
- Returns:
nw (tespy.networks.network.Network) – TESPy networks object.
Note
If you export the network structure of an existing TESPy network, it will be saved to the path you specified. The structure of the saved data in that path is the structure you need to provide in the path for loading the network.
The structure of the path must be as follows:
Folder: path (e.g. ‘mynetwork’)
Component.json
Connection.json
Network.json
Example
Create a network and export it. This is followed by loading the network from the exported json file. All network information stored will be passed to a new network object. Components and connections will be accessible by label. The following example setup is simple gas turbine setup with compressor, combustion chamber and turbine. The fuel is fed from a pipeline and throttled to the required pressure while keeping the temperature at a constant value.
>>> from tespy.components import ( ... Sink, Source, CombustionChamber, TurboCompressor, Turbine, ... SimpleHeatExchanger, PowerBus, PowerSink, Generator ... ) >>> from tespy.connections import Connection, Ref, PowerConnection >>> from tespy.networks import Network >>> import os >>> nw = Network() >>> nw.iterinfo = False >>> nw.units.set_defaults(**{ ... "pressure": "bar", "pressure_difference": "bar", ... "temperature": "degC", "enthalpy": "kJ/kg", ... "power": "MW" ... }) >>> air = Source('air') >>> f = Source('fuel') >>> compressor = TurboCompressor('compressor') >>> combustion = CombustionChamber('combustion') >>> turbine = Turbine('turbine') >>> preheater = SimpleHeatExchanger('fuel preheater') >>> si = Sink('sink') >>> shaft = PowerBus('shaft', num_in=1, num_out=2) >>> generator = Generator('generator') >>> grid = PowerSink('grid') >>> c1 = Connection(air, 'out1', compressor, 'in1', label='c01') >>> c2 = Connection(compressor, 'out1', combustion, 'in1', label='c02') >>> c11 = Connection(f, 'out1', preheater, 'in1', label='c11') >>> c12 = Connection(preheater, 'out1', combustion, 'in2', label='c12') >>> c3 = Connection(combustion, 'out1', turbine, 'in1', label='c03') >>> c4 = Connection(turbine, 'out1', si, 'in1', label='c04') >>> nw.add_conns(c1, c2, c11, c12, c3, c4) >>> e1 = PowerConnection(turbine, 'power', shaft, 'power_in1', label='e1') >>> e2 = PowerConnection(shaft, 'power_out1', compressor, 'power', label='e2') >>> e3 = PowerConnection(shaft, 'power_out2', generator, 'power_in', label='e3') >>> e4 = PowerConnection(generator, 'power_out', grid, 'power', label='e4') >>> nw.add_conns(e1, e2, e3, e4)
Specify component and connection properties. The intlet pressure at the compressor and the outlet pressure after the turbine are identical. For the compressor, the pressure ratio and isentropic efficiency are design parameters. A compressor map (efficiency vs. mass flow and pressure rise vs. mass flow) is selected for the compressor. Fuel is Methane.
>>> compressor.set_attr( ... pr=10, eta_s=0.88, design=['eta_s', 'pr'], ... offdesign=['char_map_eta_s', 'char_map_pr'] ... ) >>> turbine.set_attr( ... eta_s=0.9, design=['eta_s'], ... offdesign=['eta_s_char', 'cone'] ... ) >>> combustion.set_attr(lamb=2) >>> c1.set_attr( ... fluid={'N2': 0.7556, 'O2': 0.2315, 'Ar': 0.0129}, T=25, p=1 ... ) >>> c11.set_attr(fluid={'CH4': 0.96, 'CO2': 0.04}, T=25, p=40) >>> c12.set_attr(T=25) >>> c4.set_attr(p=Ref(c1, 1, 0)) >>> generator.set_attr(eta=1)
For a stable start, we specify the fresh air mass flow.
>>> c1.set_attr(m=3) >>> nw.solve('design') >>> nw.assert_convergence()
The total power output is set to 1 MW, electrical or mechanical efficiencies are not considered in this example. See
tespy.components.power.motor.Motorandtespy.components.power.generator.Generatorfor modelling conversion efficiencies between mechanical and electrical power.>>> combustion.set_attr(lamb=None) >>> c3.set_attr(T=1100) >>> c1.set_attr(m=None) >>> e4.set_attr(E=1) >>> nw.solve('design') >>> nw.assert_convergence() >>> design_state = nw.save(as_dict=True) >>> _ = nw.export('exported_nwk.json') >>> mass_flow = round(nw.get_conn('c01').m.val_SI, 1) >>> compressor.set_attr(igva='var') >>> nw.solve('offdesign', design_path=design_state) >>> round(turbine.eta_s.val, 1) 0.9 >>> e4.set_attr(E=0.75) >>> nw.solve('offdesign', design_path=design_state) >>> nw.assert_convergence() >>> eta_s_t = round(turbine.eta_s.val, 3) >>> igva = round(compressor.igva.val, 3) >>> eta_s_t 0.898 >>> igva 20.138
The designed network is exported to the path ‘exported_nwk’. Now import the network and recalculate. Check if the results match with the previous calculation in design and offdesign case.
>>> imported_nwk = Network.from_json('exported_nwk.json') >>> imported_nwk.iterinfo = False >>> imported_nwk.solve('design') >>> imported_nwk.problem.lin_dep False >>> round(imported_nwk.get_conn('c01').m.val_SI, 1) == mass_flow True >>> round(imported_nwk.get_comp('turbine').eta_s.val, 3) 0.9 >>> imported_nwk.get_comp('compressor').set_attr(igva='var') >>> imported_nwk.solve('offdesign', design_path=design_state) >>> round(imported_nwk.get_comp('turbine').eta_s.val, 3) 0.9 >>> imported_nwk.get_conn('e4').set_attr(E=0.75) >>> imported_nwk.solve('offdesign', design_path=design_state) >>> round(imported_nwk.get_comp('turbine').eta_s.val, 3) == eta_s_t True >>> round(imported_nwk.get_comp('compressor').igva.val, 3) == igva True >>> os.remove('exported_nwk.json')
- get_attr(key)[source]¶
Get the value of a network attribute.
- Parameters:
key (str) – The attribute you want to retrieve.
- Returns:
out – Specified attribute.
- get_block_jacobian(block) dict[source]¶
Get the linear system of a failed block at its state of failure.
The jacobian and the residual vector restricted to the block’s equations and variables, recorded as evaluated in the failing iteration of the block’s last solution attempt. Only available for blocks whose solution failed.
- Parameters:
block (int) – Id of the block of the block decomposition.
- Returns:
dict – Formatted equation and variable labels together with the jacobian matrix and the residual vector of the block.
- get_block_states(block, at='current') list[source]¶
Get the states of the connections a block touches.
The properties of every connection involved in the block’s equations and variables. What is reported comes from the connection classes, e.g. mass flow, pressure, enthalpy, temperature and phase for fluid connections, the energy flow for power connections.
- Parameters:
block (int) – Id of the block of the block decomposition.
at (str) –
"current"(default) evaluates the states from the current variable values - while the solution process is paused at the block this is its entry state, including any modification made in between."failure"returns the states as recorded in the failing iteration of the block’s last solution attempt, only available for blocks whose solution failed.
- Returns:
list – One dict per connection with its label, the reported properties and the list of properties that are variables of the block.
- get_blocks() list[source]¶
Get the block lower triangular decomposition of the problem.
- Returns:
list – One dictionary per block in solve order with the block id, its kind, the ids of the blocks it depends on, the equations as tuples of object label and equation name, the short variable labels and the solve status (
Nonebefore solving).
- get_comp(label)[source]¶
Get Component via label.
- Parameters:
label (str) – Label of the Component object.
- Returns:
c (tespy.components.component.Component) – Component object with specified label, None if no Component of the network has this label.
- get_conn(label)[source]¶
Get Connection via label.
- Parameters:
label (str) – Label of the Connection object.
- Returns:
c (tespy.connections.connection.Connection) – Connection object with specified label, None if no Connection of the network has this label.
- get_equations() dict[source]¶
Get the actual equations after presolving the problem
- Returns:
dict – Lookup with equation number as index and tuple of label and parameter defining the equation. In case one parameter defines multiple equations, the same equation is repeated.
- get_equations_with_dependents() dict[source]¶
Get the equations together with the variables they depend on.
- Returns:
dict – Lookup with equation (component, (parameter_label, number)) and the variables it depends on as a list (variable number, variable type)
- get_linear_dependent_variables() list[source]¶
Get a list with sublists containing linear dependent variables
- Returns:
list – List of lists of linear dependent variables
- get_linear_dependents_by_object(obj, prop) list[source]¶
Get the list of linear dependent variables for a specified variable
- Parameters:
obj (object) – Parent object holding a variable
prop (str) – Name of the variable (e.g. ‘m’ or ‘h’)
- Returns:
list – list of linear dependent variables
- Raises:
KeyError – In case the object does not have any variables
KeyError – In case the specified property is not a variable
- get_presolved_equations() list[source]¶
Get the list of equations, that has been presolved with their respective parent object
- Returns:
list – list of presolved equations
- get_presolved_variables() list[source]¶
Get the list of presolved variables with their respective parent object and property.
- Returns:
list – list of presolved variables
- get_structural_analysis() list[source]¶
Get the over- and under-determined parts of the problem.
- Returns:
list – One dictionary per defective part of the maximum matching of the incidence with its kind (
"overdetermined"or"underdetermined"), the equations as tuples of object label and equation name and the short variable labels. An empty list means the problem is structurally sound.
- get_structure() dict[source]¶
Get a serializable description of the mathematical structure.
The result joins with the class level schema of
tespy.tools.schemathrough class names, parameter names and quantities and with the network serialization through object labels and port identifiers. The problem has to be prepared, e.g. by solving withinit_only=True.- Returns:
dict – Dictionary with the keys
variables,equations,connectionsandcomponents. Variables carry their state (specified,presolvedorvariable), their affine relation to the reference variable and the solver column. Equations carry their mathematical kind (affine,linearornonlinear), their origin (topologyorspecification), their state (consumedoractive) and the structural variables they relate.
- get_subsystem(label)[source]¶
Get Subsystem via label.
- Parameters:
label (str) – Label of the Subsystem object.
- Returns:
tespy.components.subsystem.Subsystem – Subsystem objectt with specified label, None if no Subsystem of the network has this label.
- get_ude(label)[source]¶
Get UserDefinedEquation via label.
- Parameters:
label (str) – Label of the UserDefinedEquation object.
- Returns:
c (tespy.tools.helpers.UserDefinedEquation) – UserDefinedEquation object with specified label, None if no UserDefinedEquation of the network has this label.
- get_udv(label)[source]¶
Get UserDefinedVariable via label.
- Parameters:
label (str) – Label of the UserDefinedVariable object.
- Returns:
c (tespy.tools.helpers.UserDefinedVariable) – UserDefinedVariable object with specified label.
- get_variable_values(block=None) dict[source]¶
Get the current values of all variables of the presolved problem.
Every variable is listed with all of the original variables it represents and their individual SI values, which can differ through the affine relation between linearly dependent variables.
- Parameters:
block (int) – Restrict the result to the variables of the block with the given id of the block decomposition, default:
None(all variables).- Returns:
dict – Variable number and property with the list of represented variables as tuples of object label, property and SI value.
- get_variables() dict[source]¶
Get all variables of the presolved problem with their respective represented original variables.
- Returns:
dict – variable number and property with the list of represented variables
- get_variables_before_presolve() list[source]¶
Get the list of variables before presolving.
- Returns:
list – list of original variables
- property h_range¶
- property iterinfo¶
- property m_range¶
- property p_range¶
- presolve(mode, init_path=None, design_path=None, init_previous=True, check=True)[source]¶
Prepare and presolve the problem without running the solver.
The network is checked, the problem is built and presolved and the starting values are assigned. The variable space stays loaded afterwards, so it can be inspected through
Network.problemand the print methods, and variable values can be modified before continuing the solution process withsolve_continue().- Parameters:
mode (str) – Choose from ‘design’ and ‘offdesign’.
init_path (str | Path | dict) – Path to a previously saved network state (e.g.
nw.save('myplant/test.json')), or the dict returned bynw.save(as_dict=True).design_path (str | Path | dict) – Path to the saved design-case state (e.g.
nw.save('myplant/test.json')), or the dict returned bynw.save(as_dict=True).init_previous (boolean) – Initialise the calculation with values from the previous calculation, default:
True.check (boolean) – Check whether the number of parameters matches the number of variables, default:
True. The check is skipped when preparing withsolve(mode, init_only=True), so ill determined problems can be inspected.
- print_block_jacobian(block)[source]¶
Print the jacobian and residual of a failed block at its state of failure.
Entries the incidence matrix does not declare are left blank, a derivative that evaluated to zero although its dependency is declared is marked as
missing.
- print_block_states(block, at='current')[source]¶
Print the states of the connections a block touches, either at the current variable values or as recorded in the failing iteration (
at="failure").
- print_equations_with_dependents()[source]¶
Print a formatted table of equations and the variables they depend on.
- print_incidence_matrix(block_order=False)[source]¶
Print the incidence matrix with equation rows and variable columns.
- Parameters:
block_order (boolean) – Sort the equations and variables in the solve order of the block decomposition, so the block lower triangular form of the problem becomes visible, default:
False.
- print_results(colored=True, colors=None, print_results=True, subsystem=None)[source]¶
Print the calculations results to prompt.
- print_structural_analysis()[source]¶
Print the over- and under-determined parts of the problem.
In an over-determined part more equations compete for the involved variables than the variables can satisfy - one of the underlying specifications must be removed. In an under-determined part the involved equations cannot determine all of the variables - a specification is missing. Prints that the problem is structurally sound in case neither exists.
- print_variable_values(block=None)[source]¶
Print a formatted table of the current variable values, optionally restricted to the variables of a single block.
- print_variables_before_presolve()[source]¶
Print a formatted table of all variables before presolving.
- property problem¶
Solver
Probleminstance of the most recent solve call.Holds the variable space, equation lookups and the state of the newton algorithm (residual vector, jacobian, increment).
- save(json_file_path: str | Path | None = None, as_dict: bool = False) None | dict | str[source]¶
Dump the results to a json style output.
- Parameters:
json_file_path (str | Path | None) – Filename to dump results into. If
None, the state is returned in-memory (as dict whenas_dict=True, otherwise as JSON string).as_dict (bool) – If
Trueandjson_file_pathisNone, return the state as a dict that can be passed directly asdesign_pathorinit_pathin a subsequentsolve()call. DefaultFalse; theFalsebehaviour (returning a JSON string) is deprecated and will be removed in version 0.12.
- Returns:
None – If a file path is provided, results are saved to file.
dict – If
json_file_pathisNoneandas_dict=True.str – If
json_file_pathisNoneandas_dict=False(deprecated).
- save_csv(folder_path)[source]¶
Export the results in multiple csv files in a folder structure
Connection.csv
Component/ - Compressor.csv - ….
- Parameters:
folder_path (str) – Path to dump results to
- set_attr(**kwargs)[source]¶
Set, resets or unsets attributes of a network.
- Parameters:
iterinfo (boolean) – Print convergence progress to console.
h_range (list) – List with minimum and maximum values for enthalpy value range.
m_range (list) – List with minimum and maximum values for mass flow value range.
p_range (list) – List with minimum and maximum values for pressure value range.
- set_variable_value(label, prop, value)[source]¶
Set the SI value of a variable of the presolved problem.
The value can be set through any of the linearly dependent variables a solver variable represents, it propagates to the underlying reference container through the affine relation. For example setting the enthalpy of a connection whose enthalpy is linked to another connection updates both.
- Parameters:
label (str) – Label of the connection or component holding the variable.
prop (str) – Name of the variable (e.g.
'm'or'h').value (float) – SI value to impose.
- Raises:
KeyError – In case no object with the given label exists or the object does not have a variable of the given name.
tespy.tools.helpers.TESPyNetworkError – In case the property is not part of the variable space, e.g. because it is specified or has been presolved.
- solve(mode, init_path=None, design_path=None, max_iter=50, min_iter=2, init_only=False, init_previous=True, use_cuda=False, print_results=True, robust_relax=False, skip_postprocess=False, oscillation_damping=False, block_solve=True, pause_on_block_failure=False)[source]¶
Solve the network.
Check network consistency.
Initialise calculation and preprocessing.
Perform actual calculation.
Postprocessing.
It is possible to check programmatically, if a network was solved successfully with the .converged attribute.
- Parameters:
mode (str) – Choose from ‘design’ and ‘offdesign’.
init_path (str | Path | dict) – Path to a previously saved network state (e.g.
nw.save('myplant/test.json')), or the dict returned bynw.save(as_dict=True).design_path (str | Path | dict) – Path to the saved design-case state (e.g.
nw.save('myplant/test.json')), or the dict returned bynw.save(as_dict=True).max_iter (int) – Maximum number of iterations before calculation stops, default: 50.
min_iter (int) – Minimum number of iterations of the simultaneous solution before convergence can be accepted, default: 2. Convergence is only accepted in an iteration in which the value bounds and convergence heuristics did not modify any variable, so the parameter is a hard floor on top of that, not the primary guard. Block-wise solving accepts every block individually on the same criterion.
init_only (boolean) – Perform initialisation only, default:
False.init_previous (boolean) – Initialise the calculation with values from the previous calculation, default:
True.use_cuda (boolean) – Use cuda instead of numpy for matrix inversion, default:
False.robust_relax (boolean) – Apply a ramped relaxation factor that starts near zero and grows to 1 over the first quarter of
max_iteriterations. Helps avoid divergence from poor starting values, at the cost of slower early convergence. Default:False.oscillation_damping (boolean) – Detect Newton oscillations caused by non-smooth residuals (e.g. phase-transition kinks in sectioned heat exchangers) and dampen them automatically. When a residual component changes sign between two consecutive iterations - indicating an overshoot - the increments for all variables that equation depends on are halved before being applied. This converts the oscillating Newton step into a bisection-like contraction and restores monotone convergence without requiring an external bracketing loop. Default:
False.block_solve (boolean) – Decompose the equation system into its block lower triangular form and solve the blocks in precedence order instead of solving the full system simultaneously. Scalar blocks are solved with a bracketing fallback on oscillation. Experimental, default:
False.pause_on_block_failure (boolean) – Pause the block-wise solution process at the first block that does not converge instead of escalating to the coupled solution stages, default:
False. The variable space stays loaded (statusis 20), the variables of the failed block can be inspected withprint_variable_values()and modified withset_variable_value(), andsolve_continue()retries the block and continues the solution process.
Note
For more information on the solution process have a look at the online documentation at tespy.readthedocs.io in the section “TESPy modules”.
- solve_continue(max_iter=50, min_iter=2, use_cuda=False, print_results=True, robust_relax=False, skip_postprocess=False, oscillation_damping=False, block_solve=True, pause_on_block_failure=None)[source]¶
Run the solver on the previously prepared problem.
Continues after
presolve()orsolve(mode, init_only=True), taking into account any modification of variable values made in between. The solver parameters correspond to the ones ofsolve().When the solution process is paused at a failed block, the block is retried with the current variable values and the solution process continues from there.
pause_on_block_failuredefaults to keeping the value of the initiating solve call, passingFalseexplicitly hands a still failing block over to the standard escalation stages instead.
- property units¶